temml 0.10.24 → 0.10.30
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +2 -2
- 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 +117 -34
- package/dist/Temml-Fira.css +117 -34
- package/dist/Temml-Latin-Modern.css +117 -34
- package/dist/Temml-Libertinus.css +117 -34
- package/dist/Temml-Local.css +117 -34
- package/dist/Temml-STIX2.css +117 -34
- package/dist/temml.cjs +7099 -6901
- package/dist/temml.js +4694 -4510
- package/dist/temml.min.js +1 -1
- package/dist/temml.mjs +7099 -6901
- package/dist/temmlPostProcess.js +1 -3
- package/package.json +8 -5
- package/src/Parser.js +7 -4
- 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/color.js +2 -0
- package/src/functions/def.js +1 -2
- package/src/functions/delimsizing.js +14 -5
- 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 +5 -0
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.30";
|
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.30",
|
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.11.1",
|
33
|
+
"eslint": "^9.11.1",
|
32
34
|
"esm": "^3.2.25",
|
33
|
-
"
|
34
|
-
"
|
35
|
+
"globals": "^15.9.0",
|
36
|
+
"rollup": "^4.22.4",
|
37
|
+
"terser": "^5.34.0"
|
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/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/color.js
CHANGED
@@ -186,6 +186,7 @@ defineFunction({
|
|
186
186
|
type: "color",
|
187
187
|
mode: parser.mode,
|
188
188
|
color,
|
189
|
+
isTextColor: true,
|
189
190
|
body: ordargument(body)
|
190
191
|
}
|
191
192
|
},
|
@@ -218,6 +219,7 @@ defineFunction({
|
|
218
219
|
type: "color",
|
219
220
|
mode: parser.mode,
|
220
221
|
color,
|
222
|
+
isTextColor: false,
|
221
223
|
body
|
222
224
|
}
|
223
225
|
},
|
package/src/functions/def.js
CHANGED
@@ -118,10 +118,8 @@ function checkDelimiter(delim, context) {
|
|
118
118
|
if (symDelim && delimiters.includes(symDelim.text)) {
|
119
119
|
// If a character is not in the MathML operator dictionary, it will not stretch.
|
120
120
|
// Replace such characters w/characters that will stretch.
|
121
|
-
if (["/", "\u2044"].includes(symDelim.text)) { symDelim.text = "\u2215" }
|
122
121
|
if (["<", "\\lt"].includes(symDelim.text)) { symDelim.text = "⟨" }
|
123
122
|
if ([">", "\\gt"].includes(symDelim.text)) { symDelim.text = "⟩" }
|
124
|
-
if (symDelim.text === "\\backslash") { symDelim.text = "\u2216" }
|
125
123
|
return symDelim;
|
126
124
|
} else if (symDelim) {
|
127
125
|
throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim);
|
@@ -130,6 +128,9 @@ function checkDelimiter(delim, context) {
|
|
130
128
|
}
|
131
129
|
}
|
132
130
|
|
131
|
+
// / \
|
132
|
+
const needExplicitStretch = ["\u002F", "\u005C", "\\backslash", "\\vert", "|"];
|
133
|
+
|
133
134
|
defineFunction({
|
134
135
|
type: "delimsizing",
|
135
136
|
names: [
|
@@ -182,8 +183,7 @@ defineFunction({
|
|
182
183
|
// defaults.
|
183
184
|
node.setAttribute("fence", "false");
|
184
185
|
}
|
185
|
-
if (group.delim
|
186
|
-
group.delim === "|" || group.delim.indexOf("arrow") > -1) {
|
186
|
+
if (needExplicitStretch.includes(group.delim) || group.delim.indexOf("arrow") > -1) {
|
187
187
|
// We have to explicitly set stretchy to true.
|
188
188
|
node.setAttribute("stretchy", "true")
|
189
189
|
}
|
@@ -269,7 +269,7 @@ defineFunction({
|
|
269
269
|
const leftNode = new mathMLTree.MathNode("mo", [mml.makeText(group.left, group.mode)]);
|
270
270
|
leftNode.setAttribute("fence", "true")
|
271
271
|
leftNode.setAttribute("form", "prefix")
|
272
|
-
if (group.left === "\
|
272
|
+
if (group.left === "/" || group.left === "\u005C" || group.left.indexOf("arrow") > -1) {
|
273
273
|
leftNode.setAttribute("stretchy", "true")
|
274
274
|
}
|
275
275
|
inner.unshift(leftNode)
|
@@ -281,6 +281,15 @@ defineFunction({
|
|
281
281
|
if (group.right === "\u2216" || group.right.indexOf("arrow") > -1) {
|
282
282
|
rightNode.setAttribute("stretchy", "true")
|
283
283
|
}
|
284
|
+
if (group.body.length > 0) {
|
285
|
+
const lastElement = group.body[group.body.length - 1];
|
286
|
+
if (lastElement.type === "color" && !lastElement.isTextColor) {
|
287
|
+
// \color is a switch. If the last element is of type "color" then
|
288
|
+
// the user set the \color switch and left it on.
|
289
|
+
// A \right delimiter turns the switch off, but the delimiter itself gets the color.
|
290
|
+
rightNode.setAttribute("mathcolor", lastElement.color);
|
291
|
+
}
|
292
|
+
}
|
284
293
|
inner.push(rightNode)
|
285
294
|
|
286
295
|
return mml.makeRow(inner);
|
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
|
+
});
|