Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update MathJax contextual menus for assistive tools #1068

Merged
merged 6 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions components/bin/build
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const EXPORTPATTERN =
/(^export(?:\s+default)?(?:\s+abstract)?\s+(?:[^ {*}]+\s+(?:enum\s+)?[a-zA-Z0-9_.$]+|\{.* as .*\}))/m;

const EXPORT_IGNORE = ['type', 'interface'];
const EXPORT_PROCESS = ['let', 'const', 'var', 'function', 'class', 'namespace', 'as'];
const EXPORT_PROCESS = ['let', 'const', 'var', 'function', 'class', 'namespace', 'enum', 'as'];

/**
* The module type to use ('cjs' or 'mjs')
Expand Down Expand Up @@ -159,7 +159,7 @@ function processParts(parts) {
for (let i = 1; i < parts.length; i += 2) {
const words = parts[i].split(/\s+/);
const n = words.length;
const type = (words[n - 2] === 'enum' ? words[n - 3] : words[n - 2]);
const type = (words[n - 2] === 'enum' && n > 3 ? words[n - 3] : words[n - 2]);
const name = words[n - 1].replace(/\}$/, '');

if (words[1] === 'default' || type === 'default') {
Expand Down
1 change: 0 additions & 1 deletion components/mjs/a11y/explorer/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"webpack": {
"name": "a11y/explorer",
"libs": [
"components/src/ui/menu/lib",
"components/src/a11y/semantic-enrich/lib",
"components/src/a11y/sre/lib",
"components/src/input/mml/lib",
Expand Down
10 changes: 0 additions & 10 deletions components/mjs/a11y/explorer/explorer.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
import './lib/explorer.js';

import {combineDefaults} from '#js/components/global.js';
import {ExplorerHandler} from '#js/a11y/explorer.js';

if (MathJax.startup && typeof window !== 'undefined') {
if (MathJax.config.options && MathJax.config.options.enableExplorer !== false) {
combineDefaults(MathJax.config, 'options', {
menuOptions: {
settings: {
explorer: true
}
}
});
}
MathJax.startup.extendHandler(handler => ExplorerHandler(handler));
}
6 changes: 5 additions & 1 deletion components/mjs/a11y/semantic-enrich/config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
{
"build": {
"component": "a11y/semantic-enrich",
"targets": ["a11y/semantic-enrich.ts"]
"targets": [
"a11y/semantic-enrich.ts",
"a11y/speech/SpeechUtil.ts",
"a11y/speech/GeneratorPool.ts"
]
},
"webpack": {
"name": "a11y/semantic-enrich",
Expand Down
2 changes: 1 addition & 1 deletion components/mjs/dependencies.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
export const dependencies = {
'a11y/semantic-enrich': ['input/mml', 'a11y/sre'],
'a11y/complexity': ['a11y/semantic-enrich'],
'a11y/explorer': ['a11y/semantic-enrich', 'ui/menu'],
'a11y/explorer': ['a11y/semantic-enrich'],
'[mml]/mml3': ['input/mml'],
'[tex]/all-packages': ['input/tex-base'],
'[tex]/action': ['input/tex-base', '[tex]/newcommand'],
Expand Down
2 changes: 1 addition & 1 deletion components/mjs/ui/menu/config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"build": {
"component": "ui/menu",
"targets": ["ui/menu"],
"targets": ["ui/menu", "a11y/speech/SpeechMenu.ts"],
"excludeSubdirs": true
},
"webpack": {
Expand Down
23 changes: 8 additions & 15 deletions ts/a11y/explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ export function ExplorerMathDocumentMixin<B extends MathDocumentConstructor<HTML
align: 'top', // placement of magnified expression
backgroundColor: 'Blue', // color for background of selected sub-expression
backgroundOpacity: 20, // opacity for background of selected sub-expression
braille: false, // switch on Braille output
braille: true, // switch on Braille output
flame: false, // color collapsible sub-expressions
foregroundColor: 'Black', // color to use for text of selected sub-expression
foregroundOpacity: 100, // opacity for text of selected sub-expression
Expand All @@ -219,7 +219,7 @@ export function ExplorerMathDocumentMixin<B extends MathDocumentConstructor<HTML
speech: true, // switch on speech output
subtitles: true, // show speech as a subtitle
treeColoring: false, // tree color expression
viewBraille: false, // display Braille output as subtitles
viewBraille: true, // display Braille output as subtitles
voicing: false, // switch on speech output
}
};
Expand Down Expand Up @@ -257,12 +257,6 @@ export function ExplorerMathDocumentMixin<B extends MathDocumentConstructor<HTML
* @return {ExplorerMathDocument} The MathDocument (so calls can be chained)
*/
public explorable(): ExplorerMathDocument {
if (this.options.a11y.speech) {
this.options.enableSpeech = true;
}
if (this.options.a11y.braille) {
this.options.enableBraille = true;
}
if (!this.processed.isSet('explorer')) {
if (this.options.enableExplorer) {
if (!this.explorerRegions) {
Expand Down Expand Up @@ -325,18 +319,13 @@ export function setA11yOptions(document: HTMLDOCUMENT, options: {[key: string]:
for (let key in options) {
if (document.options.a11y[key] !== undefined) {
setA11yOption(document, key, options[key]);
if (key === 'locale') {
document.options.sre[key] = options[key];
}
continue;
}
if (sreOptions[key] !== undefined) {
} else if (sreOptions[key] !== undefined) {
document.options.sre[key] = options[key];
}
}
// Reinit explorers
for (let item of document.math) {
(item as ExplorerMathItem).explorers.attach();
(item as ExplorerMathItem)?.explorers?.attach();
}
}

Expand Down Expand Up @@ -392,6 +381,10 @@ export function setA11yOption(document: HTMLDOCUMENT, option: string, value: str
break;
}
break;
case 'locale':
document.options.sre.locale = value;
document.options.a11y.locale = value;
break;
default:
document.options.a11y[option] = value;
}
Expand Down
3 changes: 2 additions & 1 deletion ts/a11y/explorer/ExplorerPool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ export class ExplorerPool {
public attach() {
this.attached = [];
let keyExplorers = [];
const a11y = this.document.options.a11y;
for (let [key, explorer] of Object.entries(this.explorers)) {
if (explorer instanceof SpeechExplorer) {
explorer.AddEvents();
Expand All @@ -230,7 +231,7 @@ export class ExplorerPool {
}
continue;
}
if (this.document.options.a11y[key]) {
if (a11y[key] || (key === 'speech' && (a11y.braille || a11y.keyMagnifier))) {
explorer.Attach();
this.attached.push(key);
} else {
Expand Down
11 changes: 5 additions & 6 deletions ts/a11y/explorer/KeyExplorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -478,26 +478,25 @@ export class SpeechExplorer extends AbstractExplorer<string> implements KeyExplo
// the root node by default.
this.current = this.node.childNodes[0] as HTMLElement;
}
const options = this.document.options;
let promise = Sre.sreReady();
if (this.generators.update(this.document.options)) {
if (this.generators.update(options)) {
promise = promise.then(
() => this.Speech()
);
};
this.current.setAttribute('tabindex', '0');
this.current.focus();
super.Start();
if (this.document.options.a11y.speech &&
this.document.options.a11y.subtitles) {
if (options.a11y.subtitles && options.a11y.speech && options.enableSpeech) {
promise.then(
() => this.region.Show(this.node, this.highlighter));
}
if (this.document.options.a11y.braille &&
this.document.options.a11y.viewBraille) {
if (options.a11y.viewBraille && options.a11y.braille && options.enableBraille) {
promise.then(
() => this.brailleRegion.Show(this.node, this.highlighter));
}
if (this.document.options.a11y.keyMagnifier) {
if (options.a11y.keyMagnifier) {
this.magnifyRegion.Show(this.node, this.highlighter);
}
this.Update();
Expand Down
52 changes: 47 additions & 5 deletions ts/a11y/semantic-enrich.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ export interface EnrichedMathItem<N, T, D> extends MathItem<N, T, D> {
* @param {MathDocument} document The document where enrichment is occurring
*/
attachSpeech(document: MathDocument<N, T, D>): void;

/**
* @param {MathDocument} document The MathDocument for the MathItem
*/
unEnrich(document: MathDocument<N, T, D>): void;
}

/**
Expand Down Expand Up @@ -201,6 +206,19 @@ export function EnrichedMathItemMixin<N, T, D, B extends Constructor<AbstractMat
this.state(STATE.ENRICHED);
}

/**
* @param {MathDocument} document The MathDocument for the MathItem
*/
public unEnrich(document: MathDocument<N, T, D>) {
const mml = this.inputData.originalMml;
if (!mml) return;
const math = new document.options.MathItem('', MmlJax);
math.math = mml;
math.display = this.display;
math.compile(document);
this.root = math.root;
}

/**
* Correct the selection values for the maction items from the original MathML
*/
Expand Down Expand Up @@ -248,25 +266,28 @@ export function EnrichedMathItemMixin<N, T, D, B extends Constructor<AbstractMat
if (this.isEscaped || !document.options.enableEnrichment) return;
let [speech, braille] = this.existingSpeech();
let [newSpeech, newBraille] = ['', ''];
if ((!speech && document.options.enableSpeech) ||
(!braille && document.options.enableBraille)) {
const options = document.options;
if ((!speech && options.enableSpeech) ||
(!braille && options.enableBraille)) {
try {
[newSpeech, newBraille] = this.generatorPool.computeSpeech(
this.typesetRoot, this.toMathML(this.root, this));
if (newSpeech) {
newSpeech = buildSpeech(newSpeech)[0];
}
} catch (_e) { }
} catch (err) {
document.options.speechError(document, this, err);
}
}
speech = speech || newSpeech;
braille = braille || newBraille;
if (!speech && !braille) return;
const adaptor = document.adaptor;
const node = this.typesetRoot;
if (speech && document.options.enableSpeech) {
if (speech && options.enableSpeech) {
adaptor.setAttribute(node, 'aria-label', speech as string);
}
if (braille && document.options.enableBraille) {
if (braille && options.enableBraille) {
adaptor.setAttribute(node, 'aria-braillelabel', braille as string);
}
for (const child of adaptor.childNodes(node) as N[]) {
Expand Down Expand Up @@ -311,6 +332,13 @@ export interface EnrichedMathDocument<N, T, D> extends AbstractMathDocument<N, T
* @param {Error} err The error being processed
*/
enrichError(doc: EnrichedMathDocument<N, T, D>, math: EnrichedMathItem<N, T, D>, err: Error): void;

/**
* @param {EnrichedMathDocument} doc The MathDocument for the error
* @paarm {EnrichedMathItem} math The MathItem causing the error
* @param {Error} err The error being processed
*/
speechError(doc: EnrichedMathDocument<N, T, D>, math: EnrichedMathItem<N, T, D>, err: Error): void;
}

/**
Expand Down Expand Up @@ -343,6 +371,9 @@ export function EnrichedMathDocumentMixin<N, T, D, B extends MathDocumentConstru
enrichError: (doc: EnrichedMathDocument<N, T, D>,
math: EnrichedMathItem<N, T, D>,
err: Error) => doc.enrichError(doc, math, err),
speechError: (doc: EnrichedMathDocument<N, T, D>,
math: EnrichedMathItem<N, T, D>,
err: Error) => doc.speechError(doc, math, err),
renderActions: expandable({
...BaseDocument.OPTIONS.renderActions,
enrich: [STATE.ENRICHED],
Expand Down Expand Up @@ -416,13 +447,24 @@ export function EnrichedMathDocumentMixin<N, T, D, B extends MathDocumentConstru
console.warn('Enrichment error:', err);
}

/**
*/
public speechError(_doc: EnrichedMathDocument<N, T, D>, _math: EnrichedMathItem<N, T, D>, err: Error) {
console.warn('Speech generation error:', err);
}

/**
* @override
*/
public state(state: number, restore: boolean = false) {
super.state(state, restore);
if (state < STATE.ENRICHED) {
this.processed.clear('enriched');
if (state >= STATE.COMPILED) {
for (const item of this.math) {
(item as EnrichedMathItem<N, T, D>).unEnrich(this);
}
}
}
if (state < STATE.ATTACHSPEECH) {
this.processed.clear('attach-speech');
Expand Down
26 changes: 14 additions & 12 deletions ts/a11y/speech/SpeechMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,23 +169,25 @@ export function clearspeakMenu(menu: MJContextMenu, sub: Submenu) {
let locale = menu.pool.lookup('locale').getValue() as string;
const box = csSelectionBox(menu, locale);
let items: Object[] = [];
const explorer = (menu.mathItem as ExplorerMathItem)?.explorers?.speech;
const semantic = explorer?.semanticFocus();
const previous = Sre.clearspeakPreferences.currentPreference();
items = items.concat(basePreferences(previous));
if (semantic) {
const smart = Sre.clearspeakPreferences.relevantPreferences(semantic);
items = items.concat(smartPreferences(previous, smart, locale));
}
if (box) {
items.splice(2, 0, box);
if (menu.settings.speech) {
const explorer = (menu.mathItem as ExplorerMathItem)?.explorers?.speech;
const semantic = explorer?.semanticFocus();
const previous = Sre.clearspeakPreferences.currentPreference();
items = items.concat(basePreferences(previous));
if (semantic) {
const smart = Sre.clearspeakPreferences.relevantPreferences(semantic);
items = items.concat(smartPreferences(previous, smart, locale));
}
if (box) {
items.splice(2, 0, box);
}
}
return menu.factory.get('subMenu')(menu.factory, {
items: items,
id: 'Clearspeak'
}, sub);
}
MJContextMenu.DynamicSubmenus.set('Clearspeak', clearspeakMenu);
MJContextMenu.DynamicSubmenus.set('Clearspeak', [clearspeakMenu, 'speech']);

let LOCALE_MENU: SubMenu = null;
/**
Expand All @@ -209,4 +211,4 @@ export function localeMenu(menu: MJContextMenu, sub: Submenu) {
items: radios, id: 'Language'}, sub);
return LOCALE_MENU;
}
MJContextMenu.DynamicSubmenus.set('A11yLanguage', localeMenu);
MJContextMenu.DynamicSubmenus.set('A11yLanguage', [localeMenu, 'speech']);
Loading