Skip to content

Commit 2895baa

Browse files
authored
Merge branch 'develop' into issue2595
2 parents 0838edd + 35c20d3 commit 2895baa

File tree

36 files changed

+625
-156
lines changed

36 files changed

+625
-156
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: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -240,12 +240,15 @@ export function ExplorerMathDocumentMixin<B extends MathDocumentConstructor<HTML
240240
*/
241241
public static OPTIONS: OptionList = {
242242
...BaseDocument.OPTIONS,
243-
enrichSpeech: 'shallow', // overrides option in EnrichedMathDocument
244243
enableExplorer: true,
245244
renderActions: expandable({
246245
...BaseDocument.OPTIONS.renderActions,
247246
explorable: [STATE.EXPLORER]
248247
}),
248+
sre: expandable({
249+
...BaseDocument.OPTIONS.sre,
250+
speech: 'shallow', // overrides option in EnrichedMathDocument
251+
}),
249252
a11y: {
250253
align: 'top', // placement of magnified expression
251254
backgroundColor: 'Blue', // color for background of selected sub-expression
@@ -260,12 +263,10 @@ export function ExplorerMathDocumentMixin<B extends MathDocumentConstructor<HTML
260263
infoRole: false, // show semantic role on mouse hovering
261264
infoType: false, // show semantic type on mouse hovering
262265
keyMagnifier: false, // switch on magnification via key exploration
263-
locale: 'en', // switch the locale
264266
magnification: 'None', // type of magnification
265267
magnify: '400%', // percentage of magnification of zoomed expressions
266268
mouseMagnifier: false, // switch on magnification via mouse hovering
267269
speech: true, // switch on speech output
268-
speechRules: 'mathspeak-default', // speech rules as domain-style pair
269270
subtitles: true, // show speech as a subtitle
270271
treeColoring: false, // tree color expression
271272
viewBraille: false // display Braille output as subtitles
@@ -285,6 +286,7 @@ export function ExplorerMathDocumentMixin<B extends MathDocumentConstructor<HTML
285286
* @constructor
286287
*/
287288
constructor(...args: any[]) {
289+
processSreOptions(args[2]);
288290
super(...args);
289291
const ProcessBits = (this.constructor as typeof BaseDocument).ProcessBits;
290292
if (!ProcessBits.has('explorer')) {
@@ -293,6 +295,7 @@ export function ExplorerMathDocumentMixin<B extends MathDocumentConstructor<HTML
293295
const visitor = new SerializedMmlVisitor(this.mmlFactory);
294296
const toMathML = ((node: MmlNode) => visitor.visitTree(node));
295297
this.options.MathItem = ExplorerMathItemMixin(this.options.MathItem, toMathML);
298+
// TODO: set backward compatibility options here.
296299
this.explorerRegions = initExplorerRegions(this);
297300
}
298301

@@ -328,6 +331,33 @@ export function ExplorerMathDocumentMixin<B extends MathDocumentConstructor<HTML
328331

329332
}
330333

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

333363
/**
@@ -392,10 +422,9 @@ let allExplorers: {[options: string]: ExplorerInit} = {
392422
speech: (doc: ExplorerMathDocument, node: HTMLElement, ...rest: any[]) => {
393423
let explorer = ke.SpeechExplorer.create(
394424
doc, doc.explorerRegions.speechRegion, node, ...rest) as ke.SpeechExplorer;
395-
let [domain, style] = doc.options.a11y.speechRules.split('-');
396425
explorer.speechGenerator.setOptions({
397-
locale: doc.options.a11y.locale, domain: domain,
398-
style: style, modality: 'speech', cache: false});
426+
locale: doc.options.sre.locale, domain: doc.options.sre.domain,
427+
style: doc.options.sre.style, modality: 'speech', cache: false});
399428
explorer.showRegion = 'subtitles';
400429
return explorer;
401430
},
@@ -458,9 +487,17 @@ function initExplorers(document: ExplorerMathDocument, node: HTMLElement, mml: s
458487
* @param {{[key: string]: any}} options Association list for a11y option value pairs.
459488
*/
460489
export function setA11yOptions(document: HTMLDOCUMENT, options: {[key: string]: any}) {
490+
let sreOptions = SRE.engineSetup() as {[name: string]: string};
461491
for (let key in options) {
462492
if (document.options.a11y[key] !== undefined) {
463493
setA11yOption(document, key, options[key]);
494+
if (key === 'locale') {
495+
document.options.sre[key] = options[key];
496+
}
497+
continue;
498+
}
499+
if (sreOptions[key] !== undefined) {
500+
document.options.sre[key] = options[key];
464501
}
465502
}
466503
// Reinit explorers
@@ -516,6 +553,19 @@ export function setA11yOption(document: HTMLDOCUMENT, option: string, value: str
516553
break;
517554
}
518555
break;
556+
//
557+
// TODO(v3.2): These two cases should be handled directly in the menu
558+
// variable actions.
559+
//
560+
case 'speechRules':
561+
let [domain, style] = (value as string).split('-');
562+
document.options.sre.domain = domain;
563+
document.options.sre.style = style;
564+
break;
565+
case 'locale':
566+
document.options.sre.locale = value;
567+
SRE.setupEngine({locale: value as string});
568+
break;
519569
default:
520570
document.options.a11y[option] = value;
521571
}

ts/a11y/explorer/KeyExplorer.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,8 @@ export class SpeechExplorer extends AbstractKeyExplorer<string> {
212212
super.Start();
213213
this.speechGenerator = sre.SpeechGeneratorFactory.generator('Direct');
214214
this.speechGenerator.setOptions(options);
215-
this.walker = sre.WalkerFactory.walker('table',
216-
this.node, this.speechGenerator, this.highlighter, this.mml);
215+
this.walker = sre.WalkerFactory.walker(
216+
'table', this.node, this.speechGenerator, this.highlighter, this.mml);
217217
this.walker.activate();
218218
this.Update();
219219
if (this.document.options.a11y[this.showRegion]) {
@@ -233,7 +233,10 @@ export class SpeechExplorer extends AbstractKeyExplorer<string> {
233233
// during walking.
234234
let options = this.speechGenerator.getOptions();
235235
if (options.modality === 'speech') {
236-
this.document.options.a11y.speechRules = options.domain + '-' + options.style;
236+
this.document.options.sre.domain = options.domain;
237+
this.document.options.sre.style = options.style;
238+
this.document.options.a11y.speechRules =
239+
options.domain + '-' + options.style;
237240
}
238241
}
239242

@@ -300,13 +303,14 @@ export class SpeechExplorer extends AbstractKeyExplorer<string> {
300303
*/
301304
private getOptions(): {[key: string]: string} {
302305
let options = this.speechGenerator.getOptions();
303-
let [domain, style] = this.document.options.a11y.speechRules.split('-');
306+
let sreOptions = this.document.options.sre;
304307
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;
308+
(options.locale !== sreOptions.locale ||
309+
options.domain !== sreOptions.domain ||
310+
options.style !== sreOptions.style)) {
311+
options.domain = sreOptions.domain;
312+
options.style = sreOptions.style;
313+
options.locale = sreOptions.locale;
310314
this.walker.update(options);
311315
}
312316
return options;

ts/a11y/semantic-enrich.ts

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,9 @@ export function EnrichedMathItemMixin<N, T, D, B extends Constructor<AbstractMat
131131
if (typeof sre === 'undefined' || !sre.Engine.isReady()) {
132132
mathjax.retryAfter(sreReady());
133133
}
134-
if (document.options.enrichSpeech !== currentSpeech) {
135-
SRE.setupEngine({speech: document.options.enrichSpeech});
136-
currentSpeech = document.options.enrichSpeech;
134+
if (document.options.sre.speech !== currentSpeech) {
135+
SRE.setupEngine(document.options.sre);
136+
currentSpeech = document.options.sre.speech;
137137
}
138138
const math = new document.options.MathItem('', MmlJax);
139139
math.math = this.serializeMml(SRE.toEnriched(toMathML(this.root)));
@@ -240,12 +240,17 @@ export function EnrichedMathDocumentMixin<N, T, D, B extends MathDocumentConstru
240240
public static OPTIONS: OptionList = {
241241
...BaseDocument.OPTIONS,
242242
enableEnrichment: true,
243-
enrichSpeech: 'none', // or 'shallow', or 'deep'
244243
renderActions: expandable({
245244
...BaseDocument.OPTIONS.renderActions,
246245
enrich: [STATE.ENRICHED],
247246
attachSpeech: [STATE.ATTACHSPEECH]
248-
})
247+
}),
248+
sre: expandable({
249+
speech: 'none', // by default no speech is included
250+
domain: 'mathspeak', // speech rules domain
251+
style: 'default', // speech rules style
252+
locale: 'en' // switch the locale
253+
}),
249254
};
250255

251256
/**
@@ -256,6 +261,7 @@ export function EnrichedMathDocumentMixin<N, T, D, B extends MathDocumentConstru
256261
* @constructor
257262
*/
258263
constructor(...args: any[]) {
264+
processSreOptions(args[2]);
259265
super(...args);
260266
MmlJax.setMmlFactory(this.mmlFactory);
261267
const ProcessBits = (this.constructor as typeof AbstractMathDocument).ProcessBits;
@@ -335,3 +341,24 @@ export function EnrichHandler<N, T, D>(handler: Handler<N, T, D>, MmlJax: MathML
335341
);
336342
return handler;
337343
}
344+
345+
346+
//
347+
// TODO(v3.2): This is for backward compatibility of old option parameters.
348+
//
349+
/**
350+
* Processes old enrichment option for backward compatibility.
351+
* @param {OptionList} options The options to process.
352+
*/
353+
function processSreOptions(options: OptionList) {
354+
if (!options) {
355+
return;
356+
}
357+
if (!options.sre) {
358+
options.sre = {};
359+
}
360+
if (options.enrichSpeech) {
361+
options.sre.speech = options.enrichSpeech;
362+
delete options.enrichSpeech;
363+
}
364+
}

ts/adaptors/HTMLAdaptor.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export interface MinDocument<N, T> {
5353
* @template T The Text node class
5454
*/
5555
export interface MinHTMLElement<N, T> {
56+
nodeType: number;
5657
nodeName: string;
5758
nodeValue: string;
5859
textContent: string;
@@ -99,6 +100,7 @@ export interface MinHTMLElement<N, T> {
99100
* @template T The Text node class
100101
*/
101102
export interface MinText<N, T> {
103+
nodeType: number;
102104
nodeName: string;
103105
nodeValue: string;
104106
parentNode: N | Node;
@@ -365,7 +367,8 @@ AbstractDOMAdaptor<N, T, D> implements MinHTMLAdaptor<N, T, D> {
365367
* @override
366368
*/
367369
public kind(node: N | T) {
368-
return node.nodeName.toLowerCase();
370+
const n = node.nodeType;
371+
return (n === 1 || n === 3 || n === 8 ? node.nodeName.toLowerCase() : '');
369372
}
370373

371374
/**

ts/components/loader.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,20 @@ import {Package, PackageError, PackageReady, PackageFailed} from './package.js';
3030
export {Package, PackageError, PackageReady, PackageFailed} from './package.js';
3131
export {MathJaxLibrary} from './global.js';
3232

33+
import {FunctionList} from '../util/FunctionList.js';
34+
3335
/*
3436
* The current directory (for webpack), and the browser document (if any)
3537
*/
3638
declare var __dirname: string;
3739
declare var document: Document;
3840

41+
/**
42+
* Function used to determine path to a given package.
43+
*/
44+
export type PathFilterFunction = (data: {name: string, original: string, addExtension: boolean}) => boolean;
45+
export type PathFilterList = {[name: string]: PathFilterFunction};
46+
3947
/**
4048
* Update the configuration structure to include the loader configuration
4149
*/
@@ -65,10 +73,53 @@ export interface MathJaxObject extends MJObject {
6573
preLoad: (...names: string[]) => void; // Indicate that packages are already loaded by hand
6674
defaultReady: () => void; // The function performed when all packages are loaded
6775
getRoot: () => string; // Find the root URL for the MathJax files
76+
pathFilters: PathFilterList; // the filters to use for looking for package paths
6877
};
6978
startup?: any;
7079
}
7180

81+
/**
82+
* Functions used to filter the path to a package
83+
*/
84+
export const PathFilters: {[name: string]: PathFilterFunction} = {
85+
/**
86+
* Look up the path in the configuration's source list
87+
*/
88+
source: (data) => {
89+
if (CONFIG.source.hasOwnProperty(data.name)) {
90+
data.name = CONFIG.source[data.name];
91+
}
92+
return true;
93+
},
94+
95+
/**
96+
* Add [mathjax] before any relative path, and add .js if needed
97+
*/
98+
normalize: (data) => {
99+
const name = data.name;
100+
if (!name.match(/^(?:[a-z]+:\/)?\/|[a-z]:\\|\[/i)) {
101+
data.name = '[mathjax]/' + name.replace(/^\.\//, '');
102+
}
103+
if (data.addExtension && !name.match(/\.[^\/]+$/)) {
104+
data.name += '.js';
105+
}
106+
return true;
107+
},
108+
109+
/**
110+
* Recursively replace path prefixes (e.g., [mathjax], [tex], etc.)
111+
*/
112+
prefix: (data) => {
113+
let match;
114+
while ((match = data.name.match(/^\[([^\]]*)\]/))) {
115+
if (!CONFIG.paths.hasOwnProperty(match[1])) break;
116+
data.name = CONFIG.paths[match[1]] + data.name.substr(match[0].length);
117+
}
118+
return true;
119+
}
120+
};
121+
122+
72123
/**
73124
* The implementation of the dynamic loader
74125
*/
@@ -157,6 +208,17 @@ export namespace Loader {
157208
return root;
158209
}
159210

211+
/**
212+
* The filters to use to modify the paths used to obtain the packages
213+
*/
214+
export const pathFilters = new FunctionList();
215+
216+
/**
217+
* The default filters to use.
218+
*/
219+
pathFilters.add(PathFilters.source, 1);
220+
pathFilters.add(PathFilters.normalize, 2);
221+
pathFilters.add(PathFilters.prefix, 5);
160222
}
161223

162224
/**

0 commit comments

Comments
 (0)