diff --git a/js/blanks.js b/js/blanks.js
index 30194de..d3434d3 100644
--- a/js/blanks.js
+++ b/js/blanks.js
@@ -196,14 +196,8 @@ H5P.Blanks = (function ($, Question) {
if (!self.params.behaviour.autoCheck && this.params.behaviour.enableCheckButton) {
// Check answer button
self.addButton('check-answer', self.params.checkAnswer, function () {
- // Move focus to top of content
- self.a11yHeader.innerHTML = self.params.a11yHeader;
- self.a11yHeader.focus();
-
- self.toggleButtonVisibility(STATE_CHECKING);
self.markResults();
- self.showEvaluation();
- self.triggerAnswered();
+ self.handleCheckAnswer({ focusFirstAnswer: true });
}, true, {
'aria-label': self.params.a11yCheck,
}, {
@@ -220,7 +214,7 @@ H5P.Blanks = (function ($, Question) {
// Show solution button
self.addButton('show-solution', self.params.showSolutions, function () {
- self.showCorrectAnswers(false);
+ self.showCorrectAnswers(false, true);
}, self.params.behaviour.enableSolutionsButton, {
'aria-label': self.params.a11yShowSolution,
});
@@ -228,7 +222,6 @@ H5P.Blanks = (function ($, Question) {
// Try again button
if (self.params.behaviour.enableRetry === true) {
self.addButton('try-again', self.params.tryAgain, function () {
- self.a11yHeader.innerHTML = '';
self.resetTask();
self.$questions.filter(':first').find('input:first').focus();
}, true, {
@@ -245,6 +238,26 @@ H5P.Blanks = (function ($, Question) {
self.toggleButtonVisibility(STATE_ONGOING);
};
+ /**
+ * Handle checking answer.
+ *
+ * @param {object} [params={}] Parameters.
+ * @param {boolean} [params.focusFirstAnswer] If true, focus first answer.
+ */
+ Blanks.prototype.handleCheckAnswer = function(params={}) {
+ this.toggleButtonVisibility(STATE_CHECKING);
+ this.showEvaluation();
+ this.triggerAnswered();
+
+ if (params.focusFirstAnswer) {
+ this.read(this.params.a11yHeader); // Announce 'checking mode'
+
+ window.setTimeout(() => {
+ this.$questions.filter(':first').find('input:first').focus();
+ }, 1); // Read 'checking mode' before announcing focus of first answer
+ }
+ }
+
/**
* Find blanks in a string and run a handler on those blanks
*
@@ -318,11 +331,6 @@ H5P.Blanks = (function ($, Question) {
self.hasClozes = clozeNumber > 0;
this.$questions = $(html);
- self.a11yHeader = document.createElement('div');
- self.a11yHeader.classList.add('hidden-but-read');
- self.a11yHeader.tabIndex = -1;
- self.$questions[0].insertBefore(self.a11yHeader, this.$questions[0].childNodes[0] || null);
-
// Set input fields.
this.$questions.find('input').each(function (i) {
@@ -346,10 +354,7 @@ H5P.Blanks = (function ($, Question) {
var answer = $("
").text(this.getUserAnswer()).html();
self.read((this.correct() ? self.params.answerIsCorrect : self.params.answerIsWrong).replace(':ans', answer));
if (self.done || self.allBlanksFilledOut()) {
- // All answers has been given. Show solutions button.
- self.toggleButtonVisibility(STATE_CHECKING);
- self.showEvaluation();
- self.triggerAnswered();
+ self.handleCheckAnswer();
self.done = true;
}
};
@@ -561,11 +566,12 @@ H5P.Blanks = (function ($, Question) {
/**
- * Displays the correct answers
- * @param {boolean} [alwaysShowSolution]
- * Will always show solution if true
+ * Displays the correct answers.
+ *
+ * @param {boolean} [alwaysShowSolution] Will always show solution if true.
+ * @param {boolean} [focusFirstAnswer] If true, focus first answer.
*/
- Blanks.prototype.showCorrectAnswers = function (alwaysShowSolution) {
+ Blanks.prototype.showCorrectAnswers = function (alwaysShowSolution, focusFirstAnswer) {
if (!alwaysShowSolution && !this.allowSolution()) {
return;
}
@@ -573,6 +579,10 @@ H5P.Blanks = (function ($, Question) {
this.toggleButtonVisibility(STATE_SHOWING_SOLUTION);
this.hideSolutions();
+ if (focusFirstAnswer) {
+ this.$questions.filter(':first').find('input:first').focus();
+ }
+
for (var i = 0; i < this.clozes.length; i++) {
this.clozes[i].showSolution();
}
@@ -930,9 +940,13 @@ H5P.Blanks = (function ($, Question) {
/**
* Disables any active input. Useful for freezing the task and dis-allowing
* modification of wrong answers.
+ *
+ * Not used here, but may be used by other content types, currently IV only.
*/
Blanks.prototype.disableInput = function () {
- this.$questions.find('input').attr('disabled', true);
+ this.clozes.forEach((cloze) => {
+ cloze.disableInput();
+ });
};
Blanks.idCounter = 0;
diff --git a/js/cloze.js b/js/cloze.js
index 8a60a7b..432a59b 100644
--- a/js/cloze.js
+++ b/js/cloze.js
@@ -82,8 +82,7 @@
var isCorrect = correct(checkedAnswer);
if (isCorrect) {
$wrapper.addClass('h5p-correct');
- $input.attr('disabled', true)
- .attr('aria-label', inputLabel + '. ' + l10n.answeredCorrectly);
+ this.toggleInput(false, inputLabel + '. ' + l10n.answeredCorrectly);
}
else {
$wrapper.addClass('h5p-wrong');
@@ -108,12 +107,19 @@
};
/**
- * Toggles input enable/disable
+ * Toggles input enable/disable. Leaves input field tabable.
+ *
* @method toggleInput
- * @param {boolean} enabled True if input should be enabled, otherwise false
+ * @param {boolean} enabled True if input should be enabled, otherwise false.
+ * @param {string} [ariaLabel] Optional change for aria label.
*/
- this.toggleInput = function (enabled) {
- $input.attr('disabled', !enabled);
+ this.toggleInput = function (enabled, ariaLabel) {
+ $input.attr('aria-disabled', !enabled);
+ $input.attr('readonly', !enabled ? true : null);
+
+ if (typeof ariaLabel === 'string') {
+ $input.attr('aria-label', ariaLabel);
+ }
};
/**
@@ -130,12 +136,12 @@
text: H5P.trim(answer.replace(/\s*\/\s*/g, '/')),
insertAfter: $wrapper
});
- $input.attr('disabled', true);
- var ariaLabel = inputLabel + '. ' +
+
+ const ariaLabel = inputLabel + '. ' +
l10n.solutionLabel + ' ' + answer + '. ' +
l10n.answeredIncorrectly;
- $input.attr('aria-label', ariaLabel);
+ this.toggleInput(false, ariaLabel);
};
/**
@@ -214,7 +220,7 @@
// Set trimmed answer
$input.val(trimmedAnswer);
if (behaviour.formulaEditor) {
- // If fomula editor is enabled set trimmed text
+ // If fomula editor is enabled set trimmed text
$input.parent().find('.wiris-h5p-input').html(trimmedAnswer);
}
return trimmedAnswer;