Skip to content

Commit 77a5204

Browse files
authored
Merge pull request #109 from mathjax/maction
Add preliminary support for maction
2 parents 05bcf4e + 3085eb7 commit 77a5204

File tree

13 files changed

+371
-65
lines changed

13 files changed

+371
-65
lines changed

lib/Mml-lab.js

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
import {MathML} from "mathjax3/input/mathml.js";
22
import {CHTML} from "mathjax3/output/chtml.js";
3-
import {AbstractMathItem} from "mathjax3/core/MathItem.js";
4-
import {AbstractMathDocument} from "mathjax3/core/MathDocument.js";
3+
import {HTMLMathItem} from "mathjax3/handlers/html/HTMLMathItem.js";
4+
import {HTMLDocument} from "mathjax3/handlers/html/HTMLDocument.js";
55
import {handleRetriesFor} from "mathjax3/util/Retries.js";
66
import {browserAdaptor} from "mathjax3/adaptors/browserAdaptor.js";
77

8-
class LabMathItem extends AbstractMathItem {};
9-
class LabMathDocument extends AbstractMathDocument {};
10-
11-
let mml = new MathML();
8+
let mml = new MathML({forceReparse: true});
129
let chtml = new CHTML();
1310

14-
let doc = new LabMathDocument(document, browserAdaptor(), {InputJax: mml, OutputJax: chtml});
11+
let doc = new HTMLDocument(document, browserAdaptor(), {InputJax: mml, OutputJax: chtml});
1512
document.head.appendChild(chtml.styleSheet(doc));
1613

1714
const Lab = window.Lab = {
@@ -20,27 +17,28 @@ const Lab = window.Lab = {
2017
display: true,
2118

2219
Typeset() {
20+
this.output.innerHTML = '';
21+
let text = this.output.appendChild(document.createTextNode(''));
22+
2323
let MML = this.mml.value;
24-
let math = new LabMathItem(MML,mml);
24+
let math = new HTMLMathItem(MML,mml);
2525
math.setMetrics(16,8,16*20,100000,1);
2626
math.display = this.display;
27+
math.start = {node: text, n: 0, delim: ''};
28+
math.end = {node: text, n: 0, delim: ''};
2729
this.jax = math;
2830

2931
handleRetriesFor(function () {
3032
math.compile();
3133
math.typeset(doc);
32-
}).then(() => Lab.Update(math.typesetRoot.outerHTML))
33-
.catch(err => {console.log("Error: "+err.message); console.log(err.stack)});
34+
math.updateDocument(doc);
35+
}).catch(err => {console.log("Error: " + err.message); console.log(err.stack)});
3436
},
3537

3638
Keep() {
3739
window.location.search = "?" + encodeURIComponent(this.mml.value);
3840
},
3941

40-
Update(html) {
41-
this.output.innerHTML = html;
42-
},
43-
4442
checkKey: function (textarea, event) {
4543
if (!event) event = window.event;
4644
var code = event.which || event.keyCode;

lib/TeX-lab.js

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
import {TeX} from "mathjax3/input/tex.js";
22
import {CHTML} from "mathjax3/output/chtml.js";
3-
import {AbstractMathItem} from "mathjax3/core/MathItem.js";
4-
import {AbstractMathDocument} from "mathjax3/core/MathDocument.js";
3+
import {HTMLMathItem} from "mathjax3/handlers/html/HTMLMathItem.js";
4+
import {HTMLDocument} from "mathjax3/handlers/html/HTMLDocument.js";
55
import {handleRetriesFor} from "mathjax3/util/Retries.js";
66
import {browserAdaptor} from "mathjax3/adaptors/browserAdaptor.js";
77

8-
class LabMathItem extends AbstractMathItem {};
9-
class LabMathDocument extends AbstractMathDocument {};
10-
118
let tex = new TeX();
129
let chtml = new CHTML();
1310

14-
let doc = new LabMathDocument(document, browserAdaptor(), {InputJax: tex, OutputJax: chtml});
11+
let doc = new HTMLDocument(document, browserAdaptor(), {InputJax: tex, OutputJax: chtml});
1512
document.head.appendChild(chtml.styleSheet(doc));
1613

1714
const Lab = window.Lab = {
@@ -20,27 +17,28 @@ const Lab = window.Lab = {
2017
display: true,
2118

2219
Typeset() {
20+
this.output.innerHTML = '';
21+
let text = this.output.appendChild(document.createTextNode(''));
22+
2323
let TeX = this.tex.value;
24-
let math = new LabMathItem(TeX,tex);
24+
let math = new HTMLMathItem(TeX,tex);
2525
math.setMetrics(16,8,16*20,100000,1);
2626
math.display = this.display;
27+
math.start = {node: text, n: 0, delim: ''};
28+
math.end = {node: text, n: 0, delim: ''};
2729
this.jax = math;
2830

2931
handleRetriesFor(function () {
3032
math.compile();
3133
math.typeset(doc);
32-
}).then(() => Lab.Update(math.typesetRoot.outerHTML))
33-
.catch(err => {console.log("Error: "+err.message); console.log(err.stack)});
34+
math.updateDocument(doc);
35+
}).catch(err => {console.log("Error: " + err.message); console.log(err.stack)});
3436
},
3537

3638
Keep() {
3739
window.location.search = "?" + (this.display ? 1 : 0) + encodeURIComponent(this.tex.value);
3840
},
3941

40-
Update(html) {
41-
this.output.innerHTML = html;
42-
},
43-
4442
setDisplay(checked) {
4543
this.display = checked;
4644
this.Typeset();

mathjax3-ts/adaptors/HTMLAdaptor.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export interface MinDocument<N, T> {
3737
documentElement: N;
3838
head: N;
3939
body: N;
40+
title: string;
4041
createElement(type: string): N;
4142
createTextNode(text: string): T;
4243
querySelectorAll(selector: string): N[];

mathjax3-ts/core/MathDocument.ts

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ import {DOMAdaptor} from '../core/DOMAdaptor.js';
4444
* .compile()
4545
* .getMetrics()
4646
* .typeset()
47-
* .addEventHandlers()
4847
* .updateDocument();
4948
*
5049
* The MathDocument is the main interface for page authors to
@@ -129,13 +128,6 @@ export interface MathDocument<N, T, D> {
129128
*/
130129
typeset(): MathDocument<N, T, D>;
131130

132-
/*
133-
* Add any event handlers to the typeset math
134-
*
135-
* @return{MathDocument} The math document instance
136-
*/
137-
addEventHandlers(): MathDocument<N, T, D>;
138-
139131
/*
140132
* Updates the document to include the typeset math
141133
*
@@ -198,7 +190,6 @@ export type MathProcessed = {
198190
compile: boolean;
199191
getMetrics: boolean;
200192
typeset: boolean;
201-
addEventHandlers: boolean;
202193
updateDocument: boolean;
203194
[name: string]: boolean;
204195
};
@@ -289,7 +280,6 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
289280
compile: false,
290281
typeset: false,
291282
getMetrics: false,
292-
addEventHandlers: false,
293283
updateDocument: false
294284
};
295285
this.outputJax = this.options['OutputJax'] || new DefaultOutputJax<N, T, D>();
@@ -405,14 +395,6 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
405395
return this;
406396
}
407397

408-
/*
409-
* @override
410-
*/
411-
public addEventHandlers() {
412-
this.processed.addEventHandlers = true;
413-
return this;
414-
}
415-
416398
/*
417399
* @override
418400
*/
@@ -445,7 +427,6 @@ export abstract class AbstractMathDocument<N, T, D> implements MathDocument<N, T
445427
}
446428
if (state < STATE.TYPESET) {
447429
this.processed.typeset = false;
448-
this.processed.addEventHandlers = false;
449430
this.processed.getMetrics = false;
450431
}
451432
if (state < STATE.COMPILED) {

mathjax3-ts/core/MathItem.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,11 @@ export interface MathItem<N, T, D> {
150150
typeset(document: MathDocument<N, T, D>): void;
151151

152152
/*
153-
* Adds any needed event handlers to the typeset output
153+
* Rerenders an already rendered item and re-inserts it into the document
154+
*
155+
* @param{MathDocument} document The MathDocument in which the math resides
154156
*/
155-
addEventHandlers(): void;
157+
rerender(document: MathDocument<N, T, D>): void;
156158

157159
/*
158160
* Inserts the typeset version in place of the original form in the document
@@ -311,7 +313,11 @@ export abstract class AbstractMathItem<N, T, D> implements MathItem<N, T, D> {
311313
/*
312314
* @override
313315
*/
314-
public addEventHandlers() {}
316+
public rerender(document: MathDocument<N, T, D>) {
317+
this.state(AbstractMathItem.STATE.COMPILED);
318+
this.typeset(document);
319+
this.updateDocument(document);
320+
}
315321

316322
/*
317323
* @override

mathjax3-ts/core/MmlTree/MmlNodes/maction.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ export class MmlMaction extends AbstractMmlNode {
5454
* @return {MmlNode} The selected child node (or an mrow if none selected)
5555
*/
5656
public get selected(): MmlNode {
57-
return this.childNodes[(this.attributes.get('selection') as number) - 1] || this.factory.create('mrow');
57+
const selection = this.attributes.get('selection') as number;
58+
const i = Math.max(1, Math.min(this.childNodes.length, selection)) - 1;
59+
return this.childNodes[i] || this.factory.create('mrow');
5860
}
5961

6062
/*
@@ -85,6 +87,18 @@ export class MmlMaction extends AbstractMmlNode {
8587
return this.selected.coreMO();
8688
}
8789

90+
/*
91+
* @override
92+
*/
93+
protected verifyAttributes(options: PropertyList) {
94+
super.verifyAttributes(options);
95+
if (this.attributes.get('actiontype') !== 'toggle' &&
96+
this.attributes.getExplicit('selection') !== undefined) {
97+
const attributes = this.attributes.getAllAttributes();
98+
delete attributes.selection;
99+
}
100+
}
101+
88102
/*
89103
* Get the TeX class from the selceted node
90104
* For tooltips, set TeX classes within the tip as a separate math list
@@ -100,4 +114,16 @@ export class MmlMaction extends AbstractMmlNode {
100114
this.updateTeXclass(selected);
101115
return prev;
102116
}
117+
118+
/*
119+
* Select the next child for a toggle action
120+
*/
121+
public nextToggleSelection() {
122+
let selection = Math.max(1, (this.attributes.get('selection') as number) + 1);
123+
if (selection > this.childNodes.length) {
124+
selection = 1;
125+
}
126+
this.attributes.set('selection', selection);
127+
}
128+
103129
}

mathjax3-ts/core/OutputJax.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {userOptions, defaultOptions, OptionList} from '../util/Options.js';
2525
import {MathDocument} from './MathDocument.js';
2626
import {MathItem, Metrics} from './MathItem.js';
2727
import {DOMAdaptor} from '../core/DOMAdaptor.js';
28+
import {FunctionList} from '../util/FunctionList.js';
2829

2930
/*****************************************************************/
3031
/*
@@ -47,6 +48,11 @@ export interface OutputJax<N, T, D> {
4748
*/
4849
options: OptionList;
4950

51+
/*
52+
* Lists of post-filters to call after typesetting the math
53+
*/
54+
postFilters: FunctionList;
55+
5056
/*
5157
* The DOM adaptor for managing HTML elements
5258
*/
@@ -107,6 +113,7 @@ export abstract class AbstractOutputJax<N, T, D> implements OutputJax<N, T, D> {
107113
public static OPTIONS: OptionList = {};
108114

109115
public options: OptionList;
116+
public postFilters: FunctionList;
110117
public adaptor: DOMAdaptor<N, T, D> = null; // set by the handler
111118

112119
/*
@@ -115,6 +122,7 @@ export abstract class AbstractOutputJax<N, T, D> implements OutputJax<N, T, D> {
115122
constructor(options: OptionList = {}) {
116123
let CLASS = this.constructor as typeof AbstractOutputJax;
117124
this.options = userOptions(defaultOptions({}, CLASS.OPTIONS), options);
125+
this.postFilters = new FunctionList();
118126
}
119127

120128
/*
@@ -154,4 +162,19 @@ export abstract class AbstractOutputJax<N, T, D> implements OutputJax<N, T, D> {
154162
return null as N;
155163
}
156164

165+
/*
166+
* Execute a set of filters, passing them the MathItem and any needed data,
167+
* and return the (possibly modified) data
168+
*
169+
* @param{FunctionList} filters The list of functions to be performed
170+
* @param{MathItem} math The math item that is being processed
171+
* @param{any} data Whatever other data is needed
172+
* @return{any} The (possibly modified) data
173+
*/
174+
protected executeFilters(filters: FunctionList, math: MathItem<N, T, D>, data: any) {
175+
let args = {math: math, data: data};
176+
filters.execute(args);
177+
return args.data;
178+
}
179+
157180
}

mathjax3-ts/handlers/html/HTMLDocument.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,11 @@ export class HTMLDocument<N, T, D> extends AbstractMathDocument<N, T, D> {
183183
return this;
184184
}
185185

186+
/*
187+
* @param{N} head The document <head>
188+
* @param{string} id The id of the stylesheet to find
189+
* @param{N|null} The stylesheet with the given ID
190+
*/
186191
protected findSheet(head: N, id: string) {
187192
if (id) {
188193
for (const sheet of this.adaptor.tags(head, 'style')) {

mathjax3-ts/handlers/html/HTMLMathItem.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,6 @@ export class HTMLMathItem<N, T, D> extends AbstractMathItem<N, T, D> {
5656
super(math, jax, display, start, end);
5757
}
5858

59-
/*
60-
* Not yet implemented
61-
*
62-
* @override
63-
*/
64-
public addEventHandlers() {}
65-
6659
/*
6760
* Insert the typeset MathItem into the document at the right location
6861
* If the starting and ending nodes are the same:
@@ -82,7 +75,7 @@ export class HTMLMathItem<N, T, D> extends AbstractMathItem<N, T, D> {
8275
if (this.inputJax.processStrings) {
8376
let node = this.start.node as T;
8477
if (node === this.end.node) {
85-
if (this.end.n < this.adaptor.value(this.end.node).length) {
78+
if (this.end.n && this.end.n < this.adaptor.value(this.end.node).length) {
8679
this.adaptor.split(this.end.node, this.end.n);
8780
}
8881
if (this.start.n) {
@@ -122,18 +115,19 @@ export class HTMLMathItem<N, T, D> extends AbstractMathItem<N, T, D> {
122115
public removeFromDocument(restore: boolean = false) {
123116
if (this.state() >= STATE.TYPESET) {
124117
let node = this.start.node;
118+
let math: N | T = this.adaptor.text('');
125119
if (restore) {
126120
let text = this.start.delim + this.math + this.end.delim;
127-
let math;
128121
if (this.inputJax.processStrings) {
129122
math = this.adaptor.text(text);
130123
} else {
131124
const doc = this.adaptor.parse(text, 'text/html');
132125
math = this.adaptor.firstChild(this.adaptor.body(doc));
133126
}
134-
this.adaptor.insert(math, node);
135127
}
136-
this.adaptor.remove(node);
128+
this.adaptor.replace(math, node);
129+
this.start.node = this.end.node = math;
130+
this.start.n = this.end.n = 0;
137131
}
138132
}
139133

0 commit comments

Comments
 (0)