Skip to content

Commit 66a83dc

Browse files
authored
Merge branch 'develop' into sre-errors
2 parents 0194e45 + 5b664e6 commit 66a83dc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1120
-410
lines changed

components/src/input/mml/mml.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,13 @@ if (MathJax.startup) {
66
MathJax.startup.registerConstructor('mml', MathML);
77
MathJax.startup.useInput('mml');
88
}
9+
if (MathJax.loader) {
10+
//
11+
// Install a path-filter to cause loading of an entity file to load all entities,
12+
// since the individual files don't have individual components.
13+
//
14+
MathJax.loader.pathFilters.add((data) => {
15+
data.name = data.name.replace(/\/util\/entities\/.*?\.js/, '/input/mml/entities.js');
16+
return true;
17+
});
18+
}

ts/a11y/explorer.ts

Lines changed: 80 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,12 @@ export function ExplorerMathItemMixin<B extends Constructor<HTMLMATHITEM>>(
100100
/**
101101
* The currently attached explorers
102102
*/
103-
protected attached: Explorer[] = [];
103+
protected attached: string[] = [];
104104

105105
/**
106-
* True when a rerendered element should restart the explorer
106+
* True when a rerendered element should restart these explorers
107107
*/
108-
protected restart: boolean = false;
108+
protected restart: string[] = [];
109109

110110
/**
111111
* True when a rerendered element should regain the focus
@@ -146,16 +146,29 @@ export function ExplorerMathItemMixin<B extends Constructor<HTMLMATHITEM>>(
146146
*/
147147
public attachExplorers(document: ExplorerMathDocument) {
148148
this.attached = [];
149+
let keyExplorers = [];
149150
for (let key of Object.keys(this.explorers)) {
150151
let explorer = this.explorers[key];
152+
if (explorer instanceof ke.AbstractKeyExplorer) {
153+
explorer.AddEvents();
154+
explorer.stoppable = false;
155+
keyExplorers.unshift(explorer);
156+
}
151157
if (document.options.a11y[key]) {
152158
explorer.Attach();
153-
this.attached.push(explorer);
159+
this.attached.push(key);
154160
} else {
155161
explorer.Detach();
156162
}
157163
}
158-
this.addExplorers(this.attached);
164+
// Ensure that the last currently attached key explorer stops propagating
165+
// key events.
166+
for (let explorer of keyExplorers) {
167+
if (explorer.attached) {
168+
explorer.stoppable = true;
169+
break;
170+
}
171+
}
159172
}
160173

161174
/**
@@ -164,9 +177,10 @@ export function ExplorerMathItemMixin<B extends Constructor<HTMLMATHITEM>>(
164177
public rerender(document: ExplorerMathDocument, start: number = STATE.RERENDER) {
165178
this.savedId = this.typesetRoot.getAttribute('sre-explorer-id');
166179
this.refocus = (window.document.activeElement === this.typesetRoot);
167-
for (let explorer of this.attached) {
180+
for (let key of this.attached) {
181+
let explorer = this.explorers[key];
168182
if (explorer.active) {
169-
this.restart = true;
183+
this.restart.push(key);
170184
explorer.Stop();
171185
}
172186
}
@@ -179,25 +193,9 @@ export function ExplorerMathItemMixin<B extends Constructor<HTMLMATHITEM>>(
179193
public updateDocument(document: ExplorerMathDocument) {
180194
super.updateDocument(document);
181195
this.refocus && this.typesetRoot.focus();
182-
this.restart && this.attached.forEach(x => x.Start());
183-
this.refocus = this.restart = false;
184-
}
185-
186-
/**
187-
* Adds a list of explorers and makes sure the right one stops propagating.
188-
* @param {Explorer[]} explorers The active explorers to be added.
189-
*/
190-
private addExplorers(explorers: Explorer[]) {
191-
if (explorers.length <= 1) return;
192-
let lastKeyExplorer = null;
193-
for (let explorer of this.attached) {
194-
if (!(explorer instanceof ke.AbstractKeyExplorer)) continue;
195-
explorer.stoppable = false;
196-
lastKeyExplorer = explorer;
197-
}
198-
if (lastKeyExplorer) {
199-
lastKeyExplorer.stoppable = true;
200-
}
196+
this.restart.forEach(x => this.explorers[x].Start());
197+
this.restart = [];
198+
this.refocus = false;
201199
}
202200

203201
};
@@ -240,12 +238,15 @@ export function ExplorerMathDocumentMixin<B extends MathDocumentConstructor<HTML
240238
*/
241239
public static OPTIONS: OptionList = {
242240
...BaseDocument.OPTIONS,
243-
enrichSpeech: 'shallow', // overrides option in EnrichedMathDocument
244241
enableExplorer: true,
245242
renderActions: expandable({
246243
...BaseDocument.OPTIONS.renderActions,
247244
explorable: [STATE.EXPLORER]
248245
}),
246+
sre: expandable({
247+
...BaseDocument.OPTIONS.sre,
248+
speech: 'shallow', // overrides option in EnrichedMathDocument
249+
}),
249250
a11y: {
250251
align: 'top', // placement of magnified expression
251252
backgroundColor: 'Blue', // color for background of selected sub-expression
@@ -260,12 +261,10 @@ export function ExplorerMathDocumentMixin<B extends MathDocumentConstructor<HTML
260261
infoRole: false, // show semantic role on mouse hovering
261262
infoType: false, // show semantic type on mouse hovering
262263
keyMagnifier: false, // switch on magnification via key exploration
263-
locale: 'en', // switch the locale
264264
magnification: 'None', // type of magnification
265265
magnify: '400%', // percentage of magnification of zoomed expressions
266266
mouseMagnifier: false, // switch on magnification via mouse hovering
267267
speech: true, // switch on speech output
268-
speechRules: 'mathspeak-default', // speech rules as domain-style pair
269268
subtitles: true, // show speech as a subtitle
270269
treeColoring: false, // tree color expression
271270
viewBraille: false // display Braille output as subtitles
@@ -285,6 +284,7 @@ export function ExplorerMathDocumentMixin<B extends MathDocumentConstructor<HTML
285284
* @constructor
286285
*/
287286
constructor(...args: any[]) {
287+
processSreOptions(args[2]);
288288
super(...args);
289289
const ProcessBits = (this.constructor as typeof BaseDocument).ProcessBits;
290290
if (!ProcessBits.has('explorer')) {
@@ -293,6 +293,7 @@ export function ExplorerMathDocumentMixin<B extends MathDocumentConstructor<HTML
293293
const visitor = new SerializedMmlVisitor(this.mmlFactory);
294294
const toMathML = ((node: MmlNode) => visitor.visitTree(node));
295295
this.options.MathItem = ExplorerMathItemMixin(this.options.MathItem, toMathML);
296+
// TODO: set backward compatibility options here.
296297
this.explorerRegions = initExplorerRegions(this);
297298
}
298299

@@ -328,6 +329,33 @@ export function ExplorerMathDocumentMixin<B extends MathDocumentConstructor<HTML
328329

329330
}
330331

332+
//
333+
// TODO(v3.2): This is for backward compatibility of old option parameters.
334+
//
335+
/**
336+
* Processes old a11y options for backward compatibility.
337+
* @param {OptionList} options The options to process.
338+
*/
339+
function processSreOptions(options: OptionList) {
340+
if (!options || !options.a11y) {
341+
return;
342+
}
343+
if (!options.sre) {
344+
options.sre = {};
345+
}
346+
if (options.a11y.locale) {
347+
options.sre.locale = options.a11y.locale;
348+
delete options.a11y.locale;
349+
}
350+
if (options.a11y.speechRules) {
351+
let [domain, style] = (options.a11y.speechRules as string).split('-');
352+
options.sre.domain = domain;
353+
options.sre.style = style;
354+
delete options.a11y.speechRules;
355+
}
356+
}
357+
358+
331359
/*==========================================================================*/
332360

333361
/**
@@ -392,10 +420,9 @@ let allExplorers: {[options: string]: ExplorerInit} = {
392420
speech: (doc: ExplorerMathDocument, node: HTMLElement, ...rest: any[]) => {
393421
let explorer = ke.SpeechExplorer.create(
394422
doc, doc.explorerRegions.speechRegion, node, ...rest) as ke.SpeechExplorer;
395-
let [domain, style] = doc.options.a11y.speechRules.split('-');
396423
explorer.speechGenerator.setOptions({
397-
locale: doc.options.a11y.locale, domain: domain,
398-
style: style, modality: 'speech', cache: false});
424+
locale: doc.options.sre.locale, domain: doc.options.sre.domain,
425+
style: doc.options.sre.style, modality: 'speech', cache: false});
399426
explorer.showRegion = 'subtitles';
400427
return explorer;
401428
},
@@ -458,9 +485,17 @@ function initExplorers(document: ExplorerMathDocument, node: HTMLElement, mml: s
458485
* @param {{[key: string]: any}} options Association list for a11y option value pairs.
459486
*/
460487
export function setA11yOptions(document: HTMLDOCUMENT, options: {[key: string]: any}) {
488+
let sreOptions = SRE.engineSetup() as {[name: string]: string};
461489
for (let key in options) {
462490
if (document.options.a11y[key] !== undefined) {
463491
setA11yOption(document, key, options[key]);
492+
if (key === 'locale') {
493+
document.options.sre[key] = options[key];
494+
}
495+
continue;
496+
}
497+
if (sreOptions[key] !== undefined) {
498+
document.options.sre[key] = options[key];
464499
}
465500
}
466501
// Reinit explorers
@@ -516,6 +551,19 @@ export function setA11yOption(document: HTMLDOCUMENT, option: string, value: str
516551
break;
517552
}
518553
break;
554+
//
555+
// TODO(v3.2): These two cases should be handled directly in the menu
556+
// variable actions.
557+
//
558+
case 'speechRules':
559+
let [domain, style] = (value as string).split('-');
560+
document.options.sre.domain = domain;
561+
document.options.sre.style = style;
562+
break;
563+
case 'locale':
564+
document.options.sre.locale = value;
565+
SRE.setupEngine({locale: value as string});
566+
break;
519567
default:
520568
document.options.a11y[option] = value;
521569
}

ts/a11y/explorer/KeyExplorer.ts

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,19 @@ export interface KeyExplorer extends Explorer {
6464
*/
6565
export abstract class AbstractKeyExplorer<T> extends AbstractExplorer<T> implements KeyExplorer {
6666

67+
/**
68+
* Flag indicating if the explorer is attached to an object.
69+
*/
70+
public attached: boolean = false;
71+
6772
/**
6873
* The attached SRE walker.
6974
* @type {sre.Walker}
7075
*/
7176
protected walker: sre.Walker;
7277

78+
private eventsAttached: boolean = false;
79+
7380
/**
7481
* @override
7582
*/
@@ -109,19 +116,35 @@ export abstract class AbstractKeyExplorer<T> extends AbstractExplorer<T> impleme
109116
public Update(force: boolean = false) {
110117
if (!this.active && !force) return;
111118
this.highlighter.unhighlight();
112-
this.highlighter.highlight(this.walker.getFocus(true).getNodes());
119+
let nodes = this.walker.getFocus(true).getNodes();
120+
if (!nodes.length) {
121+
this.walker.refocus();
122+
nodes = this.walker.getFocus().getNodes();
123+
}
124+
this.highlighter.highlight(nodes);
113125
}
114126

115127
/**
116128
* @override
117129
*/
118130
public Attach() {
119131
super.Attach();
132+
this.attached = true;
120133
this.oldIndex = this.node.tabIndex;
121134
this.node.tabIndex = 1;
122135
this.node.setAttribute('role', 'application');
123136
}
124137

138+
/**
139+
* @override
140+
*/
141+
public AddEvents() {
142+
if (!this.eventsAttached) {
143+
super.AddEvents();
144+
this.eventsAttached = true;
145+
}
146+
}
147+
125148
/**
126149
* @override
127150
*/
@@ -131,7 +154,7 @@ export abstract class AbstractKeyExplorer<T> extends AbstractExplorer<T> impleme
131154
this.oldIndex = null;
132155
this.node.removeAttribute('role');
133156
}
134-
super.Detach();
157+
this.attached = false;
135158
}
136159

137160
/**
@@ -194,6 +217,7 @@ export class SpeechExplorer extends AbstractKeyExplorer<string> {
194217
* @override
195218
*/
196219
public Start() {
220+
if (!this.attached) return;
197221
let options = this.getOptions();
198222
// TODO: Check and set locale not only on init, but on every start.
199223
if (!this.init) {
@@ -212,8 +236,8 @@ export class SpeechExplorer extends AbstractKeyExplorer<string> {
212236
super.Start();
213237
this.speechGenerator = sre.SpeechGeneratorFactory.generator('Direct');
214238
this.speechGenerator.setOptions(options);
215-
this.walker = sre.WalkerFactory.walker('table',
216-
this.node, this.speechGenerator, this.highlighter, this.mml);
239+
this.walker = sre.WalkerFactory.walker(
240+
'table', this.node, this.speechGenerator, this.highlighter, this.mml);
217241
this.walker.activate();
218242
this.Update();
219243
if (this.document.options.a11y[this.showRegion]) {
@@ -233,7 +257,10 @@ export class SpeechExplorer extends AbstractKeyExplorer<string> {
233257
// during walking.
234258
let options = this.speechGenerator.getOptions();
235259
if (options.modality === 'speech') {
236-
this.document.options.a11y.speechRules = options.domain + '-' + options.style;
260+
this.document.options.sre.domain = options.domain;
261+
this.document.options.sre.style = options.style;
262+
this.document.options.a11y.speechRules =
263+
options.domain + '-' + options.style;
237264
}
238265
}
239266

@@ -300,13 +327,14 @@ export class SpeechExplorer extends AbstractKeyExplorer<string> {
300327
*/
301328
private getOptions(): {[key: string]: string} {
302329
let options = this.speechGenerator.getOptions();
303-
let [domain, style] = this.document.options.a11y.speechRules.split('-');
330+
let sreOptions = this.document.options.sre;
304331
if (options.modality === 'speech' &&
305-
(options.locale !== this.document.options.a11y.locale ||
306-
options.domain !== domain || options.style !== style)) {
307-
options.domain = domain;
308-
options.style = style;
309-
options.locale = this.document.options.a11y.locale;
332+
(options.locale !== sreOptions.locale ||
333+
options.domain !== sreOptions.domain ||
334+
options.style !== sreOptions.style)) {
335+
options.domain = sreOptions.domain;
336+
options.style = sreOptions.style;
337+
options.locale = sreOptions.locale;
310338
this.walker.update(options);
311339
}
312340
return options;
@@ -350,6 +378,7 @@ export class Magnifier extends AbstractKeyExplorer<HTMLElement> {
350378
*/
351379
public Start() {
352380
super.Start();
381+
if (!this.attached) return;
353382
this.region.Show(this.node, this.highlighter);
354383
this.walker.activate();
355384
this.Update();

0 commit comments

Comments
 (0)