temml 0.10.32 → 0.10.34
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/dist/Temml-Asana.css +16 -1
- package/dist/Temml-Fira.css +16 -1
- package/dist/Temml-Latin-Modern.css +16 -1
- package/dist/Temml-Libertinus.css +16 -1
- package/dist/Temml-Local.css +16 -1
- package/dist/Temml-STIX2.css +16 -1
- package/dist/temml.cjs +473 -283
- package/dist/temml.js +473 -283
- package/dist/temml.min.js +1 -1
- package/dist/temml.mjs +473 -283
- package/dist/temmlPostProcess.js +39 -25
- package/package.json +1 -1
- package/src/Style.js +5 -3
- package/src/buildMathML.js +104 -62
- package/src/domTree.js +34 -0
- package/src/environments/array.js +119 -82
- package/src/environments/cd.js +17 -10
- package/src/functions/arrow.js +11 -3
- package/src/functions/def.js +7 -4
- package/src/functions/delimsizing.js +1 -0
- package/src/functions/font.js +1 -0
- package/src/functions/genfrac.js +13 -4
- package/src/functions/href.js +4 -6
- package/src/functions/label.js +1 -1
- package/src/functions/op.js +0 -7
- package/src/functions/ref.js +3 -5
- package/src/functions/rule.js +2 -0
- package/src/functions/supsub.js +12 -3
- package/src/functions/vcenter.js +30 -0
- package/src/functions.js +1 -0
- package/src/macros.js +4 -2
- package/src/mathMLTree.js +5 -0
- package/src/postProcess.js +39 -25
- package/src/symbols.js +3 -3
- package/src/variant.js +2 -0
package/dist/temml.mjs
CHANGED
@@ -499,6 +499,40 @@ let TextNode$1 = class TextNode {
|
|
499
499
|
}
|
500
500
|
};
|
501
501
|
|
502
|
+
// Create an <a href="…"> node.
|
503
|
+
class AnchorNode {
|
504
|
+
constructor(href, classes, children) {
|
505
|
+
this.href = href;
|
506
|
+
this.classes = classes;
|
507
|
+
this.children = children || [];
|
508
|
+
}
|
509
|
+
|
510
|
+
toNode() {
|
511
|
+
const node = document.createElement("a");
|
512
|
+
node.setAttribute("href", this.href);
|
513
|
+
if (this.classes.length > 0) {
|
514
|
+
node.className = createClass(this.classes);
|
515
|
+
}
|
516
|
+
for (let i = 0; i < this.children.length; i++) {
|
517
|
+
node.appendChild(this.children[i].toNode());
|
518
|
+
}
|
519
|
+
return node
|
520
|
+
}
|
521
|
+
|
522
|
+
toMarkup() {
|
523
|
+
let markup = `<a href='${utils.escape(this.href)}'`;
|
524
|
+
if (this.classes.length > 0) {
|
525
|
+
markup += ` class="${utils.escape(createClass(this.classes))}"`;
|
526
|
+
}
|
527
|
+
markup += ">";
|
528
|
+
for (let i = 0; i < this.children.length; i++) {
|
529
|
+
markup += this.children[i].toMarkup();
|
530
|
+
}
|
531
|
+
markup += "</a>";
|
532
|
+
return markup
|
533
|
+
}
|
534
|
+
}
|
535
|
+
|
502
536
|
/*
|
503
537
|
* This node represents an image embed (<img>) element.
|
504
538
|
*/
|
@@ -573,6 +607,7 @@ class MathNode {
|
|
573
607
|
this.children = children || [];
|
574
608
|
this.classes = classes || [];
|
575
609
|
this.style = style || {}; // Used for <mstyle> elements
|
610
|
+
this.label = "";
|
576
611
|
}
|
577
612
|
|
578
613
|
/**
|
@@ -590,6 +625,10 @@ class MathNode {
|
|
590
625
|
return this.attributes[name];
|
591
626
|
}
|
592
627
|
|
628
|
+
setLabel(value) {
|
629
|
+
this.label = value;
|
630
|
+
}
|
631
|
+
|
593
632
|
/**
|
594
633
|
* Converts the math node into a MathML-namespaced DOM element.
|
595
634
|
*/
|
@@ -1506,7 +1545,7 @@ defineSymbol(math, mathord, "\u03db", "\\stigma", true);
|
|
1506
1545
|
defineSymbol(math, mathord, "\u2aeb", "\\Bot");
|
1507
1546
|
defineSymbol(math, bin, "\u2217", "\u2217", true);
|
1508
1547
|
defineSymbol(math, bin, "+", "+");
|
1509
|
-
defineSymbol(math, bin, "
|
1548
|
+
defineSymbol(math, bin, "\u2217", "*");
|
1510
1549
|
defineSymbol(math, bin, "\u2044", "/", true);
|
1511
1550
|
defineSymbol(math, bin, "\u2044", "\u2044");
|
1512
1551
|
defineSymbol(math, bin, "\u2212", "-", true);
|
@@ -1528,7 +1567,7 @@ defineSymbol(math, open, "\u27e8", "\\langle", true);
|
|
1528
1567
|
defineSymbol(math, open, "\u27ea", "\\lAngle", true);
|
1529
1568
|
defineSymbol(math, open, "\u2989", "\\llangle", true);
|
1530
1569
|
defineSymbol(math, open, "|", "\\lvert");
|
1531
|
-
defineSymbol(math, open, "\u2016", "\\lVert");
|
1570
|
+
defineSymbol(math, open, "\u2016", "\\lVert", true);
|
1532
1571
|
defineSymbol(math, textord, "!", "\\oc"); // cmll package
|
1533
1572
|
defineSymbol(math, textord, "?", "\\wn");
|
1534
1573
|
defineSymbol(math, textord, "\u2193", "\\shpos");
|
@@ -1692,7 +1731,7 @@ defineSymbol(math, inner, "\u22f0", "\\iddots", true);
|
|
1692
1731
|
defineSymbol(math, inner, "\u22ef", "\\@cdots", true);
|
1693
1732
|
defineSymbol(math, inner, "\u22f1", "\\ddots", true);
|
1694
1733
|
defineSymbol(math, textord, "\u22ee", "\\varvdots"); // \vdots is a macro
|
1695
|
-
defineSymbol(text, textord, "\u22ee", "\\
|
1734
|
+
defineSymbol(text, textord, "\u22ee", "\\varvdots");
|
1696
1735
|
defineSymbol(math, accent, "\u02ca", "\\acute");
|
1697
1736
|
defineSymbol(math, accent, "\u0060", "\\grave");
|
1698
1737
|
defineSymbol(math, accent, "\u00a8", "\\ddot");
|
@@ -2145,61 +2184,6 @@ const consolidateText = mrow => {
|
|
2145
2184
|
}
|
2146
2185
|
};
|
2147
2186
|
|
2148
|
-
const numberRegEx$1 = /^[0-9]$/;
|
2149
|
-
const isDotOrComma = (node, followingNode) => {
|
2150
|
-
return ((node.type === "textord" && node.text === ".") ||
|
2151
|
-
(node.type === "atom" && node.text === ",")) &&
|
2152
|
-
// Don't consolidate if there is a space after the comma.
|
2153
|
-
node.loc && followingNode.loc && node.loc.end === followingNode.loc.start
|
2154
|
-
};
|
2155
|
-
const consolidateNumbers = expression => {
|
2156
|
-
// Consolidate adjacent numbers. We want to return <mn>1,506.3</mn>,
|
2157
|
-
// not <mn>1</mn><mo>,</mo><mn>5</mn><mn>0</mn><mn>6</mn><mi>.</mi><mn>3</mn>
|
2158
|
-
if (expression.length < 2) { return }
|
2159
|
-
const nums = [];
|
2160
|
-
let inNum = false;
|
2161
|
-
// Find adjacent numerals
|
2162
|
-
for (let i = 0; i < expression.length; i++) {
|
2163
|
-
const node = expression[i];
|
2164
|
-
if (node.type === "textord" && numberRegEx$1.test(node.text)) {
|
2165
|
-
if (!inNum) { nums.push({ start: i }); }
|
2166
|
-
inNum = true;
|
2167
|
-
} else {
|
2168
|
-
if (inNum) { nums[nums.length - 1].end = i - 1; }
|
2169
|
-
inNum = false;
|
2170
|
-
}
|
2171
|
-
}
|
2172
|
-
if (inNum) { nums[nums.length - 1].end = expression.length - 1; }
|
2173
|
-
|
2174
|
-
// Determine if numeral groups are separated by a comma or dot.
|
2175
|
-
for (let i = nums.length - 1; i > 0; i--) {
|
2176
|
-
if (nums[i - 1].end === nums[i].start - 2 &&
|
2177
|
-
isDotOrComma(expression[nums[i].start - 1], expression[nums[i].start])) {
|
2178
|
-
// Merge the two groups.
|
2179
|
-
nums[i - 1].end = nums[i].end;
|
2180
|
-
nums.splice(i, 1);
|
2181
|
-
}
|
2182
|
-
}
|
2183
|
-
|
2184
|
-
// Consolidate the number nodes
|
2185
|
-
for (let i = nums.length - 1; i >= 0; i--) {
|
2186
|
-
for (let j = nums[i].start + 1; j <= nums[i].end; j++) {
|
2187
|
-
expression[nums[i].start].text += expression[j].text;
|
2188
|
-
}
|
2189
|
-
expression.splice(nums[i].start + 1, nums[i].end - nums[i].start);
|
2190
|
-
// Check if the <mn> is followed by a numeric base in a supsub, e.g. the "3" in 123^4
|
2191
|
-
// If so, merge the first <mn> into the base.
|
2192
|
-
if (expression.length > nums[i].start + 1) {
|
2193
|
-
const nextTerm = expression[nums[i].start + 1];
|
2194
|
-
if (nextTerm.type === "supsub" && nextTerm.base && nextTerm.base.type === "textord" &&
|
2195
|
-
numberRegEx$1.test(nextTerm.base.text)) {
|
2196
|
-
nextTerm.base.text = expression[nums[i].start].text + nextTerm.base.text;
|
2197
|
-
expression.splice(nums[i].start, 1);
|
2198
|
-
}
|
2199
|
-
}
|
2200
|
-
}
|
2201
|
-
};
|
2202
|
-
|
2203
2187
|
/**
|
2204
2188
|
* Wrap the given array of nodes in an <mrow> node if needed, i.e.,
|
2205
2189
|
* unless the array has length 1. Always returns a single node.
|
@@ -2222,6 +2206,39 @@ const makeRow = function(body, semisimple = false) {
|
|
2222
2206
|
return new mathMLTree.MathNode("mrow", body);
|
2223
2207
|
};
|
2224
2208
|
|
2209
|
+
/**
|
2210
|
+
* Check for <mi>.</mi> which is how a dot renders in MathML,
|
2211
|
+
* or <mo separator="true" lspace="0em" rspace="0em">,</mo>
|
2212
|
+
* which is how a braced comma {,} renders in MathML
|
2213
|
+
*/
|
2214
|
+
function isNumberPunctuation(group) {
|
2215
|
+
if (!group) {
|
2216
|
+
return false
|
2217
|
+
}
|
2218
|
+
if (group.type === 'mi' && group.children.length === 1) {
|
2219
|
+
const child = group.children[0];
|
2220
|
+
return child instanceof TextNode && child.text === '.'
|
2221
|
+
} else if (group.type === "mtext" && group.children.length === 1) {
|
2222
|
+
const child = group.children[0];
|
2223
|
+
return child instanceof TextNode && child.text === '\u2008' // punctuation space
|
2224
|
+
} else if (group.type === 'mo' && group.children.length === 1 &&
|
2225
|
+
group.getAttribute('separator') === 'true' &&
|
2226
|
+
group.getAttribute('lspace') === '0em' &&
|
2227
|
+
group.getAttribute('rspace') === '0em') {
|
2228
|
+
const child = group.children[0];
|
2229
|
+
return child instanceof TextNode && child.text === ','
|
2230
|
+
} else {
|
2231
|
+
return false
|
2232
|
+
}
|
2233
|
+
}
|
2234
|
+
const isComma = (expression, i) => {
|
2235
|
+
const node = expression[i];
|
2236
|
+
const followingNode = expression[i + 1];
|
2237
|
+
return (node.type === "atom" && node.text === ",") &&
|
2238
|
+
// Don't consolidate if there is a space after the comma.
|
2239
|
+
node.loc && followingNode.loc && node.loc.end === followingNode.loc.start
|
2240
|
+
};
|
2241
|
+
|
2225
2242
|
const isRel = item => {
|
2226
2243
|
return (item.type === "atom" && item.family === "rel") ||
|
2227
2244
|
(item.type === "mclass" && item.mclass === "mrel")
|
@@ -2245,11 +2262,16 @@ const buildExpression = function(expression, style, semisimple = false) {
|
|
2245
2262
|
return [group];
|
2246
2263
|
}
|
2247
2264
|
|
2248
|
-
consolidateNumbers(expression);
|
2249
|
-
|
2250
2265
|
const groups = [];
|
2266
|
+
const groupArray = [];
|
2267
|
+
let lastGroup;
|
2251
2268
|
for (let i = 0; i < expression.length; i++) {
|
2252
|
-
|
2269
|
+
groupArray.push(buildGroup$1(expression[i], style));
|
2270
|
+
}
|
2271
|
+
|
2272
|
+
for (let i = 0; i < groupArray.length; i++) {
|
2273
|
+
const group = groupArray[i];
|
2274
|
+
|
2253
2275
|
// Suppress spacing between adjacent relations
|
2254
2276
|
if (i < expression.length - 1 && isRel(expression[i]) && isRel(expression[i + 1])) {
|
2255
2277
|
group.setAttribute("rspace", "0em");
|
@@ -2257,9 +2279,39 @@ const buildExpression = function(expression, style, semisimple = false) {
|
|
2257
2279
|
if (i > 0 && isRel(expression[i]) && isRel(expression[i - 1])) {
|
2258
2280
|
group.setAttribute("lspace", "0em");
|
2259
2281
|
}
|
2282
|
+
|
2283
|
+
// Concatenate numbers
|
2284
|
+
if (group.type === 'mn' && lastGroup && lastGroup.type === 'mn') {
|
2285
|
+
// Concatenate <mn>...</mn> followed by <mi>.</mi>
|
2286
|
+
lastGroup.children.push(...group.children);
|
2287
|
+
continue
|
2288
|
+
} else if (isNumberPunctuation(group) && lastGroup && lastGroup.type === 'mn') {
|
2289
|
+
// Concatenate <mn>...</mn> followed by <mi>.</mi>
|
2290
|
+
lastGroup.children.push(...group.children);
|
2291
|
+
continue
|
2292
|
+
} else if (lastGroup && lastGroup.type === "mn" && i < groupArray.length - 1 &&
|
2293
|
+
groupArray[i + 1].type === "mn" && isComma(expression, i)) {
|
2294
|
+
lastGroup.children.push(...group.children);
|
2295
|
+
continue
|
2296
|
+
} else if (group.type === 'mn' && isNumberPunctuation(lastGroup)) {
|
2297
|
+
// Concatenate <mi>.</mi> followed by <mn>...</mn>
|
2298
|
+
group.children = [...lastGroup.children, ...group.children];
|
2299
|
+
groups.pop();
|
2300
|
+
} else if ((group.type === 'msup' || group.type === 'msub') &&
|
2301
|
+
group.children.length >= 1 && lastGroup &&
|
2302
|
+
(lastGroup.type === 'mn' || isNumberPunctuation(lastGroup))) {
|
2303
|
+
// Put preceding <mn>...</mn> or <mi>.</mi> inside base of
|
2304
|
+
// <msup><mn>...base...</mn>...exponent...</msup> (or <msub>)
|
2305
|
+
const base = group.children[0];
|
2306
|
+
if (base instanceof MathNode && base.type === 'mn' && lastGroup) {
|
2307
|
+
base.children = [...lastGroup.children, ...base.children];
|
2308
|
+
groups.pop();
|
2309
|
+
}
|
2310
|
+
}
|
2260
2311
|
groups.push(group);
|
2312
|
+
lastGroup = group;
|
2261
2313
|
}
|
2262
|
-
return groups
|
2314
|
+
return groups
|
2263
2315
|
};
|
2264
2316
|
|
2265
2317
|
/**
|
@@ -2292,16 +2344,36 @@ const glue$1 = _ => {
|
|
2292
2344
|
return new mathMLTree.MathNode("mtd", [], [], { padding: "0", width: "50%" })
|
2293
2345
|
};
|
2294
2346
|
|
2347
|
+
const labelContainers = ["mrow", "mtd", "mtable", "mtr"];
|
2348
|
+
const getLabel = parent => {
|
2349
|
+
for (const node of parent.children) {
|
2350
|
+
if (node.type && labelContainers.includes(node.type)) {
|
2351
|
+
if (node.classes && node.classes[0] === "tml-label") {
|
2352
|
+
const label = node.label;
|
2353
|
+
return label
|
2354
|
+
} else {
|
2355
|
+
const label = getLabel(node);
|
2356
|
+
if (label) { return label }
|
2357
|
+
}
|
2358
|
+
} else if (!node.type) {
|
2359
|
+
const label = getLabel(node);
|
2360
|
+
if (label) { return label }
|
2361
|
+
}
|
2362
|
+
}
|
2363
|
+
};
|
2364
|
+
|
2295
2365
|
const taggedExpression = (expression, tag, style, leqno) => {
|
2296
2366
|
tag = buildExpressionRow(tag[0].body, style);
|
2297
2367
|
tag = consolidateText(tag);
|
2298
2368
|
tag.classes.push("tml-tag");
|
2299
2369
|
|
2370
|
+
const label = getLabel(expression); // from a \label{} function.
|
2300
2371
|
expression = new mathMLTree.MathNode("mtd", [expression]);
|
2301
2372
|
const rowArray = [glue$1(), expression, glue$1()];
|
2302
2373
|
rowArray[leqno ? 0 : 2].classes.push(leqno ? "tml-left" : "tml-right");
|
2303
2374
|
rowArray[leqno ? 0 : 2].children.push(tag);
|
2304
2375
|
const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"]);
|
2376
|
+
if (label) { mtr.setAttribute("id", label); }
|
2305
2377
|
const table = new mathMLTree.MathNode("mtable", [mtr]);
|
2306
2378
|
table.style.width = "100%";
|
2307
2379
|
table.setAttribute("displaystyle", "true");
|
@@ -2321,6 +2393,11 @@ function buildMathML(tree, texExpression, style, settings) {
|
|
2321
2393
|
}
|
2322
2394
|
|
2323
2395
|
const expression = buildExpression(tree, style);
|
2396
|
+
|
2397
|
+
if (expression.length === 1 && expression[0] instanceof AnchorNode) {
|
2398
|
+
return expression[0]
|
2399
|
+
}
|
2400
|
+
|
2324
2401
|
const wrap = (settings.displayMode || settings.annotate) ? "none" : settings.wrap;
|
2325
2402
|
|
2326
2403
|
const n1 = expression.length === 0 ? null : expression[0];
|
@@ -2345,6 +2422,9 @@ function buildMathML(tree, texExpression, style, settings) {
|
|
2345
2422
|
if (settings.xml) {
|
2346
2423
|
math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML");
|
2347
2424
|
}
|
2425
|
+
if (wrapper.style.width) {
|
2426
|
+
math.style.width = "100%";
|
2427
|
+
}
|
2348
2428
|
if (settings.displayMode) {
|
2349
2429
|
math.setAttribute("display", "block");
|
2350
2430
|
math.style.display = "block math"; // necessary in Chromium.
|
@@ -2676,12 +2756,19 @@ const padding$2 = width => {
|
|
2676
2756
|
return node
|
2677
2757
|
};
|
2678
2758
|
|
2679
|
-
const paddedNode = (group, lspace = 0.3, rspace = 0) => {
|
2759
|
+
const paddedNode = (group, lspace = 0.3, rspace = 0, mustSmash = false) => {
|
2680
2760
|
if (group == null && rspace === 0) { return padding$2(lspace) }
|
2681
2761
|
const row = group ? [group] : [];
|
2682
2762
|
if (lspace !== 0) { row.unshift(padding$2(lspace)); }
|
2683
2763
|
if (rspace > 0) { row.push(padding$2(rspace)); }
|
2684
|
-
|
2764
|
+
if (mustSmash) {
|
2765
|
+
// Used for the bottom arrow in a {CD} environment
|
2766
|
+
const mpadded = new mathMLTree.MathNode("mpadded", row);
|
2767
|
+
mpadded.setAttribute("height", "0");
|
2768
|
+
return mpadded
|
2769
|
+
} else {
|
2770
|
+
return new mathMLTree.MathNode("mrow", row)
|
2771
|
+
}
|
2685
2772
|
};
|
2686
2773
|
|
2687
2774
|
const labelSize = (size, scriptLevel) => Number(size) / emScale(scriptLevel);
|
@@ -2721,7 +2808,8 @@ const munderoverNode = (fName, body, below, style) => {
|
|
2721
2808
|
(body.body.body || body.body.length > 0));
|
2722
2809
|
if (gotUpper) {
|
2723
2810
|
let label = buildGroup$1(body, labelStyle);
|
2724
|
-
|
2811
|
+
const mustSmash = (fName === "\\\\cdrightarrow" || fName === "\\\\cdleftarrow");
|
2812
|
+
label = paddedNode(label, space, space, mustSmash);
|
2725
2813
|
// Since Firefox does not support minsize, stack a invisible node
|
2726
2814
|
// on top of the label. Its width will serve as a min-width.
|
2727
2815
|
// TODO: Refactor this after Firefox supports minsize.
|
@@ -3116,6 +3204,8 @@ function parseCD(parser) {
|
|
3116
3204
|
type: "array",
|
3117
3205
|
mode: "math",
|
3118
3206
|
body,
|
3207
|
+
tags: null,
|
3208
|
+
labels: new Array(body.length + 1).fill(""),
|
3119
3209
|
envClasses: ["jot", "cd"],
|
3120
3210
|
cols: [],
|
3121
3211
|
hLinesBeforeRow: new Array(body.length + 1).fill([])
|
@@ -3144,18 +3234,23 @@ defineFunction({
|
|
3144
3234
|
};
|
3145
3235
|
},
|
3146
3236
|
mathmlBuilder(group, style) {
|
3147
|
-
|
3148
|
-
|
3149
|
-
label.setAttribute("width", "0");
|
3150
|
-
if (group.side === "left") {
|
3151
|
-
label.setAttribute("lspace", "-1width");
|
3237
|
+
if (group.label.body.length === 0) {
|
3238
|
+
return new mathMLTree.MathNode("mrow", style) // empty label
|
3152
3239
|
}
|
3153
|
-
//
|
3154
|
-
|
3155
|
-
|
3156
|
-
|
3240
|
+
// Abuse an <mtable> to create vertically centered content.
|
3241
|
+
const mtd = new mathMLTree.MathNode("mtd", [buildGroup$1(group.label, style)]);
|
3242
|
+
mtd.style.padding = "0";
|
3243
|
+
const mtr = new mathMLTree.MathNode("mtr", [mtd]);
|
3244
|
+
const mtable = new mathMLTree.MathNode("mtable", [mtr]);
|
3245
|
+
const label = new mathMLTree.MathNode("mpadded", [mtable]);
|
3246
|
+
// Set the label width to zero so that the arrow will be centered under the corner cell.
|
3247
|
+
label.setAttribute("width", "0");
|
3157
3248
|
label.setAttribute("displaystyle", "false");
|
3158
3249
|
label.setAttribute("scriptlevel", "1");
|
3250
|
+
if (group.side === "left") {
|
3251
|
+
label.style.display = "flex";
|
3252
|
+
label.style.justifyContent = "flex-end";
|
3253
|
+
}
|
3159
3254
|
return label;
|
3160
3255
|
}
|
3161
3256
|
});
|
@@ -3745,10 +3840,13 @@ defineFunction({
|
|
3745
3840
|
// replacement text, enclosed in '{' and '}' and properly nested
|
3746
3841
|
const { tokens } = parser.gullet.consumeArg();
|
3747
3842
|
|
3748
|
-
parser.gullet.macros.
|
3749
|
-
|
3750
|
-
|
3751
|
-
|
3843
|
+
if (!(funcName === "\\providecommand" && parser.gullet.macros.has(name))) {
|
3844
|
+
// Ignore \providecommand
|
3845
|
+
parser.gullet.macros.set(
|
3846
|
+
name,
|
3847
|
+
{ tokens, numArgs }
|
3848
|
+
);
|
3849
|
+
}
|
3752
3850
|
|
3753
3851
|
return { type: "internal", mode: parser.mode };
|
3754
3852
|
|
@@ -3842,6 +3940,7 @@ const delimiters = [
|
|
3842
3940
|
"\\vert",
|
3843
3941
|
"\\|",
|
3844
3942
|
"\\Vert",
|
3943
|
+
"\u2016",
|
3845
3944
|
"\\uparrow",
|
3846
3945
|
"\\Uparrow",
|
3847
3946
|
"\\downarrow",
|
@@ -4347,6 +4446,75 @@ function defineEnvironment({ type, names, props, handler, mathmlBuilder }) {
|
|
4347
4446
|
}
|
4348
4447
|
}
|
4349
4448
|
|
4449
|
+
/**
|
4450
|
+
* Lexing or parsing positional information for error reporting.
|
4451
|
+
* This object is immutable.
|
4452
|
+
*/
|
4453
|
+
class SourceLocation {
|
4454
|
+
constructor(lexer, start, end) {
|
4455
|
+
this.lexer = lexer; // Lexer holding the input string.
|
4456
|
+
this.start = start; // Start offset, zero-based inclusive.
|
4457
|
+
this.end = end; // End offset, zero-based exclusive.
|
4458
|
+
}
|
4459
|
+
|
4460
|
+
/**
|
4461
|
+
* Merges two `SourceLocation`s from location providers, given they are
|
4462
|
+
* provided in order of appearance.
|
4463
|
+
* - Returns the first one's location if only the first is provided.
|
4464
|
+
* - Returns a merged range of the first and the last if both are provided
|
4465
|
+
* and their lexers match.
|
4466
|
+
* - Otherwise, returns null.
|
4467
|
+
*/
|
4468
|
+
static range(first, second) {
|
4469
|
+
if (!second) {
|
4470
|
+
return first && first.loc;
|
4471
|
+
} else if (!first || !first.loc || !second.loc || first.loc.lexer !== second.loc.lexer) {
|
4472
|
+
return null;
|
4473
|
+
} else {
|
4474
|
+
return new SourceLocation(first.loc.lexer, first.loc.start, second.loc.end);
|
4475
|
+
}
|
4476
|
+
}
|
4477
|
+
}
|
4478
|
+
|
4479
|
+
/**
|
4480
|
+
* Interface required to break circular dependency between Token, Lexer, and
|
4481
|
+
* ParseError.
|
4482
|
+
*/
|
4483
|
+
|
4484
|
+
/**
|
4485
|
+
* The resulting token returned from `lex`.
|
4486
|
+
*
|
4487
|
+
* It consists of the token text plus some position information.
|
4488
|
+
* The position information is essentially a range in an input string,
|
4489
|
+
* but instead of referencing the bare input string, we refer to the lexer.
|
4490
|
+
* That way it is possible to attach extra metadata to the input string,
|
4491
|
+
* like for example a file name or similar.
|
4492
|
+
*
|
4493
|
+
* The position information is optional, so it is OK to construct synthetic
|
4494
|
+
* tokens if appropriate. Not providing available position information may
|
4495
|
+
* lead to degraded error reporting, though.
|
4496
|
+
*/
|
4497
|
+
class Token {
|
4498
|
+
constructor(
|
4499
|
+
text, // the text of this token
|
4500
|
+
loc
|
4501
|
+
) {
|
4502
|
+
this.text = text;
|
4503
|
+
this.loc = loc;
|
4504
|
+
}
|
4505
|
+
|
4506
|
+
/**
|
4507
|
+
* Given a pair of tokens (this and endToken), compute a `Token` encompassing
|
4508
|
+
* the whole input range enclosed by these two.
|
4509
|
+
*/
|
4510
|
+
range(
|
4511
|
+
endToken, // last token of the range, inclusive
|
4512
|
+
text // the text of the newly constructed token
|
4513
|
+
) {
|
4514
|
+
return new Token(text, SourceLocation.range(this, endToken));
|
4515
|
+
}
|
4516
|
+
}
|
4517
|
+
|
4350
4518
|
// In TeX, there are actually three sets of dimensions, one for each of
|
4351
4519
|
// textstyle, scriptstyle, and scriptscriptstyle. These are
|
4352
4520
|
// provided in the the arrays below, in that order.
|
@@ -4611,7 +4779,7 @@ defineMacro("\\underbar", "\\underline{\\text{#1}}");
|
|
4611
4779
|
// \kern6\p@\hbox{.}\hbox{.}\hbox{.}}}
|
4612
4780
|
// We'll call \varvdots, which gets a glyph from symbols.js.
|
4613
4781
|
// The zero-width rule gets us an equivalent to the vertical 6pt kern.
|
4614
|
-
defineMacro("\\vdots", "
|
4782
|
+
defineMacro("\\vdots", "{\\varvdots\\rule{0pt}{15pt}}");
|
4615
4783
|
defineMacro("\u22ee", "\\vdots");
|
4616
4784
|
|
4617
4785
|
// {array} environment gaps
|
@@ -4831,8 +4999,10 @@ defineMacro("\\tag@literal", (context) => {
|
|
4831
4999
|
if (context.macros.get("\\df@tag")) {
|
4832
5000
|
throw new ParseError("Multiple \\tag");
|
4833
5001
|
}
|
4834
|
-
return "\\
|
5002
|
+
return "\\gdef\\df@tag{\\text{#1}}";
|
4835
5003
|
});
|
5004
|
+
defineMacro("\\notag", "\\nonumber");
|
5005
|
+
defineMacro("\\nonumber", "\\gdef\\@eqnsw{0}");
|
4836
5006
|
|
4837
5007
|
// \renewcommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin
|
4838
5008
|
// {\operator@font mod}\penalty900
|
@@ -7036,33 +7206,30 @@ const arrayGaps = macros => {
|
|
7036
7206
|
return [arraystretch, arraycolsep]
|
7037
7207
|
};
|
7038
7208
|
|
7039
|
-
const
|
7040
|
-
|
7041
|
-
|
7042
|
-
|
7043
|
-
|
7044
|
-
|
7045
|
-
|
7046
|
-
|
7047
|
-
} else {
|
7048
|
-
// \notag. Return an empty span.
|
7049
|
-
tag = new mathMLTree.MathNode("mtext", [], []);
|
7050
|
-
return tag
|
7051
|
-
}
|
7052
|
-
} else if (group.envClasses.includes("multline") &&
|
7053
|
-
((group.leqno && rowNum !== 0) || (!group.leqno && rowNum !== group.body.length - 1))) {
|
7054
|
-
// A multiline that does not receive a tag. Return an empty cell.
|
7055
|
-
tag = new mathMLTree.MathNode("mtext", [], []);
|
7056
|
-
return tag
|
7057
|
-
} else {
|
7058
|
-
// AMS automatcally numbered equaton.
|
7059
|
-
// Insert a class so the element can be populated by a CSS counter.
|
7060
|
-
// WebKit will display the CSS counter only inside a span.
|
7061
|
-
tag = new mathMLTree.MathNode("mtext", [new Span(["tml-eqn"])]);
|
7209
|
+
const checkCellForLabels = cell => {
|
7210
|
+
// Check if the author wrote a \tag{} inside this cell.
|
7211
|
+
let rowLabel = "";
|
7212
|
+
for (let i = 0; i < cell.length; i++) {
|
7213
|
+
if (cell[i].type === "label") {
|
7214
|
+
if (rowLabel) { throw new ParseError(("Multiple \\labels in one row")) }
|
7215
|
+
rowLabel = cell[i].string;
|
7216
|
+
}
|
7062
7217
|
}
|
7063
|
-
return
|
7218
|
+
return rowLabel
|
7064
7219
|
};
|
7065
7220
|
|
7221
|
+
// autoTag (an argument to parseArray) can be one of three values:
|
7222
|
+
// * undefined: Regular (not-top-level) array; no tags on each row
|
7223
|
+
// * true: Automatic equation numbering, overridable by \tag
|
7224
|
+
// * false: Tags allowed on each row, but no automatic numbering
|
7225
|
+
// This function *doesn't* work with the "split" environment name.
|
7226
|
+
function getAutoTag(name) {
|
7227
|
+
if (name.indexOf("ed") === -1) {
|
7228
|
+
return name.indexOf("*") === -1;
|
7229
|
+
}
|
7230
|
+
// return undefined;
|
7231
|
+
}
|
7232
|
+
|
7066
7233
|
/**
|
7067
7234
|
* Parse the body of the environment, with rows delimited by \\ and
|
7068
7235
|
* columns delimited by &, and create a nested list in row-major order
|
@@ -7074,7 +7241,7 @@ function parseArray(
|
|
7074
7241
|
{
|
7075
7242
|
cols, // [{ type: string , align: l|c|r|null }]
|
7076
7243
|
envClasses, // align(ed|at|edat) | array | cases | cd | small | multline
|
7077
|
-
|
7244
|
+
autoTag, // boolean
|
7078
7245
|
singleRow, // boolean
|
7079
7246
|
emptySingleRow, // boolean
|
7080
7247
|
maxNumCols, // number
|
@@ -7090,13 +7257,6 @@ function parseArray(
|
|
7090
7257
|
// TODO: provide helpful error when \cr is used outside array environment
|
7091
7258
|
parser.gullet.macros.set("\\cr", "\\\\\\relax");
|
7092
7259
|
}
|
7093
|
-
if (addEqnNum) {
|
7094
|
-
parser.gullet.macros.set("\\tag", "\\@ifstar\\envtag@literal\\envtag@paren");
|
7095
|
-
parser.gullet.macros.set("\\envtag@paren", "\\env@tag{{(\\text{#1})}}");
|
7096
|
-
parser.gullet.macros.set("\\envtag@literal", "\\env@tag{\\text{#1}}");
|
7097
|
-
parser.gullet.macros.set("\\notag", "\\env@notag");
|
7098
|
-
parser.gullet.macros.set("\\nonumber", "\\env@notag");
|
7099
|
-
}
|
7100
7260
|
|
7101
7261
|
// Start group for first cell
|
7102
7262
|
parser.gullet.beginGroup();
|
@@ -7104,29 +7264,39 @@ function parseArray(
|
|
7104
7264
|
let row = [];
|
7105
7265
|
const body = [row];
|
7106
7266
|
const rowGaps = [];
|
7107
|
-
const
|
7108
|
-
|
7267
|
+
const labels = [];
|
7268
|
+
|
7109
7269
|
const hLinesBeforeRow = [];
|
7110
7270
|
|
7271
|
+
const tags = (autoTag != null ? [] : undefined);
|
7272
|
+
|
7273
|
+
// amsmath uses \global\@eqnswtrue and \global\@eqnswfalse to represent
|
7274
|
+
// whether this row should have an equation number. Simulate this with
|
7275
|
+
// a \@eqnsw macro set to 1 or 0.
|
7276
|
+
function beginRow() {
|
7277
|
+
if (autoTag) {
|
7278
|
+
parser.gullet.macros.set("\\@eqnsw", "1", true);
|
7279
|
+
}
|
7280
|
+
}
|
7281
|
+
function endRow() {
|
7282
|
+
if (tags) {
|
7283
|
+
if (parser.gullet.macros.get("\\df@tag")) {
|
7284
|
+
tags.push(parser.subparse([new Token("\\df@tag")]));
|
7285
|
+
parser.gullet.macros.set("\\df@tag", undefined, true);
|
7286
|
+
} else {
|
7287
|
+
tags.push(Boolean(autoTag) &&
|
7288
|
+
parser.gullet.macros.get("\\@eqnsw") === "1");
|
7289
|
+
}
|
7290
|
+
}
|
7291
|
+
}
|
7292
|
+
beginRow();
|
7293
|
+
|
7111
7294
|
// Test for \hline at the top of the array.
|
7112
7295
|
hLinesBeforeRow.push(getHLines(parser));
|
7113
7296
|
|
7114
7297
|
while (true) {
|
7115
7298
|
// Parse each cell in its own group (namespace)
|
7116
7299
|
let cell = parser.parseExpression(false, singleRow ? "\\end" : "\\\\");
|
7117
|
-
|
7118
|
-
if (addEqnNum && !rowTag) {
|
7119
|
-
// Check if the author wrote a \tag{} inside this cell.
|
7120
|
-
for (let i = 0; i < cell.length; i++) {
|
7121
|
-
if (cell[i].type === "envTag" || cell[i].type === "noTag") {
|
7122
|
-
// Get the contents of the \text{} nested inside the \env@Tag{}
|
7123
|
-
rowTag = cell[i].type === "envTag"
|
7124
|
-
? cell.splice(i, 1)[0].body.body[0]
|
7125
|
-
: { body: null };
|
7126
|
-
break
|
7127
|
-
}
|
7128
|
-
}
|
7129
|
-
}
|
7130
7300
|
parser.gullet.endGroup();
|
7131
7301
|
parser.gullet.beginGroup();
|
7132
7302
|
|
@@ -7155,6 +7325,7 @@ function parseArray(
|
|
7155
7325
|
}
|
7156
7326
|
parser.consume();
|
7157
7327
|
} else if (next === "\\end") {
|
7328
|
+
endRow();
|
7158
7329
|
// Arrays terminate newlines with `\crcr` which consumes a `\cr` if
|
7159
7330
|
// the last line is empty. However, AMS environments keep the
|
7160
7331
|
// empty row if it's the only one.
|
@@ -7162,6 +7333,7 @@ function parseArray(
|
|
7162
7333
|
if (row.length === 1 && cell.body.length === 0 && (body.length > 1 || !emptySingleRow)) {
|
7163
7334
|
body.pop();
|
7164
7335
|
}
|
7336
|
+
labels.push(checkCellForLabels(cell.body));
|
7165
7337
|
if (hLinesBeforeRow.length < body.length + 1) {
|
7166
7338
|
hLinesBeforeRow.push([]);
|
7167
7339
|
}
|
@@ -7178,15 +7350,16 @@ function parseArray(
|
|
7178
7350
|
size = parser.parseSizeGroup(true);
|
7179
7351
|
}
|
7180
7352
|
rowGaps.push(size ? size.value : null);
|
7353
|
+
endRow();
|
7181
7354
|
|
7182
|
-
|
7355
|
+
labels.push(checkCellForLabels(cell.body));
|
7183
7356
|
|
7184
7357
|
// check for \hline(s) following the row separator
|
7185
7358
|
hLinesBeforeRow.push(getHLines(parser));
|
7186
7359
|
|
7187
7360
|
row = [];
|
7188
|
-
rowTag = null;
|
7189
7361
|
body.push(row);
|
7362
|
+
beginRow();
|
7190
7363
|
} else {
|
7191
7364
|
throw new ParseError("Expected & or \\\\ or \\cr or \\end", parser.nextToken);
|
7192
7365
|
}
|
@@ -7197,8 +7370,6 @@ function parseArray(
|
|
7197
7370
|
// End array group defining \cr
|
7198
7371
|
parser.gullet.endGroup();
|
7199
7372
|
|
7200
|
-
tags.push(rowTag);
|
7201
|
-
|
7202
7373
|
return {
|
7203
7374
|
type: "array",
|
7204
7375
|
mode: parser.mode,
|
@@ -7207,9 +7378,10 @@ function parseArray(
|
|
7207
7378
|
rowGaps,
|
7208
7379
|
hLinesBeforeRow,
|
7209
7380
|
envClasses,
|
7210
|
-
|
7381
|
+
autoTag,
|
7211
7382
|
scriptLevel,
|
7212
7383
|
tags,
|
7384
|
+
labels,
|
7213
7385
|
leqno,
|
7214
7386
|
arraystretch,
|
7215
7387
|
arraycolsep
|
@@ -7266,19 +7438,43 @@ const mathmlBuilder$7 = function(group, style) {
|
|
7266
7438
|
}
|
7267
7439
|
row.push(mtd);
|
7268
7440
|
}
|
7269
|
-
|
7270
|
-
|
7271
|
-
|
7272
|
-
|
7273
|
-
|
7274
|
-
|
7275
|
-
|
7276
|
-
|
7277
|
-
|
7278
|
-
|
7441
|
+
const numColumns = group.body[0].length;
|
7442
|
+
// Fill out a short row with empty <mtd> elements.
|
7443
|
+
for (let k = 0; k < numColumns - rw.length; k++) {
|
7444
|
+
row.push(new mathMLTree.MathNode("mtd", [], style));
|
7445
|
+
}
|
7446
|
+
if (group.autoTag) {
|
7447
|
+
const tag = group.tags[i];
|
7448
|
+
let tagElement;
|
7449
|
+
if (tag === true) { // automatic numbering
|
7450
|
+
tagElement = new mathMLTree.MathNode("mtext", [new Span(["tml-eqn"])]);
|
7451
|
+
} else if (tag === false) {
|
7452
|
+
// \nonumber/\notag or starred environment
|
7453
|
+
tagElement = new mathMLTree.MathNode("mtext", [], []);
|
7454
|
+
} else { // manual \tag
|
7455
|
+
tagElement = buildExpressionRow(tag[0].body, style.withLevel(cellLevel), true);
|
7456
|
+
tagElement = consolidateText(tagElement);
|
7457
|
+
tagElement.classes = ["tml-tag"];
|
7458
|
+
}
|
7459
|
+
if (tagElement) {
|
7460
|
+
row.unshift(glue(group));
|
7461
|
+
row.push(glue(group));
|
7462
|
+
if (group.leqno) {
|
7463
|
+
row[0].children.push(tagElement);
|
7464
|
+
row[0].classes.push("tml-left");
|
7465
|
+
} else {
|
7466
|
+
row[row.length - 1].children.push(tagElement);
|
7467
|
+
row[row.length - 1].classes.push("tml-right");
|
7468
|
+
}
|
7279
7469
|
}
|
7280
7470
|
}
|
7281
7471
|
const mtr = new mathMLTree.MathNode("mtr", row, []);
|
7472
|
+
const label = group.labels.shift();
|
7473
|
+
if (label && group.tags && group.tags[i]) {
|
7474
|
+
mtr.setAttribute("id", label);
|
7475
|
+
if (Array.isArray(group.tags[i])) { mtr.classes.push("tml-tageqn"); }
|
7476
|
+
}
|
7477
|
+
|
7282
7478
|
// Write horizontal rules
|
7283
7479
|
if (i === 0 && hlines[0].length > 0) {
|
7284
7480
|
if (hlines[0].length === 2) {
|
@@ -7302,16 +7498,17 @@ const mathmlBuilder$7 = function(group, style) {
|
|
7302
7498
|
}
|
7303
7499
|
|
7304
7500
|
if (group.envClasses.length > 0) {
|
7305
|
-
let pad = group.envClasses.includes("jot")
|
7306
|
-
? "0.7" // 0.5ex + 0.09em top & bot padding
|
7307
|
-
: group.envClasses.includes("small")
|
7308
|
-
? "0.35"
|
7309
|
-
: "0.5"; // 0.5ex default top & bot padding
|
7310
7501
|
if (group.arraystretch && group.arraystretch !== 1) {
|
7311
7502
|
// In LaTeX, \arraystretch is a factor applied to a 12pt strut height.
|
7312
7503
|
// It defines a baseline to baseline distance.
|
7313
7504
|
// Here, we do an approximation of that approach.
|
7314
|
-
pad = String(1.4 * group.arraystretch - 0.8);
|
7505
|
+
const pad = String(1.4 * group.arraystretch - 0.8) + "ex";
|
7506
|
+
for (let i = 0; i < tbl.length; i++) {
|
7507
|
+
for (let j = 0; j < tbl[i].children.length; j++) {
|
7508
|
+
tbl[i].children[j].style.paddingTop = pad;
|
7509
|
+
tbl[i].children[j].style.paddingBottom = pad;
|
7510
|
+
}
|
7511
|
+
}
|
7315
7512
|
}
|
7316
7513
|
let sidePadding = group.envClasses.includes("abut")
|
7317
7514
|
? "0"
|
@@ -7325,7 +7522,7 @@ const mathmlBuilder$7 = function(group, style) {
|
|
7325
7522
|
let sidePadUnit = "em";
|
7326
7523
|
if (group.arraycolsep) {
|
7327
7524
|
const arraySidePad = calculateSize(group.arraycolsep, style);
|
7328
|
-
sidePadding = arraySidePad.number;
|
7525
|
+
sidePadding = arraySidePad.number.toFixed(4);
|
7329
7526
|
sidePadUnit = arraySidePad.unit;
|
7330
7527
|
}
|
7331
7528
|
|
@@ -7336,18 +7533,18 @@ const mathmlBuilder$7 = function(group, style) {
|
|
7336
7533
|
if (j === numCols - 1 && hand === 1) { return "0" }
|
7337
7534
|
if (group.envClasses[0] !== "align") { return sidePadding }
|
7338
7535
|
if (hand === 1) { return "0" }
|
7339
|
-
if (group.
|
7536
|
+
if (group.autoTag) {
|
7340
7537
|
return (j % 2) ? "1" : "0"
|
7341
7538
|
} else {
|
7342
7539
|
return (j % 2) ? "0" : "1"
|
7343
7540
|
}
|
7344
7541
|
};
|
7345
7542
|
|
7346
|
-
//
|
7543
|
+
// Side padding
|
7347
7544
|
for (let i = 0; i < tbl.length; i++) {
|
7348
7545
|
for (let j = 0; j < tbl[i].children.length; j++) {
|
7349
|
-
tbl[i].children[j].style.
|
7350
|
-
|
7546
|
+
tbl[i].children[j].style.paddingLeft = `${sidePad(j, 0)}${sidePadUnit}`;
|
7547
|
+
tbl[i].children[j].style.paddingRight = `${sidePad(j, 1)}${sidePadUnit}`;
|
7351
7548
|
}
|
7352
7549
|
}
|
7353
7550
|
|
@@ -7361,13 +7558,13 @@ const mathmlBuilder$7 = function(group, style) {
|
|
7361
7558
|
// TODO: Remove -webkit- when Chromium no longer needs it.
|
7362
7559
|
row.children[j].classes = ["tml-" + (j % 2 ? "left" : "right")];
|
7363
7560
|
}
|
7364
|
-
if (group.
|
7561
|
+
if (group.autoTag) {
|
7365
7562
|
const k = group.leqno ? 0 : row.children.length - 1;
|
7366
7563
|
row.children[k].classes = ["tml-" + (group.leqno ? "left" : "right")];
|
7367
7564
|
}
|
7368
7565
|
}
|
7369
7566
|
if (row.children.length > 1 && group.envClasses.includes("cases")) {
|
7370
|
-
row.children[1].style.
|
7567
|
+
row.children[1].style.paddingLeft = "1em";
|
7371
7568
|
}
|
7372
7569
|
|
7373
7570
|
if (group.envClasses.includes("cases") || group.envClasses.includes("subarray")) {
|
@@ -7387,9 +7584,17 @@ const mathmlBuilder$7 = function(group, style) {
|
|
7387
7584
|
}
|
7388
7585
|
|
7389
7586
|
let table = new mathMLTree.MathNode("mtable", tbl);
|
7587
|
+
if (group.envClasses.length > 0) {
|
7588
|
+
// Top & bottom padding
|
7589
|
+
if (group.envClasses.includes("jot")) {
|
7590
|
+
table.classes.push("tml-jot");
|
7591
|
+
} else if (group.envClasses.includes("small")) {
|
7592
|
+
table.classes.push("tml-small");
|
7593
|
+
}
|
7594
|
+
}
|
7390
7595
|
if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true"); }
|
7391
7596
|
|
7392
|
-
if (group.
|
7597
|
+
if (group.autoTag || group.envClasses.includes("multline")) {
|
7393
7598
|
table.style.width = "100%";
|
7394
7599
|
}
|
7395
7600
|
|
@@ -7419,7 +7624,7 @@ const mathmlBuilder$7 = function(group, style) {
|
|
7419
7624
|
row.children[0].style.borderLeft = sep;
|
7420
7625
|
}
|
7421
7626
|
}
|
7422
|
-
let iCol = group.
|
7627
|
+
let iCol = group.autoTag ? 0 : -1;
|
7423
7628
|
for (let i = iStart; i < iEnd; i++) {
|
7424
7629
|
if (cols[i].type === "align") {
|
7425
7630
|
const colAlign = alignMap[cols[i].align];
|
@@ -7461,7 +7666,7 @@ const mathmlBuilder$7 = function(group, style) {
|
|
7461
7666
|
}
|
7462
7667
|
}
|
7463
7668
|
}
|
7464
|
-
if (group.
|
7669
|
+
if (group.autoTag) {
|
7465
7670
|
// allow for glue cells on each side
|
7466
7671
|
align = "left " + (align.length > 0 ? align : "center ") + "right ";
|
7467
7672
|
}
|
@@ -7485,13 +7690,14 @@ const alignedHandler = function(context, args) {
|
|
7485
7690
|
if (context.envName.indexOf("ed") === -1) {
|
7486
7691
|
validateAmsEnvironmentContext(context);
|
7487
7692
|
}
|
7693
|
+
const isSplit = context.envName === "split";
|
7488
7694
|
const cols = [];
|
7489
7695
|
const res = parseArray(
|
7490
7696
|
context.parser,
|
7491
7697
|
{
|
7492
7698
|
cols,
|
7493
|
-
addEqnNum: context.envName === "align" || context.envName === "alignat",
|
7494
7699
|
emptySingleRow: true,
|
7700
|
+
autoTag: isSplit ? undefined : getAutoTag(context.envName),
|
7495
7701
|
envClasses: ["abut", "jot"], // set row spacing & provisional column spacing
|
7496
7702
|
maxNumCols: context.envName === "split" ? 2 : undefined,
|
7497
7703
|
leqno: context.parser.settings.leqno
|
@@ -7813,7 +8019,7 @@ defineEnvironment({
|
|
7813
8019
|
const res = {
|
7814
8020
|
cols: [],
|
7815
8021
|
envClasses: ["abut", "jot"],
|
7816
|
-
|
8022
|
+
autoTag: getAutoTag(context.envName),
|
7817
8023
|
emptySingleRow: true,
|
7818
8024
|
leqno: context.parser.settings.leqno
|
7819
8025
|
};
|
@@ -7831,7 +8037,7 @@ defineEnvironment({
|
|
7831
8037
|
handler(context) {
|
7832
8038
|
validateAmsEnvironmentContext(context);
|
7833
8039
|
const res = {
|
7834
|
-
|
8040
|
+
autoTag: getAutoTag(context.envName),
|
7835
8041
|
emptySingleRow: true,
|
7836
8042
|
singleRow: true,
|
7837
8043
|
maxNumCols: 1,
|
@@ -7852,7 +8058,7 @@ defineEnvironment({
|
|
7852
8058
|
handler(context) {
|
7853
8059
|
validateAmsEnvironmentContext(context);
|
7854
8060
|
const res = {
|
7855
|
-
|
8061
|
+
autoTag: context.envName === "multline",
|
7856
8062
|
maxNumCols: 1,
|
7857
8063
|
envClasses: ["jot", "multline"],
|
7858
8064
|
leqno: context.parser.settings.leqno
|
@@ -8074,6 +8280,7 @@ defineFunction({
|
|
8074
8280
|
"\\mathfrak",
|
8075
8281
|
"\\mathscr",
|
8076
8282
|
"\\mathsf",
|
8283
|
+
"\\mathsfit",
|
8077
8284
|
"\\mathtt",
|
8078
8285
|
|
8079
8286
|
// aliases
|
@@ -8143,10 +8350,19 @@ const mathmlBuilder$5 = (group, style) => {
|
|
8143
8350
|
? style.withLevel(StyleLevel.SCRIPT)
|
8144
8351
|
: style.withLevel(StyleLevel.SCRIPTSCRIPT);
|
8145
8352
|
|
8146
|
-
|
8147
|
-
|
8148
|
-
|
8149
|
-
|
8353
|
+
// Chromium (wrongly) continues to shrink fractions beyond scriptscriptlevel.
|
8354
|
+
// So we check for levels that Chromium shrinks too small.
|
8355
|
+
// If necessary, set an explicit fraction depth.
|
8356
|
+
const numer = buildGroup$1(group.numer, childOptions);
|
8357
|
+
const denom = buildGroup$1(group.denom, childOptions);
|
8358
|
+
if (style.level === 3) {
|
8359
|
+
numer.style.mathDepth = "2";
|
8360
|
+
numer.setAttribute("scriptlevel", "2");
|
8361
|
+
denom.style.mathDepth = "2";
|
8362
|
+
denom.setAttribute("scriptlevel", "2");
|
8363
|
+
}
|
8364
|
+
|
8365
|
+
let node = new mathMLTree.MathNode("mfrac", [numer, denom]);
|
8150
8366
|
|
8151
8367
|
if (!group.hasBarLine) {
|
8152
8368
|
node.setAttribute("linethickness", "0px");
|
@@ -8539,12 +8755,9 @@ defineFunction({
|
|
8539
8755
|
};
|
8540
8756
|
},
|
8541
8757
|
mathmlBuilder: (group, style) => {
|
8542
|
-
|
8543
|
-
|
8544
|
-
|
8545
|
-
}
|
8546
|
-
math.setAttribute("href", group.href);
|
8547
|
-
return math;
|
8758
|
+
const math = new MathNode("math", [buildExpressionRow(group.body, style)]);
|
8759
|
+
const anchorNode = new AnchorNode(group.href, [], [math]);
|
8760
|
+
return anchorNode
|
8548
8761
|
}
|
8549
8762
|
});
|
8550
8763
|
|
@@ -8902,7 +9115,7 @@ defineFunction({
|
|
8902
9115
|
// Return a no-width, no-ink element with an HTML id.
|
8903
9116
|
const node = new mathMLTree.MathNode("mrow", [], ["tml-label"]);
|
8904
9117
|
if (group.string.length > 0) {
|
8905
|
-
node.
|
9118
|
+
node.setLabel(group.string);
|
8906
9119
|
}
|
8907
9120
|
return node
|
8908
9121
|
}
|
@@ -9416,13 +9629,6 @@ const mathmlBuilder$2 = (group, style) => {
|
|
9416
9629
|
node = new MathNode("mo", [makeText(group.name, group.mode)]);
|
9417
9630
|
if (noSuccessor.includes(group.name)) {
|
9418
9631
|
node.setAttribute("largeop", "false");
|
9419
|
-
} else if (group.limits) {
|
9420
|
-
// This is a workaround for a MathML/Chromium bug.
|
9421
|
-
// This is being applied to singleCharBigOps, which are not really stretchy.
|
9422
|
-
// But by setting the stretchy attribute, Chromium will vertically center
|
9423
|
-
// big ops around the math axis. This is needed since STIX TWO does not do so.
|
9424
|
-
// TODO: Remove this hack when MathML & Chromium fix their problem.
|
9425
|
-
node.setAttribute("stretchy", "true");
|
9426
9632
|
} else {
|
9427
9633
|
node.setAttribute("movablelimits", "false");
|
9428
9634
|
}
|
@@ -10057,12 +10263,10 @@ defineFunction({
|
|
10057
10263
|
};
|
10058
10264
|
},
|
10059
10265
|
mathmlBuilder(group, style) {
|
10060
|
-
// Create an empty
|
10266
|
+
// Create an empty <a> node. Set a class and an href attribute.
|
10061
10267
|
// The post-processor will populate with the target's tag or equation number.
|
10062
10268
|
const classes = group.funcName === "\\ref" ? ["tml-ref"] : ["tml-ref", "tml-eqref"];
|
10063
|
-
|
10064
|
-
node.setAttribute("href", "#" + group.string);
|
10065
|
-
return node
|
10269
|
+
return new AnchorNode("#" + group.string, classes, null)
|
10066
10270
|
}
|
10067
10271
|
});
|
10068
10272
|
|
@@ -10109,6 +10313,8 @@ defineFunction({
|
|
10109
10313
|
props: {
|
10110
10314
|
numArgs: 2,
|
10111
10315
|
numOptionalArgs: 1,
|
10316
|
+
allowedInText: true,
|
10317
|
+
allowedInMath: true,
|
10112
10318
|
argTypes: ["size", "size", "size"]
|
10113
10319
|
},
|
10114
10320
|
handler({ parser }, args, optArgs) {
|
@@ -10401,16 +10607,25 @@ defineFunctionBuilders({
|
|
10401
10607
|
? [buildGroup$1(group.base.body[0], style)]
|
10402
10608
|
: [buildGroup$1(group.base, style)];
|
10403
10609
|
|
10610
|
+
// Note regarding scriptstyle level.
|
10611
|
+
// (Sub|super)scripts should not shrink beyond MathML scriptlevel 2 aka \scriptscriptstyle
|
10612
|
+
// Ref: https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes
|
10613
|
+
// (BTW, MathML scriptlevel 2 is equal to Temml level 3.)
|
10614
|
+
// But Chromium continues to shrink the (sub|super)scripts. So we explicitly set scriptlevel 2.
|
10615
|
+
|
10404
10616
|
const childStyle = style.inSubOrSup();
|
10405
10617
|
if (group.sub) {
|
10406
|
-
|
10618
|
+
const sub = buildGroup$1(group.sub, childStyle);
|
10619
|
+
if (style.level === 3) { sub.setAttribute("scriptlevel", "2"); }
|
10620
|
+
children.push(sub);
|
10407
10621
|
}
|
10408
10622
|
|
10409
10623
|
if (group.sup) {
|
10410
10624
|
const sup = buildGroup$1(group.sup, childStyle);
|
10625
|
+
if (style.level === 3) { sup.setAttribute("scriptlevel", "2"); }
|
10411
10626
|
const testNode = sup.type === "mrow" ? sup.children[0] : sup;
|
10412
10627
|
if ((testNode && testNode.type === "mo" && testNode.classes.includes("tml-prime"))
|
10413
|
-
&& group.base && group.base.text && group.base.text
|
10628
|
+
&& group.base && group.base.text && "fF".indexOf(group.base.text) > -1) {
|
10414
10629
|
// Chromium does not address italic correction on prime. Prevent f′ from overlapping.
|
10415
10630
|
testNode.classes.push("prime-pad");
|
10416
10631
|
}
|
@@ -10637,6 +10852,8 @@ const getVariant = function(group, style) {
|
|
10637
10852
|
return "script"
|
10638
10853
|
case "mathsf":
|
10639
10854
|
return "sans-serif"
|
10855
|
+
case "mathsfit":
|
10856
|
+
return "sans-serif-italic"
|
10640
10857
|
case "mathtt":
|
10641
10858
|
return "monospace"
|
10642
10859
|
}
|
@@ -11101,6 +11318,32 @@ defineFunction({
|
|
11101
11318
|
}
|
11102
11319
|
});
|
11103
11320
|
|
11321
|
+
// \vcenter: Vertically center the argument group on the math axis.
|
11322
|
+
|
11323
|
+
defineFunction({
|
11324
|
+
type: "vcenter",
|
11325
|
+
names: ["\\vcenter"],
|
11326
|
+
props: {
|
11327
|
+
numArgs: 1,
|
11328
|
+
argTypes: ["original"],
|
11329
|
+
allowedInText: false
|
11330
|
+
},
|
11331
|
+
handler({ parser }, args) {
|
11332
|
+
return {
|
11333
|
+
type: "vcenter",
|
11334
|
+
mode: parser.mode,
|
11335
|
+
body: args[0]
|
11336
|
+
};
|
11337
|
+
},
|
11338
|
+
mathmlBuilder(group, style) {
|
11339
|
+
// Use a math table to create vertically centered content.
|
11340
|
+
const mtd = new mathMLTree.MathNode("mtd", [buildGroup$1(group.body, style)]);
|
11341
|
+
mtd.style.padding = "0";
|
11342
|
+
const mtr = new mathMLTree.MathNode("mtr", [mtd]);
|
11343
|
+
return new mathMLTree.MathNode("mtable", [mtr])
|
11344
|
+
}
|
11345
|
+
});
|
11346
|
+
|
11104
11347
|
defineFunction({
|
11105
11348
|
type: "verb",
|
11106
11349
|
names: ["\\verb"],
|
@@ -11135,75 +11378,6 @@ const makeVerb = (group) => group.body.replace(/ /g, group.star ? "\u2423" : "\x
|
|
11135
11378
|
|
11136
11379
|
const functions = _functions;
|
11137
11380
|
|
11138
|
-
/**
|
11139
|
-
* Lexing or parsing positional information for error reporting.
|
11140
|
-
* This object is immutable.
|
11141
|
-
*/
|
11142
|
-
class SourceLocation {
|
11143
|
-
constructor(lexer, start, end) {
|
11144
|
-
this.lexer = lexer; // Lexer holding the input string.
|
11145
|
-
this.start = start; // Start offset, zero-based inclusive.
|
11146
|
-
this.end = end; // End offset, zero-based exclusive.
|
11147
|
-
}
|
11148
|
-
|
11149
|
-
/**
|
11150
|
-
* Merges two `SourceLocation`s from location providers, given they are
|
11151
|
-
* provided in order of appearance.
|
11152
|
-
* - Returns the first one's location if only the first is provided.
|
11153
|
-
* - Returns a merged range of the first and the last if both are provided
|
11154
|
-
* and their lexers match.
|
11155
|
-
* - Otherwise, returns null.
|
11156
|
-
*/
|
11157
|
-
static range(first, second) {
|
11158
|
-
if (!second) {
|
11159
|
-
return first && first.loc;
|
11160
|
-
} else if (!first || !first.loc || !second.loc || first.loc.lexer !== second.loc.lexer) {
|
11161
|
-
return null;
|
11162
|
-
} else {
|
11163
|
-
return new SourceLocation(first.loc.lexer, first.loc.start, second.loc.end);
|
11164
|
-
}
|
11165
|
-
}
|
11166
|
-
}
|
11167
|
-
|
11168
|
-
/**
|
11169
|
-
* Interface required to break circular dependency between Token, Lexer, and
|
11170
|
-
* ParseError.
|
11171
|
-
*/
|
11172
|
-
|
11173
|
-
/**
|
11174
|
-
* The resulting token returned from `lex`.
|
11175
|
-
*
|
11176
|
-
* It consists of the token text plus some position information.
|
11177
|
-
* The position information is essentially a range in an input string,
|
11178
|
-
* but instead of referencing the bare input string, we refer to the lexer.
|
11179
|
-
* That way it is possible to attach extra metadata to the input string,
|
11180
|
-
* like for example a file name or similar.
|
11181
|
-
*
|
11182
|
-
* The position information is optional, so it is OK to construct synthetic
|
11183
|
-
* tokens if appropriate. Not providing available position information may
|
11184
|
-
* lead to degraded error reporting, though.
|
11185
|
-
*/
|
11186
|
-
class Token {
|
11187
|
-
constructor(
|
11188
|
-
text, // the text of this token
|
11189
|
-
loc
|
11190
|
-
) {
|
11191
|
-
this.text = text;
|
11192
|
-
this.loc = loc;
|
11193
|
-
}
|
11194
|
-
|
11195
|
-
/**
|
11196
|
-
* Given a pair of tokens (this and endToken), compute a `Token` encompassing
|
11197
|
-
* the whole input range enclosed by these two.
|
11198
|
-
*/
|
11199
|
-
range(
|
11200
|
-
endToken, // last token of the range, inclusive
|
11201
|
-
text // the text of the newly constructed token
|
11202
|
-
) {
|
11203
|
-
return new Token(text, SourceLocation.range(this, endToken));
|
11204
|
-
}
|
11205
|
-
}
|
11206
|
-
|
11207
11381
|
/**
|
11208
11382
|
* The Lexer class handles tokenizing the input in various ways. Since our
|
11209
11383
|
* parser expects us to be able to backtrack, the lexer allows lexing from any
|
@@ -13367,9 +13541,11 @@ class Style {
|
|
13367
13541
|
constructor(data) {
|
13368
13542
|
// Style.level can be 0 | 1 | 2 | 3, which correspond to
|
13369
13543
|
// displaystyle, textstyle, scriptstyle, and scriptscriptstyle.
|
13370
|
-
// style.level does not directly set MathML's script level. MathML does that itself.
|
13371
|
-
//
|
13372
|
-
//
|
13544
|
+
// style.level usually does not directly set MathML's script level. MathML does that itself.
|
13545
|
+
// However, Chromium does not stop shrinking after scriptscriptstyle, so we do explicitly
|
13546
|
+
// set a scriptlevel attribute in those conditions.
|
13547
|
+
// We also use style.level to track math style so that we can get the correct
|
13548
|
+
// scriptlevel when needed in supsub.js, mathchoice.js, or for dimensions in em.
|
13373
13549
|
this.level = data.level;
|
13374
13550
|
this.color = data.color; // string | void
|
13375
13551
|
// A font family applies to a group of fonts (i.e. SansSerif), while a font
|
@@ -13493,42 +13669,51 @@ class Style {
|
|
13493
13669
|
}
|
13494
13670
|
|
13495
13671
|
/* Temml Post Process
|
13496
|
-
*
|
13497
|
-
* Given a block,
|
13498
|
-
* 1. At each AMS auto-numbered environment, assign an id.
|
13499
|
-
* 2. Populate the text contents of each \ref & \eqref
|
13672
|
+
* Populate the text contents of each \ref & \eqref
|
13500
13673
|
*
|
13501
13674
|
* As with other Temml code, this file is released under terms of the MIT license.
|
13502
13675
|
* https://mit-license.org/
|
13503
13676
|
*/
|
13504
13677
|
|
13505
|
-
const version = "0.10.
|
13678
|
+
const version = "0.10.34";
|
13506
13679
|
|
13507
13680
|
function postProcess(block) {
|
13508
13681
|
const labelMap = {};
|
13509
13682
|
let i = 0;
|
13510
13683
|
|
13511
13684
|
// Get a collection of the parents of each \tag & auto-numbered equation
|
13512
|
-
const
|
13513
|
-
for (
|
13514
|
-
|
13515
|
-
|
13516
|
-
|
13517
|
-
|
13518
|
-
|
13519
|
-
|
13520
|
-
|
13521
|
-
|
13685
|
+
const amsEqns = document.getElementsByClassName('tml-eqn');
|
13686
|
+
for (let parent of amsEqns) {
|
13687
|
+
// AMS automatically numbered equation.
|
13688
|
+
// Assign an id.
|
13689
|
+
i += 1;
|
13690
|
+
parent.setAttribute("id", "tml-eqn-" + String(i));
|
13691
|
+
// No need to write a number into the text content of the element.
|
13692
|
+
// A CSS counter has done that even if this postProcess() function is not used.
|
13693
|
+
|
13694
|
+
// Find any \label that refers to an AMS automatic eqn number.
|
13695
|
+
while (true) {
|
13696
|
+
if (parent.tagName === "mtable") { break }
|
13697
|
+
const labels = parent.getElementsByClassName("tml-label");
|
13698
|
+
if (labels.length > 0) {
|
13699
|
+
const id = parent.attributes.id.value;
|
13700
|
+
labelMap[id] = String(i);
|
13701
|
+
break
|
13702
|
+
} else {
|
13703
|
+
parent = parent.parentElement;
|
13704
|
+
}
|
13522
13705
|
}
|
13523
|
-
|
13706
|
+
}
|
13707
|
+
|
13708
|
+
// Find \labels associated with \tag
|
13709
|
+
const taggedEqns = document.getElementsByClassName('tml-tageqn');
|
13710
|
+
for (const parent of taggedEqns) {
|
13524
13711
|
const labels = parent.getElementsByClassName("tml-label");
|
13525
|
-
if (labels.length
|
13526
|
-
if (eqns.length > 0) {
|
13527
|
-
labelMap[labels[0].id] = String(i);
|
13528
|
-
} else {
|
13712
|
+
if (labels.length > 0) {
|
13529
13713
|
const tags = parent.getElementsByClassName("tml-tag");
|
13530
13714
|
if (tags.length > 0) {
|
13531
|
-
|
13715
|
+
const id = parent.attributes.id.value;
|
13716
|
+
labelMap[id] = tags[0].textContent;
|
13532
13717
|
}
|
13533
13718
|
}
|
13534
13719
|
}
|
@@ -13536,17 +13721,22 @@ function postProcess(block) {
|
|
13536
13721
|
// Populate \ref & \eqref text content
|
13537
13722
|
const refs = block.getElementsByClassName("tml-ref");
|
13538
13723
|
[...refs].forEach(ref => {
|
13539
|
-
|
13724
|
+
const attr = ref.getAttribute("href");
|
13725
|
+
let str = labelMap[attr.slice(1)];
|
13540
13726
|
if (ref.className.indexOf("tml-eqref") === -1) {
|
13541
13727
|
// \ref. Omit parens.
|
13542
13728
|
str = str.replace(/^\(/, "");
|
13543
|
-
str = str.replace(/\
|
13544
|
-
}
|
13729
|
+
str = str.replace(/\)$/, "");
|
13730
|
+
} else {
|
13545
13731
|
// \eqref. Include parens
|
13546
13732
|
if (str.charAt(0) !== "(") { str = "(" + str; }
|
13547
13733
|
if (str.slice(-1) !== ")") { str = str + ")"; }
|
13548
13734
|
}
|
13549
|
-
|
13735
|
+
const mtext = document.createElementNS("http://www.w3.org/1998/Math/MathML", "mtext");
|
13736
|
+
mtext.appendChild(document.createTextNode(str));
|
13737
|
+
const math = document.createElementNS("http://www.w3.org/1998/Math/MathML", "math");
|
13738
|
+
math.appendChild(mtext);
|
13739
|
+
ref.appendChild(math);
|
13550
13740
|
});
|
13551
13741
|
}
|
13552
13742
|
|