Skip to content

Commit

Permalink
Merge pull request #331 from BloomBooks/noPageDragOnCheck
Browse files Browse the repository at this point in the history
fix: Prevent clicks on choices being treated as drags (BL-13999)
  • Loading branch information
hatton authored Oct 16, 2024
2 parents 9ada481 + a45afd5 commit 9ad85a4
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 1 deletion.
8 changes: 8 additions & 0 deletions src/activities/domActivities/SimpleCheckboxQuiz.css
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
47 changes: 46 additions & 1 deletion src/activities/domActivities/SimpleCheckboxQuiz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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) ===
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 9ad85a4

Please sign in to comment.