Skip to content

Commit

Permalink
Merge pull request #1142 from drgrice1/mathquill-accessibility-improv…
Browse files Browse the repository at this point in the history
…ements

Mathquill accessibility improvements
  • Loading branch information
Alex-Jordan authored Dec 11, 2024
2 parents f4e6aa7 + 2211244 commit d0ea4b1
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 41 deletions.
112 changes: 79 additions & 33 deletions htdocs/js/MathQuill/mqeditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
window.answerQuills = {};

// initialize MathQuill
const MQ = MathQuill.getInterface(2);
const MQ = MathQuill.getInterface();

let toolbarEnabled = (localStorage.getItem('MQEditorToolbarEnabled') ?? 'true') === 'true';

Expand Down Expand Up @@ -43,7 +43,7 @@

// Default options.
const cfgOptions = {
spaceBehavesLikeTab: true,
enableSpaceNavigation: true,
leftRightIntoCmdGoes: 'up',
restrictMismatchedBrackets: true,
sumStartsWithNEquals: true,
Expand All @@ -62,7 +62,8 @@
if (answerQuill.latexInput.dataset.mqOpts)
Object.assign(cfgOptions, JSON.parse(answerQuill.latexInput.dataset.mqOpts));

// This is after the option merge to prevent handlers from being overridden.
// The handlers and blurWithCursor options are set after
// the option merge to prevent them from being overridden.
cfgOptions.handlers = {
// Disable the toolbar when a text block is entered.
textBlockEnter: () => {
Expand All @@ -76,6 +77,11 @@
}
};

cfgOptions.blurWithCursor = (e) =>
toolbarEnabled &&
answerQuill.toolbar &&
(e.relatedTarget?.closest('.quill-toolbar') || e.relatedTarget?.classList.contains('symbol-button'));

const latexEntryMode = input.classList.contains('latexentryfield');

if (latexEntryMode) {
Expand Down Expand Up @@ -273,6 +279,26 @@
if (feedbackBtn) bootstrap.Popover.getInstance(feedbackBtn)?.update();
};

// Trigger a button press when the enter key is pressed in an answer box.
cfgOptions.handlers.enter = () => {
// Ensure that the toolbar and any open tooltips are removed.
answerQuill.toolbar?.tooltips.forEach((tooltip) => tooltip.dispose());
answerQuill.toolbar?.remove();
delete answerQuill.toolbar;

// For ww2 homework, depends on $pg{options}{enterKey}
const enterKeySubmit = document.getElementById('enter_key_submit');
if (enterKeySubmit) enterKeySubmit.click();
else document.getElementById('previewAnswers_id')?.click();
// For gateway quizzes, always the preview button
document.querySelector('input[name=previewAnswers]')?.click();
// For ww3
const previewButtonId = answerQuill.textarea
.closest('[name=problemMainForm]')
?.id.replace('problemMainForm', 'previewAnswers');
if (previewButtonId) document.getElementById(previewButtonId)?.click();
};

input.after(answerQuill);
}

Expand Down Expand Up @@ -301,9 +327,11 @@
delete answerQuill.toolbar;
toolbar.style.opacity = 0;
window.removeEventListener('resize', toolbar.setPosition);
window.removeEventListener('focus', toolbar.removeOnWindowRefocus);
toolbar.tooltips.forEach((tooltip) => tooltip.dispose());
toolbar.addEventListener('transitionend', () => toolbar.remove(), { once: true });
toolbar.addEventListener('transitioncancel', () => toolbar.remove(), { once: true });
if (toolbarEnabled && document.activeElement !== answerQuill.textarea) answerQuill.mathField.blur();
}
};

Expand All @@ -319,17 +347,31 @@

answerQuill.toolbar.addEventListener('focusout', (e) => {
if (
!document.hasFocus() ||
(e.relatedTarget &&
(e.relatedTarget.closest('.quill-toolbar') ||
e.relatedTarget.classList.contains('symbol-button') ||
e.relatedTarget.parentElement?.parentElement === answerQuill)) ||
e.relatedTarget === answerQuill.textarea)) ||
(answerQuill.clearButton && e.relatedTarget === answerQuill.clearButton)
)
return;

toolbarRemove();
});

// If the window is refocused after a blur, and the focus is not on the toolbar
// or the MathQuill input, then remove the toolbar.
answerQuill.toolbar.removeOnWindowRefocus = () => {
if (
document.activeElement &&
!document.activeElement.closest('.quill-toolbar') &&
!document.activeElement.classList.contains('symbol-button') &&
document.activeElement !== answerQuill.textarea
)
toolbarRemove();
};
window.addEventListener('focus', answerQuill.toolbar.removeOnWindowRefocus);

answerQuill.toolbar.tooltips = [];

for (const buttonData of answerQuill.buttons) {
Expand All @@ -347,7 +389,7 @@
button.append(icon);
answerQuill.toolbar.append(button);

MQ.StaticMath(icon, { mouseEvents: false });
MQ.StaticMath(icon, { mouseEvents: false, tabbable: false });

answerQuill.toolbar.tooltips.push(new bootstrap.Tooltip(button, { placement: 'left' }));

Expand All @@ -357,8 +399,34 @@
});
}

const getNextFocusableElement = (currentElement) => {
const focusableElements = Array.from(
document.querySelectorAll(
'a[href]:not([tabindex="-1"]),' +
'button:not([tabindex="-1"]),' +
'input:not([tabindex="-1"]),' +
'textarea:not([tabindex="-1"]),' +
'select:not([tabindex="-1"]),' +
'details:not([tabindex="-1"]),' +
'[tabindex]:not([tabindex="-1"])'
)
);

let currentIndex = focusableElements.indexOf(currentElement);
if (currentIndex === -1) return;

for (const focusableElement of focusableElements.slice(currentIndex + 1)) {
if (!focusableElement.disabled && focusableElement.offsetParent !== null) return focusableElement;
}
};

answerQuill.toolbar.addEventListener('keydown', (e) => {
if (e.key === 'Escape') toolbarRemove();
if (e.key === 'Escape') {
const nextFocusable = getNextFocusableElement(answerQuill.toolbar.lastElementChild);
console.log(nextFocusable);
toolbarRemove();
nextFocusable?.focus();
}
});

answerQuill.toolbar.setPosition = () => {
Expand Down Expand Up @@ -494,10 +562,11 @@

answerQuill.textarea.addEventListener('focusout', (e) => {
if (
e.relatedTarget &&
(e.relatedTarget.closest('.quill-toolbar') ||
e.relatedTarget.classList.contains('symbol-button') ||
(answerQuill.clearButton && e.relatedTarget === answerQuill.clearButton))
!document.hasFocus() ||
(e.relatedTarget &&
(e.relatedTarget.closest('.quill-toolbar') ||
e.relatedTarget.classList.contains('symbol-button') ||
(answerQuill.clearButton && e.relatedTarget === answerQuill.clearButton)))
)
return;

Expand All @@ -508,29 +577,6 @@

if (latexEntryMode) return;

// Trigger a button press when the enter key is pressed in an answer box.
answerQuill.keydownHandler = (e) => {
if (e.key == 'Enter') {
// Ensure that the toolbar and any open tooltips are removed.
answerQuill.toolbar?.tooltips.forEach((tooltip) => tooltip.dispose());
answerQuill.toolbar?.remove();
delete answerQuill.toolbar;

// For ww2 homework, depends on $pg{options}{enterKey}
const enterKeySubmit = document.getElementById('enter_key_submit');
if (enterKeySubmit) enterKeySubmit.click();
else document.getElementById('previewAnswers_id')?.click();
// For gateway quizzes, always the preview button
document.querySelector('input[name=previewAnswers]')?.click();
// For ww3
const previewButtonId = answerQuill.textarea
.closest('[name=problemMainForm]')
?.id.replace('problemMainForm', 'previewAnswers');
if (previewButtonId) document.getElementById(previewButtonId)?.click();
}
};
answerQuill.addEventListener('keydown', answerQuill.keydownHandler);

setTimeout(() => {
answerQuill.mathField.latex(answerQuill.latexInput.value);
answerQuill.mathField.moveToLeftEnd();
Expand Down
14 changes: 7 additions & 7 deletions htdocs/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion htdocs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"prettier-check": "prettier --ignore-path=../.gitignore --check \"**/*.{js,css,scss,html}\" \"../**/*.dist.yml\""
},
"dependencies": {
"@openwebwork/mathquill": "^0.11.0-beta.1",
"@openwebwork/mathquill": "^0.11.0-beta.2",
"jsxgraph": "^1.9.2",
"jszip": "^3.10.1",
"jszip-utils": "^0.1.0",
Expand Down

0 comments on commit d0ea4b1

Please sign in to comment.