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