From 45385109b9fbb245767bff7320489e6a7a7a1178 Mon Sep 17 00:00:00 2001 From: Oliver Tacke Date: Tue, 28 Feb 2023 17:17:53 +0100 Subject: [PATCH 1/5] Fix dropzone access on resume --- src/scripts/drag-text.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/scripts/drag-text.js b/src/scripts/drag-text.js index 5aba25dc..cb5540ec 100644 --- a/src/scripts/drag-text.js +++ b/src/scripts/drag-text.js @@ -1378,6 +1378,10 @@ H5P.DragText = (function ($, Question, ConfirmationDialog) { } } } + + // Allow to tab to filled drop zones. + this.addAllDroppablesToControls(); + this.removeControlsFromEmptyDropZones(); }; /** From 5cc9801846c6d93e580206f8e1b46e894e0ec69f Mon Sep 17 00:00:00 2001 From: Oliver Tacke Date: Tue, 28 Feb 2023 18:51:28 +0100 Subject: [PATCH 2/5] Focus first droppable on check --- src/scripts/drag-text.js | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/scripts/drag-text.js b/src/scripts/drag-text.js index cb5540ec..64962d49 100644 --- a/src/scripts/drag-text.js +++ b/src/scripts/drag-text.js @@ -407,6 +407,15 @@ H5P.DragText = (function ($, Question, ConfirmationDialog) { var self = this; self.addDropzoneWidth(); + // Prevent losing focus caused by detaching word container + const closestWordContainer = document.activeElement + .closest('.h5p-drag-droppable-words'); + + let restoreFocusTo = null; + if (closestWordContainer === self.$wordContainer.get(0)) { + restoreFocusTo = document.activeElement; + } + //Find ratio of width to em, and make sure it is less than the predefined ratio, make sure widest draggable is less than a third of parent width. if ((self.$inner.width() / parseFloat(self.$inner.css("font-size"), 10) > 43) && (self.widestDraggable <= (self.$inner.width() / 3))) { // Adds a class that floats the draggables to the right. @@ -431,6 +440,13 @@ H5P.DragText = (function ($, Question, ConfirmationDialog) { draggable.getDraggableElement().removeClass(DRAGGABLE_ELEMENT_WIDE_SCREEN); }); } + + if (restoreFocusTo) { + window.clearTimeout(this.layoutTimeout); + this.layoutTimeout = window.setTimeout(() => { + restoreFocusTo.focus(); + }, 1); + } }; /** @@ -460,8 +476,14 @@ H5P.DragText = (function ($, Question, ConfirmationDialog) { self.hideButton('check-answer'); } - // Focus top of the task for natural navigation - self.$introduction.parent().focus(); + /* + * Allow all dropzones incl. empty ones to be accessed. + * Weird to remove and add, but that will ensure tabindex to be correct. + */ + self.removeAllDroppablesFromControls(); + self.addAllDroppablesToControls(); + + self.droppables[0].getElement().focus(); }, !self.params.behaviour.instantFeedback, { 'aria-label': self.params.a11yCheck, }, { @@ -1134,7 +1156,7 @@ H5P.DragText = (function ($, Question, ConfirmationDialog) { // Shows evaluation text self.showEvaluation(); - } + } else { //Hides "retry" and "show solution" buttons. self.hideButton('try-again'); From 737d94711d2b85ef6cf713084156694d5fe4e048 Mon Sep 17 00:00:00 2001 From: Oliver Tacke Date: Tue, 28 Feb 2023 18:52:33 +0100 Subject: [PATCH 3/5] Fix dropzone aria-label index --- src/scripts/drag-text.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/scripts/drag-text.js b/src/scripts/drag-text.js index 64962d49..ccccc132 100644 --- a/src/scripts/drag-text.js +++ b/src/scripts/drag-text.js @@ -299,7 +299,7 @@ H5P.DragText = (function ($, Question, ConfirmationDialog) { const hasChildren = (dropZone.childNodes.length > 0); if (dropZone) { - let ariaLabel; + let ariaMessage; if (checkButtonPressed) { const droppable = this.getDroppableByElement(dropZone); @@ -310,7 +310,7 @@ H5P.DragText = (function ($, Question, ConfirmationDialog) { else { resultString = droppable.incorrectFeedback ? droppable.incorrectFeedback : this.params.incorrectText; } - ariaLabel = `${this.params.contains.replace('@index', index.toString()).replace('@draggable', text)} ${resultString}.`; + ariaMessage = `${this.params.contains.replace('@index', index.toString()).replace('@draggable', text)} ${resultString}.`; if (droppable && droppable.containedDraggable) { droppable.containedDraggable.updateAriaDescription( @@ -319,13 +319,13 @@ H5P.DragText = (function ($, Question, ConfirmationDialog) { } } else if (hasChildren) { - ariaLabel = `${this.params.contains.replace('@index', index.toString()).replace('@draggable', text)}`; + ariaMessage = `${this.params.contains.replace('@index', index.toString()).replace('@draggable', text)}`; } else { - ariaLabel = `${this.params.empty.replace('@index', index.toString())}`; + ariaMessage = `${this.params.empty.replace('@index', index.toString())}`; } - dropZone.setAttribute('aria-label', ariaLabel); + dropZone.setAttribute('aria-label', `${indexText} ${ariaMessage}`); } }; From e7f8d612c72b74988ed24b73a15581dfb838afae Mon Sep 17 00:00:00 2001 From: Oliver Tacke Date: Tue, 28 Feb 2023 19:21:25 +0100 Subject: [PATCH 4/5] Focus first droppable on show solution --- src/scripts/drag-text.js | 25 +++++++++++++++++++++++++ src/scripts/droppable.js | 5 +++++ 2 files changed, 30 insertions(+) diff --git a/src/scripts/drag-text.js b/src/scripts/drag-text.js index ccccc132..ef7c97f2 100644 --- a/src/scripts/drag-text.js +++ b/src/scripts/drag-text.js @@ -499,7 +499,13 @@ H5P.DragText = (function ($, Question, ConfirmationDialog) { }); self.draggables.forEach(draggable => self.setDraggableAriaLabel(draggable)); self.disableDraggables(); + + // Weird to remove and add, but that will ensure tabindex to be correct self.removeAllDroppablesFromControls(); + self.addAllDroppablesToControls(); + + self.droppables[0].getElement().focus(); + self.hideButton('show-solution'); }, self.initShowShowSolutionButton || false, { 'aria-label': self.params.a11yShowSolution, @@ -512,6 +518,7 @@ H5P.DragText = (function ($, Question, ConfirmationDialog) { // move draggables to original container self.resetDraggables(); } + self.resetDroppables(); self.answered = false; self.hideEvaluation(); @@ -1309,6 +1316,8 @@ H5P.DragText = (function ($, Question, ConfirmationDialog) { self.answered = false; //Reset draggables parameters and position self.resetDraggables(); + self.resetDroppables(); + //Hides solution text and re-enable draggables self.hideEvaluation(); self.hideExplanation(); @@ -1331,6 +1340,22 @@ H5P.DragText = (function ($, Question, ConfirmationDialog) { Util.shuffle(this.draggables).forEach(this.revert, this); }; + /** + * Reset dropzones. + */ + DragText.prototype.resetDroppables = function () { + const self = this; + + this.droppables.forEach((droppable, index) => { + droppable.$dropzone.attr( + 'aria-label', + self.params.dropZoneIndex.replace('@index', (index + 1).toString()) + + ' ' + self.params.empty.replace('@index', (index + 1).toString()), + ) + }) + Util.shuffle(this.draggables).forEach(this.revert, this); + }; + /** * Returns an object containing the dropped words * diff --git a/src/scripts/droppable.js b/src/scripts/droppable.js index 4a2b6f33..db65a21d 100644 --- a/src/scripts/droppable.js +++ b/src/scripts/droppable.js @@ -81,6 +81,11 @@ H5P.TextDroppable = (function ($) { Droppable.prototype.showSolution = function () { const correct = (this.containedDraggable !== null) && (this.containedDraggable.getAnswerText() === this.text); if (!correct) { + + const currentAriaLabel = this.$dropzone.attr('aria-label'); + const correctAnswer = `${this.params.correctAnswer} ${this.text}`; + this.$dropzone.attr('aria-label', `${currentAriaLabel} ${correctAnswer}`); + this.$showSolution.html(this.text); } From 569b92ef09ce4bb011d4e64ec069b8ff16500d3d Mon Sep 17 00:00:00 2001 From: Oliver Tacke Date: Tue, 28 Feb 2023 19:26:34 +0100 Subject: [PATCH 5/5] Remove unnecessary code --- src/scripts/drag-text.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/scripts/drag-text.js b/src/scripts/drag-text.js index ef7c97f2..91e3479d 100644 --- a/src/scripts/drag-text.js +++ b/src/scripts/drag-text.js @@ -476,11 +476,7 @@ H5P.DragText = (function ($, Question, ConfirmationDialog) { self.hideButton('check-answer'); } - /* - * Allow all dropzones incl. empty ones to be accessed. - * Weird to remove and add, but that will ensure tabindex to be correct. - */ - self.removeAllDroppablesFromControls(); + // Allow all dropzones incl. empty ones to be accessed. self.addAllDroppablesToControls(); self.droppables[0].getElement().focus(); @@ -500,8 +496,7 @@ H5P.DragText = (function ($, Question, ConfirmationDialog) { self.draggables.forEach(draggable => self.setDraggableAriaLabel(draggable)); self.disableDraggables(); - // Weird to remove and add, but that will ensure tabindex to be correct - self.removeAllDroppablesFromControls(); + // Allow all dropzones incl. empty ones to be accessed. self.addAllDroppablesToControls(); self.droppables[0].getElement().focus();