temml 0.10.23 → 0.10.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/contrib/auto-render/dist/auto-render.js +4 -7
- package/contrib/auto-render/dist/auto-render.min.js +1 -1
- package/contrib/auto-render/test/auto-render.js +4 -7
- package/contrib/mhchem/mhchem.js +19 -5
- package/contrib/mhchem/mhchem.min.js +1 -1
- package/dist/Temml-Asana.css +119 -34
- package/dist/Temml-Fira.css +119 -34
- package/dist/Temml-Latin-Modern.css +119 -34
- package/dist/Temml-Libertinus.css +119 -34
- package/dist/Temml-Local.css +119 -34
- package/dist/Temml-STIX2.css +119 -34
- package/dist/temml.cjs +7180 -6904
- package/dist/temml.js +4775 -4513
- package/dist/temml.min.js +1 -1
- package/dist/temml.mjs +7180 -6904
- package/dist/temmlPostProcess.js +1 -3
- package/package.json +8 -5
- package/src/Parser.js +7 -4
- package/src/Settings.js +5 -1
- package/src/buildMathML.js +55 -32
- package/src/environments/array.js +54 -13
- package/src/environments/cd.js +1 -1
- package/src/functions/accent.js +32 -7
- package/src/functions/def.js +4 -2
- package/src/functions/enclose.js +60 -31
- package/src/functions/op.js +15 -1
- package/src/functions/supsub.js +2 -2
- package/src/functions/text.js +7 -3
- package/src/macros.js +5 -1
- package/src/postProcess.js +1 -1
- package/src/symbols.js +73 -4
- package/src/utils.js +21 -3
package/dist/temmlPostProcess.js
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
* https://mit-license.org/
|
15
15
|
*/
|
16
16
|
|
17
|
-
const version = "0.10.
|
17
|
+
const version = "0.10.29";
|
18
18
|
|
19
19
|
function postProcess(block) {
|
20
20
|
const labelMap = {};
|
@@ -65,6 +65,4 @@
|
|
65
65
|
exports.postProcess = postProcess;
|
66
66
|
exports.version = version;
|
67
67
|
|
68
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
69
|
-
|
70
68
|
}));
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "temml",
|
3
|
-
"version": "0.10.
|
3
|
+
"version": "0.10.29",
|
4
4
|
"description": "TeX to MathML conversion in JavaScript.",
|
5
5
|
"main": "dist/temml.js",
|
6
6
|
"engines": {
|
@@ -28,10 +28,13 @@
|
|
28
28
|
],
|
29
29
|
"license": "MIT",
|
30
30
|
"devDependencies": {
|
31
|
-
"eslint": "^
|
31
|
+
"@eslint/eslintrc": "^3.1.0",
|
32
|
+
"@eslint/js": "^9.9.0",
|
33
|
+
"eslint": "^9.9.0",
|
32
34
|
"esm": "^3.2.25",
|
33
|
-
"
|
34
|
-
"
|
35
|
+
"globals": "^15.9.0",
|
36
|
+
"rollup": "^4.20.0",
|
37
|
+
"terser": "^5.31.6"
|
35
38
|
},
|
36
39
|
"scripts": {
|
37
40
|
"lint": "eslint temml.js src",
|
@@ -39,7 +42,7 @@
|
|
39
42
|
"visual-test": "node utils/buildTests.js",
|
40
43
|
"test": "yarn lint && node utils/buildTests.js && yarn unit-test",
|
41
44
|
"minify": "terser test/temml.js -o site/assets/temml.min.js -c -m && terser contrib/mhchem/mhchem.js -o site/assets/mhchem.min.js -c -m",
|
42
|
-
"build": "rollup --config ./utils/rollupConfig.
|
45
|
+
"build": "rollup --config ./utils/rollupConfig.mjs && yarn minify && node utils/insertPlugins.js",
|
43
46
|
"docs": "node utils/buildDocs.js",
|
44
47
|
"dist": "yarn build && node ./utils/copyfiles.js && terser contrib/auto-render/test/auto-render.js -o contrib/auto-render/dist/auto-render.min.js -c -m"
|
45
48
|
}
|
package/src/Parser.js
CHANGED
@@ -16,6 +16,7 @@ import unicodeAccents from /*preval*/ "./unicodeAccents";
|
|
16
16
|
import unicodeSymbols from /*preval*/ "./unicodeSymbols";
|
17
17
|
|
18
18
|
const binLeftCancellers = ["bin", "op", "open", "punct", "rel"];
|
19
|
+
const sizeRegEx = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/
|
19
20
|
|
20
21
|
/**
|
21
22
|
* This file contains the parser used to parse out a TeX expression from the
|
@@ -679,7 +680,7 @@ export default class Parser {
|
|
679
680
|
res.text = "0pt"; // Enable \above{}
|
680
681
|
isBlank = true; // This is here specifically for \genfrac
|
681
682
|
}
|
682
|
-
const match =
|
683
|
+
const match = sizeRegEx.exec(res.text);
|
683
684
|
if (!match) {
|
684
685
|
throw new ParseError("Invalid size: '" + res.text + "'", res);
|
685
686
|
}
|
@@ -885,7 +886,7 @@ export default class Parser {
|
|
885
886
|
// At this point, we should have a symbol, possibly with accents.
|
886
887
|
// First expand any accented base symbol according to unicodeSymbols.
|
887
888
|
if (Object.prototype.hasOwnProperty.call(unicodeSymbols, text[0]) &&
|
888
|
-
|
889
|
+
this.mode === "math" && !symbols[this.mode][text[0]]) {
|
889
890
|
// This behavior is not strict (XeTeX-compatible) in math mode.
|
890
891
|
if (this.settings.strict && this.mode === "math") {
|
891
892
|
throw new ParseError(`Accented Unicode text character "${text[0]}" used in ` + `math mode`,
|
@@ -895,7 +896,9 @@ export default class Parser {
|
|
895
896
|
text = unicodeSymbols[text[0]] + text.slice(1);
|
896
897
|
}
|
897
898
|
// Strip off any combining characters
|
898
|
-
const match =
|
899
|
+
const match = this.mode === "math"
|
900
|
+
? combiningDiacriticalMarksEndRegex.exec(text)
|
901
|
+
: null
|
899
902
|
if (match) {
|
900
903
|
text = text.substring(0, match.index);
|
901
904
|
if (text === "i") {
|
@@ -948,7 +951,7 @@ export default class Parser {
|
|
948
951
|
};
|
949
952
|
}
|
950
953
|
symbol = s;
|
951
|
-
} else if (text.charCodeAt(0) >= 0x80) {
|
954
|
+
} else if (text.charCodeAt(0) >= 0x80 || combiningDiacriticalMarksEndRegex.exec(text)) {
|
952
955
|
// no symbol for e.g. ^
|
953
956
|
if (this.settings.strict && this.mode === "math") {
|
954
957
|
throw new ParseError(`Unicode text character "${text[0]}" used in math mode`, nucleus)
|
package/src/Settings.js
CHANGED
@@ -42,7 +42,11 @@ export default class Settings {
|
|
42
42
|
*/
|
43
43
|
isTrusted(context) {
|
44
44
|
if (context.url && !context.protocol) {
|
45
|
-
|
45
|
+
const protocol = utils.protocolFromUrl(context.url);
|
46
|
+
if (protocol == null) {
|
47
|
+
return false
|
48
|
+
}
|
49
|
+
context.protocol = protocol
|
46
50
|
}
|
47
51
|
const trust = typeof this.trust === "function" ? this.trust(context) : this.trust;
|
48
52
|
return Boolean(trust);
|
package/src/buildMathML.js
CHANGED
@@ -34,49 +34,72 @@ export const makeText = function(text, mode, style) {
|
|
34
34
|
return new mathMLTree.TextNode(text);
|
35
35
|
};
|
36
36
|
|
37
|
+
const copyChar = (newRow, child) => {
|
38
|
+
if (newRow.children.length === 0 ||
|
39
|
+
newRow.children[newRow.children.length - 1].type !== "mtext") {
|
40
|
+
const mtext = new mathMLTree.MathNode(
|
41
|
+
"mtext",
|
42
|
+
[new mathMLTree.TextNode(child.children[0].text)]
|
43
|
+
)
|
44
|
+
newRow.children.push(mtext)
|
45
|
+
} else {
|
46
|
+
newRow.children[newRow.children.length - 1].children[0].text += child.children[0].text
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
37
50
|
export const consolidateText = mrow => {
|
38
51
|
// If possible, consolidate adjacent <mtext> elements into a single element.
|
39
52
|
if (mrow.type !== "mrow" && mrow.type !== "mstyle") { return mrow }
|
40
53
|
if (mrow.children.length === 0) { return mrow } // empty group, e.g., \text{}
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
"mtext"
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
54
|
+
const newRow = new mathMLTree.MathNode("mrow")
|
55
|
+
for (let i = 0; i < mrow.children.length; i++) {
|
56
|
+
const child = mrow.children[i];
|
57
|
+
if (child.type === "mtext" && Object.keys(child.attributes).length === 0) {
|
58
|
+
copyChar(newRow, child)
|
59
|
+
} else if (child.type === "mrow") {
|
60
|
+
// We'll also check the children of an mrow. One level only. No recursion.
|
61
|
+
let canConsolidate = true
|
62
|
+
for (let j = 0; j < child.children.length; j++) {
|
63
|
+
const grandChild = child.children[j];
|
64
|
+
if (grandChild.type !== "mtext" || Object.keys(child.attributes).length !== 0) {
|
65
|
+
canConsolidate = false
|
66
|
+
break
|
67
|
+
}
|
68
|
+
}
|
69
|
+
if (canConsolidate) {
|
70
|
+
for (let j = 0; j < child.children.length; j++) {
|
71
|
+
const grandChild = child.children[j];
|
72
|
+
copyChar(newRow, grandChild)
|
59
73
|
}
|
74
|
+
} else {
|
75
|
+
newRow.children.push(child)
|
60
76
|
}
|
61
|
-
} else if (localVariant !== variant || mrow.children[i].type !== "mtext") {
|
62
|
-
return mrow
|
63
77
|
} else {
|
64
|
-
|
78
|
+
newRow.children.push(child)
|
65
79
|
}
|
66
80
|
}
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
81
|
+
for (let i = 0; i < newRow.children.length; i++) {
|
82
|
+
if (newRow.children[i].type === "mtext") {
|
83
|
+
const mtext = newRow.children[i];
|
84
|
+
// Firefox does not render a space at either end of an <mtext> string.
|
85
|
+
// To get proper rendering, we replace leading or trailing spaces with no-break spaces.
|
86
|
+
if (mtext.children[0].text.charAt(0) === " ") {
|
87
|
+
mtext.children[0].text = "\u00a0" + mtext.children[0].text.slice(1)
|
88
|
+
}
|
89
|
+
const L = mtext.children[0].text.length
|
90
|
+
if (L > 0 && mtext.children[0].text.charAt(L - 1) === " ") {
|
91
|
+
mtext.children[0].text = mtext.children[0].text.slice(0, -1) + "\u00a0"
|
92
|
+
}
|
93
|
+
for (const [key, value] of Object.entries(mrow.attributes)) {
|
94
|
+
mtext.attributes[key] = value
|
95
|
+
}
|
96
|
+
}
|
75
97
|
}
|
76
|
-
|
77
|
-
|
98
|
+
if (newRow.children.length === 1 && newRow.children[0].type === "mtext") {
|
99
|
+
return newRow.children[0]; // A consolidated <mtext>
|
100
|
+
} else {
|
101
|
+
return newRow
|
78
102
|
}
|
79
|
-
return mtext
|
80
103
|
}
|
81
104
|
|
82
105
|
const numberRegEx = /^[0-9]$/
|
@@ -7,7 +7,8 @@ import { StyleLevel } from "../constants"
|
|
7
7
|
import ParseError from "../ParseError";
|
8
8
|
import { assertNodeType, assertSymbolNodeType } from "../parseNode";
|
9
9
|
import { checkSymbolNodeType } from "../parseNode";
|
10
|
-
|
10
|
+
import { stringFromArg } from "../macros"
|
11
|
+
import { calculateSize } from "../units"
|
11
12
|
import * as mml from "../buildMathML";
|
12
13
|
|
13
14
|
// Helper functions
|
@@ -38,6 +39,24 @@ const validateAmsEnvironmentContext = context => {
|
|
38
39
|
}
|
39
40
|
}
|
40
41
|
|
42
|
+
const sizeRegEx = /([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/
|
43
|
+
const arrayGaps = macros => {
|
44
|
+
let arraystretch = macros.get("\\arraystretch")
|
45
|
+
if (typeof arraystretch !== "string") {
|
46
|
+
arraystretch = stringFromArg(arraystretch.tokens)
|
47
|
+
}
|
48
|
+
arraystretch = isNaN(arraystretch) ? null : Number(arraystretch)
|
49
|
+
let arraycolsepStr = macros.get("\\arraycolsep")
|
50
|
+
if (typeof arraycolsepStr !== "string") {
|
51
|
+
arraycolsepStr = stringFromArg(arraycolsepStr.tokens)
|
52
|
+
}
|
53
|
+
const match = sizeRegEx.exec(arraycolsepStr)
|
54
|
+
const arraycolsep = match
|
55
|
+
? { number: +(match[1] + match[2]), unit: match[3] }
|
56
|
+
: null
|
57
|
+
return [arraystretch, arraycolsep]
|
58
|
+
}
|
59
|
+
|
41
60
|
const getTag = (group, style, rowNum) => {
|
42
61
|
let tag
|
43
62
|
const tagContents = group.tags.shift()
|
@@ -76,12 +95,14 @@ function parseArray(
|
|
76
95
|
{
|
77
96
|
cols, // [{ type: string , align: l|c|r|null }]
|
78
97
|
envClasses, // align(ed|at|edat) | array | cases | cd | small | multline
|
79
|
-
addEqnNum,
|
80
|
-
singleRow,
|
98
|
+
addEqnNum, // boolean
|
99
|
+
singleRow, // boolean
|
81
100
|
emptySingleRow, // boolean
|
82
|
-
maxNumCols,
|
83
|
-
leqno
|
84
|
-
|
101
|
+
maxNumCols, // number
|
102
|
+
leqno, // boolean
|
103
|
+
arraystretch, // number | null
|
104
|
+
arraycolsep // size value | null
|
105
|
+
},
|
85
106
|
scriptLevel
|
86
107
|
) {
|
87
108
|
parser.gullet.beginGroup();
|
@@ -111,7 +132,6 @@ function parseArray(
|
|
111
132
|
// Test for \hline at the top of the array.
|
112
133
|
hLinesBeforeRow.push(getHLines(parser));
|
113
134
|
|
114
|
-
// eslint-disable-next-line no-constant-condition
|
115
135
|
while (true) {
|
116
136
|
// Parse each cell in its own group (namespace)
|
117
137
|
let cell = parser.parseExpression(false, singleRow ? "\\end" : "\\\\");
|
@@ -211,7 +231,9 @@ function parseArray(
|
|
211
231
|
addEqnNum,
|
212
232
|
scriptLevel,
|
213
233
|
tags,
|
214
|
-
leqno
|
234
|
+
leqno,
|
235
|
+
arraystretch,
|
236
|
+
arraycolsep
|
215
237
|
};
|
216
238
|
}
|
217
239
|
|
@@ -301,12 +323,18 @@ const mathmlBuilder = function(group, style) {
|
|
301
323
|
}
|
302
324
|
|
303
325
|
if (group.envClasses.length > 0) {
|
304
|
-
|
326
|
+
let pad = group.envClasses.includes("jot")
|
305
327
|
? "0.7" // 0.5ex + 0.09em top & bot padding
|
306
328
|
: group.envClasses.includes("small")
|
307
329
|
? "0.35"
|
308
330
|
: "0.5" // 0.5ex default top & bot padding
|
309
|
-
|
331
|
+
if (group.arraystretch && group.arraystretch !== 1) {
|
332
|
+
// In LaTeX, \arraystretch is a factor applied to a 12pt strut height.
|
333
|
+
// It defines a baseline to baseline distance.
|
334
|
+
// Here, we do an approximation of that approach.
|
335
|
+
pad = String(1.4 * group.arraystretch - 0.8)
|
336
|
+
}
|
337
|
+
let sidePadding = group.envClasses.includes("abut")
|
310
338
|
? "0"
|
311
339
|
: group.envClasses.includes("cases")
|
312
340
|
? "0"
|
@@ -315,6 +343,12 @@ const mathmlBuilder = function(group, style) {
|
|
315
343
|
: group.envClasses.includes("cd")
|
316
344
|
? "0.25"
|
317
345
|
: "0.4" // default side padding
|
346
|
+
let sidePadUnit = "em"
|
347
|
+
if (group.arraycolsep) {
|
348
|
+
const arraySidePad = calculateSize(group.arraycolsep, style)
|
349
|
+
sidePadding = arraySidePad.number
|
350
|
+
sidePadUnit = arraySidePad.unit
|
351
|
+
}
|
318
352
|
|
319
353
|
const numCols = tbl.length === 0 ? 0 : tbl[0].children.length
|
320
354
|
|
@@ -333,7 +367,8 @@ const mathmlBuilder = function(group, style) {
|
|
333
367
|
// Padding
|
334
368
|
for (let i = 0; i < tbl.length; i++) {
|
335
369
|
for (let j = 0; j < tbl[i].children.length; j++) {
|
336
|
-
tbl[i].children[j].style.padding = `${pad}ex ${sidePad(j, 1)}
|
370
|
+
tbl[i].children[j].style.padding = `${pad}ex ${sidePad(j, 1)}${sidePadUnit}`
|
371
|
+
+ ` ${pad}ex ${sidePad(j, 0)}${sidePadUnit}`
|
337
372
|
}
|
338
373
|
}
|
339
374
|
|
@@ -587,10 +622,13 @@ defineEnvironment({
|
|
587
622
|
}
|
588
623
|
throw new ParseError("Unknown column alignment: " + ca, nde);
|
589
624
|
});
|
625
|
+
const [arraystretch, arraycolsep] = arrayGaps(context.parser.gullet.macros)
|
590
626
|
const res = {
|
591
627
|
cols,
|
592
628
|
envClasses: ["array"],
|
593
|
-
maxNumCols: cols.length
|
629
|
+
maxNumCols: cols.length,
|
630
|
+
arraystretch,
|
631
|
+
arraycolsep
|
594
632
|
};
|
595
633
|
return parseArray(context.parser, res, dCellStyle(context.envName));
|
596
634
|
},
|
@@ -656,6 +694,7 @@ defineEnvironment({
|
|
656
694
|
}
|
657
695
|
const res = parseArray(context.parser, payload, "text")
|
658
696
|
res.cols = new Array(res.body[0].length).fill({ type: "align", align: colAlign })
|
697
|
+
const [arraystretch, arraycolsep] = arrayGaps(context.parser.gullet.macros)
|
659
698
|
return delimiters
|
660
699
|
? {
|
661
700
|
type: "leftright",
|
@@ -663,7 +702,9 @@ defineEnvironment({
|
|
663
702
|
body: [res],
|
664
703
|
left: delimiters[0],
|
665
704
|
right: delimiters[1],
|
666
|
-
rightColor: undefined // \right uninfluenced by \color in array
|
705
|
+
rightColor: undefined, // \right uninfluenced by \color in array
|
706
|
+
arraystretch,
|
707
|
+
arraycolsep
|
667
708
|
}
|
668
709
|
: res;
|
669
710
|
},
|
package/src/environments/cd.js
CHANGED
@@ -71,7 +71,7 @@ export function parseCD(parser) {
|
|
71
71
|
parser.gullet.beginGroup();
|
72
72
|
parser.gullet.macros.set("\\cr", "\\\\\\relax");
|
73
73
|
parser.gullet.beginGroup();
|
74
|
-
while (true) {
|
74
|
+
while (true) {
|
75
75
|
// Get the parse nodes for the next row.
|
76
76
|
parsedRows.push(parser.parseExpression(false, "\\\\"));
|
77
77
|
parser.gullet.endGroup();
|
package/src/functions/accent.js
CHANGED
@@ -71,6 +71,20 @@ const needWebkitShift = new Set([
|
|
71
71
|
"\\'", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v"
|
72
72
|
])
|
73
73
|
|
74
|
+
const combiningChar = {
|
75
|
+
"\\`": "\u0300",
|
76
|
+
"\\'": "\u0301",
|
77
|
+
"\\^": "\u0302",
|
78
|
+
"\\~": "\u0303",
|
79
|
+
"\\=": "\u0304",
|
80
|
+
"\\u": "\u0306",
|
81
|
+
"\\.": "\u0307",
|
82
|
+
'\\"': "\u0308",
|
83
|
+
"\\r": "\u030A",
|
84
|
+
"\\H": "\u030B",
|
85
|
+
"\\v": "\u030C"
|
86
|
+
}
|
87
|
+
|
74
88
|
// Accents
|
75
89
|
defineFunction({
|
76
90
|
type: "accent",
|
@@ -140,13 +154,24 @@ defineFunction({
|
|
140
154
|
console.log(`Temml parse error: Command ${context.funcName} is invalid in math mode.`)
|
141
155
|
}
|
142
156
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
157
|
+
if (mode === "text" && base.text && base.text.length === 1
|
158
|
+
&& context.funcName in combiningChar && smalls.indexOf(base.text) > -1) {
|
159
|
+
// Return a combining accent character
|
160
|
+
return {
|
161
|
+
type: "textord",
|
162
|
+
mode: "text",
|
163
|
+
text: base.text + combiningChar[context.funcName]
|
164
|
+
}
|
165
|
+
} else {
|
166
|
+
// Build up the accent
|
167
|
+
return {
|
168
|
+
type: "accent",
|
169
|
+
mode: mode,
|
170
|
+
label: context.funcName,
|
171
|
+
isStretchy: false,
|
172
|
+
base: base
|
173
|
+
}
|
174
|
+
}
|
150
175
|
},
|
151
176
|
mathmlBuilder
|
152
177
|
});
|
package/src/functions/def.js
CHANGED
@@ -141,6 +141,9 @@ defineFunction({
|
|
141
141
|
|
142
142
|
if (funcName === "\\edef" || funcName === "\\xdef") {
|
143
143
|
tokens = parser.gullet.expandTokens(tokens);
|
144
|
+
if (tokens.length > parser.gullet.settings.maxExpand) {
|
145
|
+
throw new ParseError("Too many expansions in an " + funcName);
|
146
|
+
}
|
144
147
|
tokens.reverse(); // to fit in with stack order
|
145
148
|
}
|
146
149
|
// Final arg is the expansion of the macro
|
@@ -249,8 +252,7 @@ defineFunction({
|
|
249
252
|
|
250
253
|
parser.gullet.macros.set(
|
251
254
|
name,
|
252
|
-
{ tokens, numArgs }
|
253
|
-
!parser.settings.strict
|
255
|
+
{ tokens, numArgs }
|
254
256
|
)
|
255
257
|
|
256
258
|
return { type: "internal", mode: parser.mode };
|
package/src/functions/enclose.js
CHANGED
@@ -22,52 +22,62 @@ const mathmlBuilder = (group, style) => {
|
|
22
22
|
padding()
|
23
23
|
])
|
24
24
|
} else {
|
25
|
-
node = new mathMLTree.MathNode("
|
25
|
+
node = new mathMLTree.MathNode("menclose", [mml.buildGroup(group.body, style)])
|
26
26
|
}
|
27
27
|
switch (group.label) {
|
28
28
|
case "\\overline":
|
29
|
-
node.
|
30
|
-
node.
|
29
|
+
node.setAttribute("notation", "top") // for Firefox & WebKit
|
30
|
+
node.classes.push("tml-overline") // for Chromium
|
31
31
|
break
|
32
32
|
case "\\underline":
|
33
|
-
node.
|
34
|
-
node.
|
33
|
+
node.setAttribute("notation", "bottom")
|
34
|
+
node.classes.push("tml-underline")
|
35
35
|
break
|
36
36
|
case "\\cancel":
|
37
|
-
|
38
|
-
|
39
|
-
node.classes.push("tml-cancel")
|
37
|
+
node.setAttribute("notation", "updiagonalstrike")
|
38
|
+
node.children.push(new mathMLTree.MathNode("mrow", [], ["tml-cancel", "upstrike"]))
|
40
39
|
break
|
41
40
|
case "\\bcancel":
|
42
|
-
node.
|
41
|
+
node.setAttribute("notation", "downdiagonalstrike")
|
42
|
+
node.children.push(new mathMLTree.MathNode("mrow", [], ["tml-cancel", "downstrike"]))
|
43
|
+
break
|
44
|
+
case "\\sout":
|
45
|
+
node.setAttribute("notation", "horizontalstrike")
|
46
|
+
node.children.push(new mathMLTree.MathNode("mrow", [], ["tml-cancel", "sout"]))
|
47
|
+
break
|
48
|
+
case "\\xcancel":
|
49
|
+
node.setAttribute("notation", "updiagonalstrike downdiagonalstrike")
|
50
|
+
node.classes.push("tml-xcancel")
|
43
51
|
break
|
44
|
-
/*
|
45
52
|
case "\\longdiv":
|
46
|
-
node.setAttribute("notation", "longdiv")
|
53
|
+
node.setAttribute("notation", "longdiv")
|
54
|
+
node.classes.push("longdiv-top")
|
55
|
+
node.children.push(new mathMLTree.MathNode("mrow", [], ["longdiv-arc"]))
|
47
56
|
break
|
48
57
|
case "\\phase":
|
49
|
-
node.setAttribute("notation", "phasorangle")
|
50
|
-
|
51
|
-
|
52
|
-
node.style.padding = "0.03889em 0.03889em 0 0.03889em"
|
53
|
-
node.style.borderTop = "0.049em solid"
|
54
|
-
node.style.borderRight = "0.049em solid"
|
55
|
-
node.style.marginRight = "0.03889em"
|
58
|
+
node.setAttribute("notation", "phasorangle")
|
59
|
+
node.classes.push("phasor-bottom")
|
60
|
+
node.children.push(new mathMLTree.MathNode("mrow", [], ["phasor-angle"]))
|
56
61
|
break
|
57
|
-
case "\\
|
58
|
-
node.
|
59
|
-
node.
|
60
|
-
node.
|
61
|
-
|
62
|
+
case "\\textcircled":
|
63
|
+
node.setAttribute("notation", "circle")
|
64
|
+
node.classes.push("circle-pad")
|
65
|
+
node.children.push(new mathMLTree.MathNode("mrow", [], ["textcircle"]))
|
66
|
+
break
|
67
|
+
case "\\angl":
|
68
|
+
node.setAttribute("notation", "actuarial")
|
69
|
+
node.classes.push("actuarial")
|
62
70
|
break
|
63
71
|
case "\\boxed":
|
64
72
|
// \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} from amsmath.sty
|
65
|
-
node.
|
73
|
+
node.setAttribute("notation", "box")
|
74
|
+
node.classes.push("tml-box")
|
66
75
|
node.setAttribute("scriptlevel", "0")
|
67
76
|
node.setAttribute("displaystyle", "true")
|
68
77
|
break
|
69
78
|
case "\\fbox":
|
70
|
-
node.
|
79
|
+
node.setAttribute("notation", "box")
|
80
|
+
node.classes.push("tml-fbox")
|
71
81
|
break
|
72
82
|
case "\\fcolorbox":
|
73
83
|
case "\\colorbox": {
|
@@ -80,14 +90,11 @@ const mathmlBuilder = (group, style) => {
|
|
80
90
|
const style = { padding: "3pt 0 3pt 0" }
|
81
91
|
|
82
92
|
if (group.label === "\\fcolorbox") {
|
83
|
-
style.border = "0.
|
93
|
+
style.border = "0.0667em solid " + String(group.borderColor)
|
84
94
|
}
|
85
95
|
node.style = style
|
86
96
|
break
|
87
97
|
}
|
88
|
-
case "\\xcancel":
|
89
|
-
node.classes.push("tml-xcancel")
|
90
|
-
break
|
91
98
|
}
|
92
99
|
if (group.backgroundColor) {
|
93
100
|
node.setAttribute("mathbackground", group.backgroundColor);
|
@@ -180,8 +187,8 @@ defineFunction({
|
|
180
187
|
|
181
188
|
defineFunction({
|
182
189
|
type: "enclose",
|
183
|
-
names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline",
|
184
|
-
|
190
|
+
names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline",
|
191
|
+
"\\boxed", "\\longdiv", "\\phase"],
|
185
192
|
props: {
|
186
193
|
numArgs: 1
|
187
194
|
},
|
@@ -215,3 +222,25 @@ defineFunction({
|
|
215
222
|
},
|
216
223
|
mathmlBuilder
|
217
224
|
});
|
225
|
+
|
226
|
+
|
227
|
+
defineFunction({
|
228
|
+
type: "enclose",
|
229
|
+
names: ["\\textcircled"],
|
230
|
+
props: {
|
231
|
+
numArgs: 1,
|
232
|
+
argTypes: ["text"],
|
233
|
+
allowedInArgument: true,
|
234
|
+
allowedInText: true
|
235
|
+
},
|
236
|
+
handler({ parser, funcName }, args) {
|
237
|
+
const body = args[0];
|
238
|
+
return {
|
239
|
+
type: "enclose",
|
240
|
+
mode: parser.mode,
|
241
|
+
label: funcName,
|
242
|
+
body
|
243
|
+
};
|
244
|
+
},
|
245
|
+
mathmlBuilder
|
246
|
+
});
|
package/src/functions/op.js
CHANGED
@@ -12,7 +12,7 @@ const ordAtomTypes = ["textord", "mathord", "atom"]
|
|
12
12
|
const noSuccessor = ["\\smallint"];
|
13
13
|
|
14
14
|
// Math operators (e.g. \sin) need a space between these types and themselves:
|
15
|
-
export const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright"];
|
15
|
+
export const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright", "font"];
|
16
16
|
|
17
17
|
// NOTE: Unlike most `builders`s, this one handles not only "op", but also
|
18
18
|
// "supsub" since some of them (like \int) can affect super/subscripting.
|
@@ -32,6 +32,13 @@ const mathmlBuilder = (group, style) => {
|
|
32
32
|
node = new mathMLTree.MathNode("mo", [mml.makeText(group.name, group.mode)]);
|
33
33
|
if (noSuccessor.includes(group.name)) {
|
34
34
|
node.setAttribute("largeop", "false")
|
35
|
+
} else if (group.limits) {
|
36
|
+
// This is a workaround for a MathML/Chromium bug.
|
37
|
+
// This is being applied to singleCharBigOps, which are not really stretchy.
|
38
|
+
// But by setting the stretchy attribute, Chromium will vertically center
|
39
|
+
// big ops around the math axis. This is needed since STIX TWO does not do so.
|
40
|
+
// TODO: Remove this hack when MathML & Chromium fix their problem.
|
41
|
+
node.setAttribute("stretchy", "true")
|
35
42
|
} else {
|
36
43
|
node.setAttribute("movablelimits", "false")
|
37
44
|
}
|
@@ -81,6 +88,9 @@ const singleCharBigOps = {
|
|
81
88
|
"\u2a04": "\\biguplus",
|
82
89
|
"\u2a05": "\\bigsqcap",
|
83
90
|
"\u2a06": "\\bigsqcup",
|
91
|
+
"\u2a03": "\\bigcupdot",
|
92
|
+
"\u2a07": "\\bigdoublevee",
|
93
|
+
"\u2a08": "\\bigdoublewedge",
|
84
94
|
"\u2a09": "\\bigtimes"
|
85
95
|
};
|
86
96
|
|
@@ -91,8 +101,12 @@ defineFunction({
|
|
91
101
|
"\\bigvee",
|
92
102
|
"\\bigwedge",
|
93
103
|
"\\biguplus",
|
104
|
+
"\\bigcupplus",
|
105
|
+
"\\bigcupdot",
|
94
106
|
"\\bigcap",
|
95
107
|
"\\bigcup",
|
108
|
+
"\\bigdoublevee",
|
109
|
+
"\\bigdoublewedge",
|
96
110
|
"\\intop",
|
97
111
|
"\\prod",
|
98
112
|
"\\sum",
|
package/src/functions/supsub.js
CHANGED
@@ -55,9 +55,9 @@ defineFunctionBuilders({
|
|
55
55
|
if (group.sup) {
|
56
56
|
const sup = mml.buildGroup(group.sup, childStyle)
|
57
57
|
const testNode = sup.type === "mrow" ? sup.children[0] : sup
|
58
|
-
if ((testNode.type === "mo" && testNode.classes.includes("tml-prime"))
|
58
|
+
if ((testNode && testNode.type === "mo" && testNode.classes.includes("tml-prime"))
|
59
59
|
&& group.base && group.base.text && group.base.text === "f") {
|
60
|
-
// Chromium does not address italic correction on prime.
|
60
|
+
// Chromium does not address italic correction on prime. Prevent f′ from overlapping.
|
61
61
|
testNode.classes.push("prime-pad")
|
62
62
|
}
|
63
63
|
children.push(sup)
|