temml 0.10.23 → 0.10.29
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|