Skip to content

Commit 4e4ad55

Browse files
authored
Merge branch 'master' into table-support
2 parents b740a3d + 7101270 commit 4e4ad55

File tree

26 files changed

+1236
-116
lines changed

26 files changed

+1236
-116
lines changed

Mml-lab.html

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>MathJax v3 MathML lab</title>
5+
<script src="lib/traceur.min.js"></script>
6+
<script src="lib/system.js"></script>
7+
<style>
8+
#output {
9+
border: 1px solid black;
10+
padding: 10px;
11+
width: auto;
12+
min-width: 50%;
13+
display: inline-block;
14+
font-size: 200%;
15+
}
16+
#container {
17+
display: inline-block;
18+
text-align: right;
19+
}
20+
</style>
21+
</head>
22+
<body>
23+
24+
<div id="container">
25+
<textarea id="mml" cols="80" rows="15" onkeypress="Lab.checkKey(this,event)"></textarea><br>
26+
<input type="button" value="Keep" onclick="Lab.Keep()" />
27+
<input type="button" value="Typeset" onclick="Lab.Typeset()" />
28+
</div>
29+
<p>
30+
<div id="output"></div>
31+
32+
<script>
33+
System.import('Mml-lab.js').catch(function (error) {console.log(error.message)});
34+
</script>
35+
</body>
36+
</html>
37+
38+

Mml-lab.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import {MathML} from "mathjax3/input/MathML.js";
2+
import {CHTML} from "mathjax3/output/chtml.js";
3+
import {AbstractMathItem} from "mathjax3/core/MathItem.js";
4+
import {AbstractMathDocument} from "mathjax3/core/MathDocument.js";
5+
import {DOM} from "mathjax3/util/DOM.js";
6+
import {handleRetriesFor} from "mathjax3/util/Retries.js";
7+
8+
let mml = new MathML();
9+
let chtml = new CHTML();
10+
11+
let doc = new AbstractMathDocument(DOM.document,{OutputJax: chtml});
12+
13+
chtml.nodes.document = doc.document;
14+
DOM.document.head.appendChild(chtml.styleSheet(doc));
15+
16+
const Lab = DOM.window.Lab = {
17+
mml: DOM.document.getElementById('mml'),
18+
output: DOM.document.getElementById('output'),
19+
display: true,
20+
21+
Typeset() {
22+
let MML = this.mml.value;
23+
let math = new AbstractMathItem(MML,mml);
24+
math.setMetrics(16,8,1000000,100000,1);
25+
math.display = this.display;
26+
this.jax = math;
27+
28+
handleRetriesFor(function () {
29+
math.compile();
30+
math.typeset(doc);
31+
}).then(() => Lab.Update(math.typesetRoot.outerHTML))
32+
.catch(err => console.log("Error: "+err.message));
33+
},
34+
35+
Keep() {
36+
DOM.window.location.search = "?" + encodeURIComponent(this.mml.value);
37+
},
38+
39+
Update(html) {
40+
this.output.innerHTML = html;
41+
},
42+
43+
checkKey: function (textarea, event) {
44+
if (!event) event = window.event;
45+
var code = event.which || event.keyCode;
46+
if ((event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) &&
47+
(code === 13 || code === 10)) {
48+
if (event.preventDefault) event.preventDefault();
49+
event.returnValue = false;
50+
this.Typeset();
51+
}
52+
}
53+
54+
}
55+
56+
if (DOM.window.location.search !== "") {
57+
Lab.mml.value = decodeURIComponent(DOM.window.location.search.substr(1));
58+
Lab.Typeset();
59+
}
60+

TeX-lab.html

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>MathJax v3 TeX lab</title>
5+
<script src="lib/traceur.min.js"></script>
6+
<script src="lib/system.js"></script>
7+
<style>
8+
#output {
9+
border: 1px solid black;
10+
padding: 10px;
11+
width: auto;
12+
min-width: 50%;
13+
display: inline-block;
14+
font-size: 200%;
15+
}
16+
#container {
17+
display: inline-block;
18+
text-align: right;
19+
}
20+
</style>
21+
</head>
22+
<body>
23+
24+
<div id="container">
25+
<textarea id="tex" cols="80" rows="15" onkeypress="Lab.checkKey(this,event)"></textarea><br>
26+
<span style="float:left">
27+
<input type="checkbox" id="display" onchange="Lab.setDisplay(this.checked)" checked /> display mode
28+
</span>
29+
<input type="button" value="Keep" onclick="Lab.Keep()" />
30+
<input type="button" value="Typeset" onclick="Lab.Typeset()" />
31+
</div>
32+
<p>
33+
<div id="output"></div>
34+
35+
<script>
36+
System.import('TeX-lab.js').catch(function (error) {console.log(error.message)});
37+
</script>
38+
</body>
39+
</html>
40+
41+

TeX-lab.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import {TeX} from "mathjax3/input/tex.js";
2+
import {CHTML} from "mathjax3/output/chtml.js";
3+
import {AbstractMathItem} from "mathjax3/core/MathItem.js";
4+
import {AbstractMathDocument} from "mathjax3/core/MathDocument.js";
5+
import {DOM} from "mathjax3/util/DOM.js";
6+
import {handleRetriesFor} from "mathjax3/util/Retries.js";
7+
8+
let tex = new TeX();
9+
let chtml = new CHTML();
10+
11+
let doc = new AbstractMathDocument(DOM.document,{OutputJax: chtml});
12+
13+
chtml.nodes.document = doc.document;
14+
DOM.document.head.appendChild(chtml.styleSheet(doc));
15+
16+
const Lab = DOM.window.Lab = {
17+
tex: DOM.document.getElementById('tex'),
18+
output: DOM.document.getElementById('output'),
19+
display: true,
20+
21+
Typeset() {
22+
let TeX = this.tex.value;
23+
let math = new AbstractMathItem(TeX,tex);
24+
math.setMetrics(16,8,1000000,100000,1);
25+
math.display = this.display;
26+
this.jax = math;
27+
28+
handleRetriesFor(function () {
29+
math.compile();
30+
math.typeset(doc);
31+
}).then(() => Lab.Update(math.typesetRoot.outerHTML))
32+
.catch(err => {console.log("Error: "+err.message); console.log(err.stack)});
33+
},
34+
35+
Keep() {
36+
DOM.window.location.search = "?" + (this.display ? 1 : 0) + encodeURIComponent(this.tex.value);
37+
},
38+
39+
Update(html) {
40+
this.output.innerHTML = html;
41+
},
42+
43+
setDisplay(checked) {
44+
this.display = checked;
45+
this.Typeset();
46+
},
47+
48+
checkKey: function (textarea, event) {
49+
if (!event) event = window.event;
50+
var code = event.which || event.keyCode;
51+
if ((event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) &&
52+
(code === 13 || code === 10)) {
53+
if (event.preventDefault) event.preventDefault();
54+
event.returnValue = false;
55+
this.Typeset();
56+
}
57+
}
58+
59+
}
60+
61+
if (DOM.window.location.search !== "") {
62+
Lab.tex.value = decodeURIComponent(DOM.window.location.search.substr(2));
63+
Lab.display = DOM.window.location.search.substr(1,1) === '1';
64+
DOM.document.getElementById('display').checked = Lab.display;
65+
Lab.Typeset();
66+
}
67+

mathjax3-ts/core/MmlTree/MmlNode.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode {
207207
public static defaults: PropertyList = {
208208
mathbackground: INHERIT,
209209
mathcolor: INHERIT,
210+
mathsize: INHERIT, // technically only for token elements, but <mstyle mathsize="..."> should
211+
// scale all spaces, fractions, etc.
210212
dir: INHERIT
211213
};
212214
/*
@@ -500,7 +502,7 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode {
500502
display: boolean = false, level: number = 0, prime: boolean = false) {
501503
let defaults = this.attributes.getAllDefaults();
502504
for (const key of Object.keys(attributes)) {
503-
if (key in defaults) {
505+
if (defaults.hasOwnProperty(key)) {
504506
let [node, value] = attributes[key];
505507
let noinherit = (AbstractMmlNode.noInherit[node] || {})[this.kind] || {};
506508
if (!noinherit[key]) {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export class MmlMath extends AbstractMmlLayoutNode {
9090
attributes = this.addInheritedAttributes(attributes, this.attributes.getAllAttributes());
9191
display = (!!this.attributes.get('displaystyle') ||
9292
(!this.attributes.get('displaystyle') && this.attributes.get('display') === 'block'));
93+
this.attributes.setInherited('displaystyle', display);
9394
level = (this.attributes.get('scriptlevel') ||
9495
(this.constructor as typeof MmlMath).defaults['scriptlevel']) as number;
9596
super.setChildInheritedAttributes(attributes, display, level, prime);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ export class MmlMstyle extends AbstractMmlLayoutNode {
6565
level = parseInt(scriptlevel);
6666
}
6767
}
68-
let displaystyle = this.attributes.getExplicit('displaystyle') as string;
68+
let displaystyle = this.attributes.getExplicit('displaystyle') as boolean;
6969
if (displaystyle != null) {
70-
display = (displaystyle === 'true');
70+
display = (displaystyle === true);
7171
}
7272
attributes = this.addInheritedAttributes(attributes, this.attributes.getAllAttributes());
7373
this.childNodes[0].setInheritedAttributes(attributes, display, level, prime);

mathjax3-ts/output/chtml/FontData.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ export class FontData {
197197
big_op_spacing1: .111,
198198
big_op_spacing2: .167,
199199
big_op_spacing3: .2,
200-
big_op_spacing4: .45, // .6, // better spacing for under arrows and braces
200+
big_op_spacing4: .6,
201201
big_op_spacing5: .1,
202202

203203
surd_height: .075,

mathjax3-ts/output/chtml/Wrapper.ts

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ export const FONTSIZE: StringMap = {
5959
'249%': 'HG'
6060
};
6161

62+
export const SPACE: StringMap = {
63+
[LENGTHS.em(3/18)]: '1',
64+
[LENGTHS.em(4/18)]: '2',
65+
[LENGTHS.em(5/18)]: '3',
66+
};
67+
6268
/*
6369
* Needed to access node.style[id] using variable id
6470
*/
@@ -102,6 +108,8 @@ export class CHTMLWrapper extends AbstractWrapper<MmlNode, CHTMLWrapper> {
102108
'mjx-box': {display: 'inline-block'},
103109
'mjx-block': {display: 'block'},
104110
'mjx-itable': {display: 'inline-table'},
111+
'mjx-row': {display: 'table-row'},
112+
'mjx-row > *': {display: 'table-cell'},
105113

106114
//
107115
// These don't have Wrapper subclasses, so add their styles here
@@ -304,24 +312,21 @@ export class CHTMLWrapper extends AbstractWrapper<MmlNode, CHTMLWrapper> {
304312
if (this.bboxComputed) {
305313
return this.bbox;
306314
}
307-
let bbox = this.computeBBox();
308-
if (save) {
309-
this.bbox = bbox;
310-
this.bboxComputed = true;
311-
}
315+
const bbox = (save ? this.bbox : BBox.zero());
316+
this.computeBBox(bbox);
317+
this.bboxComputed = save;
312318
return bbox;
313319
}
314320

315321
/*
316-
* @return{BBox} The computed bounding box for the wrapped node
322+
* @param{BBox} bbox The bounding box to modify (either this.bbox, or an empty one)
317323
*/
318-
protected computeBBox() {
319-
const bbox = this.bbox.empty();
324+
protected computeBBox(bbox: BBox) {
325+
bbox.empty();
320326
for (const child of this.childNodes) {
321327
bbox.append(child.getBBox());
322328
}
323329
bbox.clean();
324-
return bbox;
325330
}
326331

327332
/*******************************************************************/
@@ -405,7 +410,8 @@ export class CHTMLWrapper extends AbstractWrapper<MmlNode, CHTMLWrapper> {
405410
let attributes = this.node.attributes;
406411
let scriptlevel = Math.min(attributes.get('scriptlevel') as number, 2);
407412
let fontsize = attributes.get('fontsize');
408-
let mathsize = (parent && !this.node.isToken ? parent : this).node.attributes.get('mathsize');
413+
let mathsize = (this.node.isToken || this.node.isKind('mstyle') ?
414+
attributes.get('mathsize') : attributes.getInherited('mathsize'));
409415
//
410416
// If scriptsize is non-zero, set scale based on scriptsizemultiplier
411417
//
@@ -507,15 +513,25 @@ export class CHTMLWrapper extends AbstractWrapper<MmlNode, CHTMLWrapper> {
507513
* Set the (relative) scaling factor for the node
508514
*/
509515
protected handleScale() {
510-
const scale = (Math.abs(this.bbox.rscale - 1) < .001 ? 1 : this.bbox.rscale);
511-
if (this.chtml && scale !== 1) {
516+
this.setScale(this.chtml, this.bbox.rscale);
517+
}
518+
519+
/*
520+
* @param{HTMLElement} chtml The HTML node to scale
521+
* @param{number} rscale The relatie scale to apply
522+
* @return{HTMLElement} The HTML node (for chaining)
523+
*/
524+
setScale(chtml: HTMLElement, rscale: number) {
525+
const scale = (Math.abs(rscale - 1) < .001 ? 1 : rscale);
526+
if (chtml && scale !== 1) {
512527
const size = this.percent(scale);
513528
if (FONTSIZE[size]) {
514-
this.chtml.setAttribute('size', FONTSIZE[size]);
529+
chtml.setAttribute('size', FONTSIZE[size]);
515530
} else {
516-
this.chtml.style.fontSize = size;
531+
chtml.style.fontSize = size;
517532
}
518533
}
534+
return chtml;
519535
}
520536

521537
/*
@@ -524,7 +540,12 @@ export class CHTMLWrapper extends AbstractWrapper<MmlNode, CHTMLWrapper> {
524540
*/
525541
protected handleSpace() {
526542
if (this.bbox.L) {
527-
this.chtml.setAttribute('space', (this.bbox.L * 18 - 2).toString());
543+
const space = this.em(this.bbox.L);
544+
if (SPACE[space]) {
545+
this.chtml.setAttribute('space', SPACE[space]);
546+
} else {
547+
this.chtml.style.marginLeft = space;
548+
}
528549
}
529550
}
530551

@@ -624,7 +645,7 @@ export class CHTMLWrapper extends AbstractWrapper<MmlNode, CHTMLWrapper> {
624645
public drawBBox() {
625646
const bbox = this.getBBox();
626647
const box = this.html('mjx-box', {style: {
627-
opacity: .25, 'margin-left': this.em(-bbox.w)
648+
opacity: .25, 'margin-left': this.em(-bbox.w - bbox.R)
628649
}}, [
629650
this.html('mjx-box', {style: {
630651
height: this.em(bbox.h),
@@ -640,7 +661,7 @@ export class CHTMLWrapper extends AbstractWrapper<MmlNode, CHTMLWrapper> {
640661
}})
641662
]);
642663
const node = this.chtml || this.parent.chtml;
643-
node.appendChild(box);
664+
node.parentNode.appendChild(box);
644665
node.style.backgroundColor = '#FFEE00';
645666
}
646667

0 commit comments

Comments
 (0)