diff --git a/src/activities/domActivities/SimpleCheckboxQuiz.css b/src/activities/domActivities/SimpleCheckboxQuiz.css index 7ed74712..3fc5053c 100644 --- a/src/activities/domActivities/SimpleCheckboxQuiz.css +++ b/src/activities/domActivities/SimpleCheckboxQuiz.css @@ -16,6 +16,14 @@ .simple-comprehension-quiz .checkbox-and-textbox-choice { display: flex; z-index: 0; + /* without this, each choice extends to the full width of the container */ + /* that means you can click on empty space to the right of the text and accidentally select the choice */ + /* this could also interfere with trying to swipe to the next page */ + /* note that everything from the container down to the paragraph has to have width: fit-content */ + width: fit-content; + * { + width: fit-content; + } /* Checkmark is done as a rotated half-bordered box that is the :before of the div */ } .simple-comprehension-quiz .checkbox-and-textbox-choice input { diff --git a/src/activities/domActivities/SimpleCheckboxQuiz.ts b/src/activities/domActivities/SimpleCheckboxQuiz.ts index 9ebad462..51adf745 100644 --- a/src/activities/domActivities/SimpleCheckboxQuiz.ts +++ b/src/activities/domActivities/SimpleCheckboxQuiz.ts @@ -41,7 +41,7 @@ export default class SimpleCheckboxQuiz implements IActivityObject { const choices = this.activityContext.pageElement.getElementsByClassName( "checkbox-and-textbox-choice" ); - Array.from(choices).forEach((choice: HTMLElement) => { + Array.from(choices).forEach((choice: HTMLElement, index: number) => { const checkbox = this.getCheckBox(choice); // ----- This whole file is never loaded in Bloom. For now it is bloom-player only. @@ -68,6 +68,34 @@ export default class SimpleCheckboxQuiz implements IActivityObject { capture: true } ); + // We only need to add these body-level listeners once. + if (index === 0) { + // I can't find any clear documentation on whether we need all of these or just the pointer ones. + for (const eventName of [ + "mousedown", + "mousemove", + "pointerdown", + "pointermove", + "touchstart", + "touchmove" + ]) { + // The purpose of this is to prevent Swiper allowing the page to be moved or + // flicked when the user is trying to click on a choice. + // Unfortunately it does not work to put a handler on these events for the choice itself. + // Apparently the Swiper is capturing them before they get to the choice. + // So we capture them at a higher level still, but only stop propagation if + // in one of the choices. + this.activityContext.addEventListener( + eventName, + choice.ownerDocument.body, + e => this.handleInputMouseEvent(e), + { + capture: true + } + ); + } + } + const key = this.getStorageKeyForChoice(choice); if ( activityContext.getSessionPageData(key) === @@ -102,6 +130,23 @@ export default class SimpleCheckboxQuiz implements IActivityObject { (e.textContent || "").trim() !== "" ); } + private handleInputMouseEvent(event: Event) { + if ( + (event.target as HTMLElement).closest( + ".checkbox-and-textbox-choice" + ) + ) { + // Stop Swier from seeing events on these elements. + // Note: Swiper version 11 has a class "swiper-no-swiping" that I think can be used to + // achieve this, or configured with noSwipingClass or noSwipingSelector. + // But we're at too low a version to use that, and bringing in the latest + // version is non-trivial. + event.stopPropagation(); + // We don't need to preventDefault to keep Swiper from moving the page, + // and we don't want to because I think it would stop the mousedown + // from eventually resulting in a click. + } + } private handleReadModeClick(event: Event) { // prevent the browser messing with the check box checked state