Skip to content

Commit 6a3608a

Browse files
committed
Merge branch 'core-update' into beta.3
2 parents 10a8a37 + c00be3b commit 6a3608a

24 files changed

+333
-120
lines changed

mathjax3-ts/core/DOMAdaptor.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -571,8 +571,9 @@ export abstract class AbstractDOMAdaptor<N, T, D> implements DOMAdaptor<N, T, D>
571571
* @override
572572
*/
573573
public allClasses(node: N) {
574-
const classes = this.getAttribute(node, 'class') || '';
575-
return classes.replace(/ +/g, ' ').replace(/^ /, '').replace(/ $/, '').split(/ /);
574+
const classes = this.getAttribute(node, 'class');
575+
return (!classes ? [] as string[] :
576+
classes.replace(/ +/g, ' ').replace(/^ /, '').replace(/ $/, '').split(/ /));
576577
}
577578

578579
/**

mathjax3-ts/core/Handler.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
* @author [email protected] (Davide Cervone)
2222
*/
2323

24-
import {MathDocument, AbstractMathDocument} from './MathDocument.js';
24+
import {MathDocument, AbstractMathDocument, MathDocumentConstructor} from './MathDocument.js';
2525
import {OptionList} from '../util/Options.js';
2626
import {DOMAdaptor} from '../core/DOMAdaptor.js';
2727

@@ -50,6 +50,12 @@ export interface Handler<N, T, D> {
5050
*/
5151
priority: number;
5252

53+
/**
54+
* The class implementing the MathDocument for this handler
55+
* (so it can be subclassed by extensions as needed)
56+
*/
57+
documentClass: MathDocumentConstructor<N, T, D>;
58+
5359
/**
5460
* Checks to see if the handler can process a given document
5561
*
@@ -62,11 +68,10 @@ export interface Handler<N, T, D> {
6268
* Creates a MathDocument for the given handler
6369
*
6470
* @param {any} document The document to be handled
65-
* @param {DOMAdaptor} adaptor The DOM adaptor for managing HTML elements
6671
* @param {OptionList} options The options for the handling of the document
6772
* @return {MathDocument} The MathDocument object that manages the processing
6873
*/
69-
create(document: any, adaptor: DOMAdaptor<N, T, D>, options: OptionList): MathDocument<N, T, D>;
74+
create(document: any, options: OptionList): MathDocument<N, T, D>;
7075
}
7176

7277
/*****************************************************************/
@@ -104,6 +109,12 @@ export abstract class AbstractHandler<N, T, D> implements Handler<N, T, D> {
104109
*/
105110
public priority: number;
106111

112+
/**
113+
* The class implementing the MathDocument for this handler
114+
* (so it can be subclassed by extensions as needed)
115+
*/
116+
public documentClass: MathDocumentConstructor<N, T, D> = DefaultMathDocument;
117+
107118
/**
108119
* @param {number} priority The priority to use for this handler
109120
*
@@ -132,7 +143,7 @@ export abstract class AbstractHandler<N, T, D> implements Handler<N, T, D> {
132143
* @override
133144
*/
134145
public create(document: any, options: OptionList) {
135-
return new DefaultMathDocument<N, T, D>(document, this.adaptor, options) as MathDocument<N, T, D>;
146+
return new this.documentClass(document, this.adaptor, options) as MathDocument<N, T, D>;
136147
}
137148

138149
}

mathjax3-ts/core/HandlerList.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ export class HandlerList<N, T, D> extends PrioritizedList<Handler<N, T, D>> {
7575
* @param {OptionList} options The options for the handler
7676
* @return {MathDocument} The MathDocument created by the handler for this document
7777
*/
78-
public document(document: any, adaptor: DOMAdaptor<N, T, D>, options: OptionList = null) {
79-
return this.handlesDocument(document).create(document, adaptor, options);
78+
public document(document: any, options: OptionList = null) {
79+
return this.handlesDocument(document).create(document, options);
8080
}
8181

8282
}

mathjax3-ts/core/InputJax.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import {MathItem, ProtoItem} from './MathItem.js';
2525
import {MmlNode} from './MmlTree/MmlNode.js';
26+
import {MmlFactory} from './MmlTree/MmlFactory.js';
2627
import {userOptions, defaultOptions, OptionList} from '../util/Options.js';
2728
import {FunctionList} from '../util/FunctionList.js';
2829
import {DOMAdaptor} from '../core/DOMAdaptor.js';
@@ -63,11 +64,21 @@ export interface InputJax<N, T, D> {
6364
*/
6465
adaptor: DOMAdaptor<N, T, D>;
6566

67+
/**
68+
* The MmlFactory for this input jax
69+
*/
70+
mmlFactory: MmlFactory;
71+
6672
/**
6773
* @param {DOMAdaptor} The adaptor to use in this jax
6874
*/
6975
setAdaptor(adaptor: DOMAdaptor<N, T, D>): void;
7076

77+
/**
78+
* @param {MmlFactory} The MmlFactory to use in this jax
79+
*/
80+
setMmlFactory(mmlFactory: MmlFactory): void;
81+
7182
/**
7283
* Finds the math within the DOM or the list of strings
7384
*
@@ -104,6 +115,7 @@ export abstract class AbstractInputJax<N, T, D> implements InputJax<N, T, D> {
104115
public preFilters: FunctionList;
105116
public postFilters: FunctionList;
106117
public adaptor: DOMAdaptor<N, T, D> = null; // set by the handler
118+
public mmlFactory: MmlFactory = null; // set by the handler
107119

108120
/**
109121
* @param {OptionList} options The options to applyt to this input jax
@@ -131,6 +143,13 @@ export abstract class AbstractInputJax<N, T, D> implements InputJax<N, T, D> {
131143
this.adaptor = adaptor;
132144
}
133145

146+
/**
147+
* @override
148+
*/
149+
public setMmlFactory(mmlFactory: MmlFactory) {
150+
this.mmlFactory = mmlFactory;
151+
}
152+
134153
/**
135154
* @return {boolean} True means find math in string array, false means in DOM element
136155
*/

mathjax3-ts/core/MathDocument.ts

Lines changed: 59 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {MathItem, AbstractMathItem} from './MathItem.js';
2929
import {MmlNode, TextNode} from './MmlTree/MmlNode.js';
3030
import {MmlFactory} from '../core/MmlTree/MmlFactory.js';
3131
import {DOMAdaptor} from '../core/DOMAdaptor.js';
32+
import {BitField, BitFieldClass} from '../util/BitField.js';
3233

3334
/*****************************************************************/
3435
/**
@@ -79,7 +80,7 @@ export interface MathDocument<N, T, D> {
7980
* asynchronous operations are used), the ones that have already been
8081
* completed won't be performed again.
8182
*/
82-
processed: {[name: string]: boolean};
83+
processed: BitField;
8384

8485
/**
8586
* An array of input jax to run on the document
@@ -96,6 +97,11 @@ export interface MathDocument<N, T, D> {
9697
*/
9798
adaptor: DOMAdaptor<N, T, D>;
9899

100+
/**
101+
* The MmlFactory to be used for input jax and error processing
102+
*/
103+
mmlFactory: MmlFactory;
104+
99105
/**
100106
* Locates the math in the document and constructs the MathList
101107
* for the document.
@@ -178,19 +184,6 @@ export interface MathDocument<N, T, D> {
178184
}
179185

180186
/*****************************************************************/
181-
/**
182-
* The booleans used to keep track of what processing has been
183-
* performed.
184-
*/
185-
186-
export type MathProcessed = {
187-
findMath: boolean;
188-
compile: boolean;
189-
getMetrics: boolean;
190-
typeset: boolean;
191-
updateDocument: boolean;
192-
[name: string]: boolean;
193-
};
194187

195188
/**
196189
* Defaults used when input jax isn't specified
@@ -233,9 +226,14 @@ class DefaultOutputJax<N, T, D> extends AbstractOutputJax<N, T, D> {
233226
* @template D The Document class
234227
*/
235228
class DefaultMathList<N, T, D> extends AbstractMathList<N, T, D> {}
236-
237-
let errorFactory = new MmlFactory();
238-
229+
/**
230+
* Default for the Mathitem when one isn't specified
231+
*
232+
* @template N The HTMLElement node class
233+
* @template T The Text node class
234+
* @template D The Document class
235+
*/
236+
class DefaultMathItem<N, T, D> extends AbstractMathItem<N, T, D> {}
239237

240238
/*****************************************************************/
241239
/**
@@ -251,7 +249,9 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
251249
public static OPTIONS: OptionList = {
252250
OutputJax: null, // instance of an OutputJax for the document
253251
InputJax: null, // instance of an InputJax or an array of them
254-
MathList: DefaultMathList, // instance of a MathList to use for the document
252+
MmlFactory: null, // instance of a MmlFactory for this document
253+
MathList: DefaultMathList, // constructor for a MathList to use for the document
254+
MathItem: DefaultMathItem, // constructor for a MathItem to use for the MathList
255255
compileError: (doc: AbstractMathDocument<any, any, any>, math: MathItem<any, any, any>, err: Error) => {
256256
doc.compileError(math, err);
257257
},
@@ -261,32 +261,33 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
261261
};
262262
public static STATE = AbstractMathItem.STATE;
263263

264+
/**
265+
* A bit-field for the actions that heve been processed
266+
*/
267+
public static ProcessBits = BitFieldClass('findMath', 'compile', 'getMetrics', 'typeset', 'updateDocument');
268+
264269
public document: D;
265270
public options: OptionList;
266271
public math: MathList<N, T, D>;
267-
public processed: MathProcessed;
272+
public processed: BitField;
268273
public inputJax: InputJax<N, T, D>[];
269274
public outputJax: OutputJax<N, T, D>;
270275
public adaptor: DOMAdaptor<N, T, D>;
276+
public mmlFactory: MmlFactory;
271277

272278

273279
/**
274-
* @param {any} document The document (HTML string, parsed DOM, etc.) to be processed
275-
* @param {OptionList} options The options for this document
280+
* @param {any} document The document (HTML string, parsed DOM, etc.) to be processed
281+
* @param {DOMAdaptor} adaptor The DOM adaptor for this document
282+
* @param {OptionList} options The options for this document
276283
* @constructor
277284
*/
278285
constructor (document: any, adaptor: DOMAdaptor<N, T, D>, options: OptionList) {
279286
let CLASS = this.constructor as typeof AbstractMathDocument;
280287
this.document = document;
281288
this.options = userOptions(defaultOptions({}, CLASS.OPTIONS), options);
282289
this.math = new (this.options['MathList'] || DefaultMathList)();
283-
this.processed = {
284-
findMath: false,
285-
compile: false,
286-
typeset: false,
287-
getMetrics: false,
288-
updateDocument: false
289-
};
290+
this.processed = new AbstractMathDocument.ProcessBits();
290291
this.outputJax = this.options['OutputJax'] || new DefaultOutputJax<N, T, D>();
291292
let inputJax = this.options['InputJax'] || [new DefaultInputJax<N, T, D>()];
292293
if (!Array.isArray(inputJax)) {
@@ -299,6 +300,11 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
299300
this.adaptor = adaptor;
300301
this.outputJax.setAdaptor(adaptor);
301302
this.inputJax.map(jax => jax.setAdaptor(adaptor));
303+
//
304+
// Pass the MmlFactory to the jax
305+
//
306+
this.mmlFactory = this.options['MmlFactory'] || new MmlFactory();
307+
this.inputJax.map(jax => jax.setMmlFactory(this.mmlFactory));
302308
}
303309

304310
/**
@@ -312,15 +318,15 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
312318
* @override
313319
*/
314320
public findMath(options: OptionList = null) {
315-
this.processed.findMath = true;
321+
this.processed.set('findMath');
316322
return this;
317323
}
318324

319325
/**
320326
* @override
321327
*/
322328
public compile() {
323-
if (!this.processed.compile) {
329+
if (!this.processed.isSet('compile')) {
324330
for (const math of this.math) {
325331
try {
326332
math.compile(this);
@@ -332,7 +338,7 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
332338
math.inputData['error'] = err;
333339
}
334340
}
335-
this.processed.compile = true;
341+
this.processed.set('compile');
336342
}
337343
return this;
338344
}
@@ -344,10 +350,10 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
344350
* @param {Error} err The Error object for the error
345351
*/
346352
public compileError(math: MathItem<N, T, D>, err: Error) {
347-
math.root = errorFactory.create('math', {'data-mjx-error': err.message}, [
348-
errorFactory.create('merror', null, [
349-
errorFactory.create('mtext', null, [
350-
(errorFactory.create('text') as TextNode).setText('Math input error')
353+
math.root = this.mmlFactory.create('math', {'data-mjx-error': err.message}, [
354+
this.mmlFactory.create('merror', null, [
355+
this.mmlFactory.create('mtext', null, [
356+
(this.mmlFactory.create('text') as TextNode).setText('Math input error')
351357
])
352358
])
353359
]);
@@ -360,7 +366,7 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
360366
* @override
361367
*/
362368
public typeset() {
363-
if (!this.processed.typeset) {
369+
if (!this.processed.isSet('typeset')) {
364370
for (const math of this.math) {
365371
try {
366372
math.typeset(this);
@@ -372,7 +378,7 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
372378
math.outputData['error'] = err;
373379
}
374380
}
375-
this.processed.typeset = true;
381+
this.processed.set('typeset');
376382
}
377383
return this;
378384
}
@@ -393,9 +399,9 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
393399
* @override
394400
*/
395401
public getMetrics() {
396-
if (!this.processed.getMetrics) {
402+
if (!this.processed.isSet('getMetrics')) {
397403
this.outputJax.getMetrics(this);
398-
this.processed.getMetrics = true;
404+
this.processed.set('getMetrics');
399405
}
400406
return this;
401407
}
@@ -404,11 +410,11 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
404410
* @override
405411
*/
406412
public updateDocument() {
407-
if (!this.processed.updateDocument) {
413+
if (!this.processed.isSet('updateDocument')) {
408414
for (const math of this.math.reversed()) {
409415
math.updateDocument(this);
410416
}
411-
this.processed.updateDocument = true;
417+
this.processed.set('updateDocument');
412418
}
413419
return this;
414420
}
@@ -428,14 +434,14 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
428434
math.state(state, restore);
429435
}
430436
if (state < STATE.INSERTED) {
431-
this.processed.updateDocument = false;
437+
this.processed.clear('updateDocument');
432438
}
433439
if (state < STATE.TYPESET) {
434-
this.processed.typeset = false;
435-
this.processed.getMetrics = false;
440+
this.processed.clear('typeset');
441+
this.processed.clear('getMetrics');
436442
}
437443
if (state < STATE.COMPILED) {
438-
this.processed.compile = false;
444+
this.processed.clear('compile');
439445
}
440446
return this;
441447
}
@@ -444,9 +450,7 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
444450
* @override
445451
*/
446452
public reset() {
447-
for (const key of Object.keys(this.processed)) {
448-
this.processed[key] = false;
449-
}
453+
this.processed.reset();
450454
return this;
451455
}
452456

@@ -470,3 +474,10 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
470474
}
471475

472476
let STATE = AbstractMathDocument.STATE;
477+
478+
/**
479+
* The constructor type for a MathDocument
480+
*/
481+
export type MathDocumentConstructor<N, T, D> = {
482+
new (document: any, adaptor: DOMAdaptor<N, T, D>, options: OptionList): AbstractMathDocument<N, T, D>;
483+
};

0 commit comments

Comments
 (0)