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/dist/temml.js CHANGED
@@ -502,6 +502,40 @@ var temml = (function () {
502
502
  }
503
503
  };
504
504
 
505
+ // Create an <a href="…"> node.
506
+ class AnchorNode {
507
+ constructor(href, classes, children) {
508
+ this.href = href;
509
+ this.classes = classes;
510
+ this.children = children || [];
511
+ }
512
+
513
+ toNode() {
514
+ const node = document.createElement("a");
515
+ node.setAttribute("href", this.href);
516
+ if (this.classes.length > 0) {
517
+ node.className = createClass(this.classes);
518
+ }
519
+ for (let i = 0; i < this.children.length; i++) {
520
+ node.appendChild(this.children[i].toNode());
521
+ }
522
+ return node
523
+ }
524
+
525
+ toMarkup() {
526
+ let markup = `<a href='${utils.escape(this.href)}'`;
527
+ if (this.classes.length > 0) {
528
+ markup += ` class="${utils.escape(createClass(this.classes))}"`;
529
+ }
530
+ markup += ">";
531
+ for (let i = 0; i < this.children.length; i++) {
532
+ markup += this.children[i].toMarkup();
533
+ }
534
+ markup += "</a>";
535
+ return markup
536
+ }
537
+ }
538
+
505
539
  /*
506
540
  * This node represents an image embed (<img>) element.
507
541
  */
@@ -576,6 +610,7 @@ var temml = (function () {
576
610
  this.children = children || [];
577
611
  this.classes = classes || [];
578
612
  this.style = style || {}; // Used for <mstyle> elements
613
+ this.label = "";
579
614
  }
580
615
 
581
616
  /**
@@ -593,6 +628,10 @@ var temml = (function () {
593
628
  return this.attributes[name];
594
629
  }
595
630
 
631
+ setLabel(value) {
632
+ this.label = value;
633
+ }
634
+
596
635
  /**
597
636
  * Converts the math node into a MathML-namespaced DOM element.
598
637
  */
@@ -1509,7 +1548,7 @@ var temml = (function () {
1509
1548
  defineSymbol(math, mathord, "\u2aeb", "\\Bot");
1510
1549
  defineSymbol(math, bin, "\u2217", "\u2217", true);
1511
1550
  defineSymbol(math, bin, "+", "+");
1512
- defineSymbol(math, bin, "*", "*");
1551
+ defineSymbol(math, bin, "\u2217", "*");
1513
1552
  defineSymbol(math, bin, "\u2044", "/", true);
1514
1553
  defineSymbol(math, bin, "\u2044", "\u2044");
1515
1554
  defineSymbol(math, bin, "\u2212", "-", true);
@@ -1531,7 +1570,7 @@ var temml = (function () {
1531
1570
  defineSymbol(math, open, "\u27ea", "\\lAngle", true);
1532
1571
  defineSymbol(math, open, "\u2989", "\\llangle", true);
1533
1572
  defineSymbol(math, open, "|", "\\lvert");
1534
- defineSymbol(math, open, "\u2016", "\\lVert");
1573
+ defineSymbol(math, open, "\u2016", "\\lVert", true);
1535
1574
  defineSymbol(math, textord, "!", "\\oc"); // cmll package
1536
1575
  defineSymbol(math, textord, "?", "\\wn");
1537
1576
  defineSymbol(math, textord, "\u2193", "\\shpos");
@@ -1695,7 +1734,7 @@ var temml = (function () {
1695
1734
  defineSymbol(math, inner, "\u22ef", "\\@cdots", true);
1696
1735
  defineSymbol(math, inner, "\u22f1", "\\ddots", true);
1697
1736
  defineSymbol(math, textord, "\u22ee", "\\varvdots"); // \vdots is a macro
1698
- defineSymbol(text, textord, "\u22ee", "\\textvdots");
1737
+ defineSymbol(text, textord, "\u22ee", "\\varvdots");
1699
1738
  defineSymbol(math, accent, "\u02ca", "\\acute");
1700
1739
  defineSymbol(math, accent, "\u0060", "\\grave");
1701
1740
  defineSymbol(math, accent, "\u00a8", "\\ddot");
@@ -2148,61 +2187,6 @@ var temml = (function () {
2148
2187
  }
2149
2188
  };
2150
2189
 
2151
- const numberRegEx$1 = /^[0-9]$/;
2152
- const isDotOrComma = (node, followingNode) => {
2153
- return ((node.type === "textord" && node.text === ".") ||
2154
- (node.type === "atom" && node.text === ",")) &&
2155
- // Don't consolidate if there is a space after the comma.
2156
- node.loc && followingNode.loc && node.loc.end === followingNode.loc.start
2157
- };
2158
- const consolidateNumbers = expression => {
2159
- // Consolidate adjacent numbers. We want to return <mn>1,506.3</mn>,
2160
- // not <mn>1</mn><mo>,</mo><mn>5</mn><mn>0</mn><mn>6</mn><mi>.</mi><mn>3</mn>
2161
- if (expression.length < 2) { return }
2162
- const nums = [];
2163
- let inNum = false;
2164
- // Find adjacent numerals
2165
- for (let i = 0; i < expression.length; i++) {
2166
- const node = expression[i];
2167
- if (node.type === "textord" && numberRegEx$1.test(node.text)) {
2168
- if (!inNum) { nums.push({ start: i }); }
2169
- inNum = true;
2170
- } else {
2171
- if (inNum) { nums[nums.length - 1].end = i - 1; }
2172
- inNum = false;
2173
- }
2174
- }
2175
- if (inNum) { nums[nums.length - 1].end = expression.length - 1; }
2176
-
2177
- // Determine if numeral groups are separated by a comma or dot.
2178
- for (let i = nums.length - 1; i > 0; i--) {
2179
- if (nums[i - 1].end === nums[i].start - 2 &&
2180
- isDotOrComma(expression[nums[i].start - 1], expression[nums[i].start])) {
2181
- // Merge the two groups.
2182
- nums[i - 1].end = nums[i].end;
2183
- nums.splice(i, 1);
2184
- }
2185
- }
2186
-
2187
- // Consolidate the number nodes
2188
- for (let i = nums.length - 1; i >= 0; i--) {
2189
- for (let j = nums[i].start + 1; j <= nums[i].end; j++) {
2190
- expression[nums[i].start].text += expression[j].text;
2191
- }
2192
- expression.splice(nums[i].start + 1, nums[i].end - nums[i].start);
2193
- // Check if the <mn> is followed by a numeric base in a supsub, e.g. the "3" in 123^4
2194
- // If so, merge the first <mn> into the base.
2195
- if (expression.length > nums[i].start + 1) {
2196
- const nextTerm = expression[nums[i].start + 1];
2197
- if (nextTerm.type === "supsub" && nextTerm.base && nextTerm.base.type === "textord" &&
2198
- numberRegEx$1.test(nextTerm.base.text)) {
2199
- nextTerm.base.text = expression[nums[i].start].text + nextTerm.base.text;
2200
- expression.splice(nums[i].start, 1);
2201
- }
2202
- }
2203
- }
2204
- };
2205
-
2206
2190
  /**
2207
2191
  * Wrap the given array of nodes in an <mrow> node if needed, i.e.,
2208
2192
  * unless the array has length 1. Always returns a single node.
@@ -2225,6 +2209,39 @@ var temml = (function () {
2225
2209
  return new mathMLTree.MathNode("mrow", body);
2226
2210
  };
2227
2211
 
2212
+ /**
2213
+ * Check for <mi>.</mi> which is how a dot renders in MathML,
2214
+ * or <mo separator="true" lspace="0em" rspace="0em">,</mo>
2215
+ * which is how a braced comma {,} renders in MathML
2216
+ */
2217
+ function isNumberPunctuation(group) {
2218
+ if (!group) {
2219
+ return false
2220
+ }
2221
+ if (group.type === 'mi' && group.children.length === 1) {
2222
+ const child = group.children[0];
2223
+ return child instanceof TextNode && child.text === '.'
2224
+ } else if (group.type === "mtext" && group.children.length === 1) {
2225
+ const child = group.children[0];
2226
+ return child instanceof TextNode && child.text === '\u2008' // punctuation space
2227
+ } else if (group.type === 'mo' && group.children.length === 1 &&
2228
+ group.getAttribute('separator') === 'true' &&
2229
+ group.getAttribute('lspace') === '0em' &&
2230
+ group.getAttribute('rspace') === '0em') {
2231
+ const child = group.children[0];
2232
+ return child instanceof TextNode && child.text === ','
2233
+ } else {
2234
+ return false
2235
+ }
2236
+ }
2237
+ const isComma = (expression, i) => {
2238
+ const node = expression[i];
2239
+ const followingNode = expression[i + 1];
2240
+ return (node.type === "atom" && node.text === ",") &&
2241
+ // Don't consolidate if there is a space after the comma.
2242
+ node.loc && followingNode.loc && node.loc.end === followingNode.loc.start
2243
+ };
2244
+
2228
2245
  const isRel = item => {
2229
2246
  return (item.type === "atom" && item.family === "rel") ||
2230
2247
  (item.type === "mclass" && item.mclass === "mrel")
@@ -2248,11 +2265,16 @@ var temml = (function () {
2248
2265
  return [group];
2249
2266
  }
2250
2267
 
2251
- consolidateNumbers(expression);
2252
-
2253
2268
  const groups = [];
2269
+ const groupArray = [];
2270
+ let lastGroup;
2254
2271
  for (let i = 0; i < expression.length; i++) {
2255
- const group = buildGroup$1(expression[i], style);
2272
+ groupArray.push(buildGroup$1(expression[i], style));
2273
+ }
2274
+
2275
+ for (let i = 0; i < groupArray.length; i++) {
2276
+ const group = groupArray[i];
2277
+
2256
2278
  // Suppress spacing between adjacent relations
2257
2279
  if (i < expression.length - 1 && isRel(expression[i]) && isRel(expression[i + 1])) {
2258
2280
  group.setAttribute("rspace", "0em");
@@ -2260,9 +2282,39 @@ var temml = (function () {
2260
2282
  if (i > 0 && isRel(expression[i]) && isRel(expression[i - 1])) {
2261
2283
  group.setAttribute("lspace", "0em");
2262
2284
  }
2285
+
2286
+ // Concatenate numbers
2287
+ if (group.type === 'mn' && lastGroup && lastGroup.type === 'mn') {
2288
+ // Concatenate <mn>...</mn> followed by <mi>.</mi>
2289
+ lastGroup.children.push(...group.children);
2290
+ continue
2291
+ } else if (isNumberPunctuation(group) && lastGroup && lastGroup.type === 'mn') {
2292
+ // Concatenate <mn>...</mn> followed by <mi>.</mi>
2293
+ lastGroup.children.push(...group.children);
2294
+ continue
2295
+ } else if (lastGroup && lastGroup.type === "mn" && i < groupArray.length - 1 &&
2296
+ groupArray[i + 1].type === "mn" && isComma(expression, i)) {
2297
+ lastGroup.children.push(...group.children);
2298
+ continue
2299
+ } else if (group.type === 'mn' && isNumberPunctuation(lastGroup)) {
2300
+ // Concatenate <mi>.</mi> followed by <mn>...</mn>
2301
+ group.children = [...lastGroup.children, ...group.children];
2302
+ groups.pop();
2303
+ } else if ((group.type === 'msup' || group.type === 'msub') &&
2304
+ group.children.length >= 1 && lastGroup &&
2305
+ (lastGroup.type === 'mn' || isNumberPunctuation(lastGroup))) {
2306
+ // Put preceding <mn>...</mn> or <mi>.</mi> inside base of
2307
+ // <msup><mn>...base...</mn>...exponent...</msup> (or <msub>)
2308
+ const base = group.children[0];
2309
+ if (base instanceof MathNode && base.type === 'mn' && lastGroup) {
2310
+ base.children = [...lastGroup.children, ...base.children];
2311
+ groups.pop();
2312
+ }
2313
+ }
2263
2314
  groups.push(group);
2315
+ lastGroup = group;
2264
2316
  }
2265
- return groups;
2317
+ return groups
2266
2318
  };
2267
2319
 
2268
2320
  /**
@@ -2295,16 +2347,36 @@ var temml = (function () {
2295
2347
  return new mathMLTree.MathNode("mtd", [], [], { padding: "0", width: "50%" })
2296
2348
  };
2297
2349
 
2350
+ const labelContainers = ["mrow", "mtd", "mtable", "mtr"];
2351
+ const getLabel = parent => {
2352
+ for (const node of parent.children) {
2353
+ if (node.type && labelContainers.includes(node.type)) {
2354
+ if (node.classes && node.classes[0] === "tml-label") {
2355
+ const label = node.label;
2356
+ return label
2357
+ } else {
2358
+ const label = getLabel(node);
2359
+ if (label) { return label }
2360
+ }
2361
+ } else if (!node.type) {
2362
+ const label = getLabel(node);
2363
+ if (label) { return label }
2364
+ }
2365
+ }
2366
+ };
2367
+
2298
2368
  const taggedExpression = (expression, tag, style, leqno) => {
2299
2369
  tag = buildExpressionRow(tag[0].body, style);
2300
2370
  tag = consolidateText(tag);
2301
2371
  tag.classes.push("tml-tag");
2302
2372
 
2373
+ const label = getLabel(expression); // from a \label{} function.
2303
2374
  expression = new mathMLTree.MathNode("mtd", [expression]);
2304
2375
  const rowArray = [glue$1(), expression, glue$1()];
2305
2376
  rowArray[leqno ? 0 : 2].classes.push(leqno ? "tml-left" : "tml-right");
2306
2377
  rowArray[leqno ? 0 : 2].children.push(tag);
2307
2378
  const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"]);
2379
+ if (label) { mtr.setAttribute("id", label); }
2308
2380
  const table = new mathMLTree.MathNode("mtable", [mtr]);
2309
2381
  table.style.width = "100%";
2310
2382
  table.setAttribute("displaystyle", "true");
@@ -2324,6 +2396,11 @@ var temml = (function () {
2324
2396
  }
2325
2397
 
2326
2398
  const expression = buildExpression(tree, style);
2399
+
2400
+ if (expression.length === 1 && expression[0] instanceof AnchorNode) {
2401
+ return expression[0]
2402
+ }
2403
+
2327
2404
  const wrap = (settings.displayMode || settings.annotate) ? "none" : settings.wrap;
2328
2405
 
2329
2406
  const n1 = expression.length === 0 ? null : expression[0];
@@ -2348,6 +2425,9 @@ var temml = (function () {
2348
2425
  if (settings.xml) {
2349
2426
  math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML");
2350
2427
  }
2428
+ if (wrapper.style.width) {
2429
+ math.style.width = "100%";
2430
+ }
2351
2431
  if (settings.displayMode) {
2352
2432
  math.setAttribute("display", "block");
2353
2433
  math.style.display = "block math"; // necessary in Chromium.
@@ -2679,12 +2759,19 @@ var temml = (function () {
2679
2759
  return node
2680
2760
  };
2681
2761
 
2682
- const paddedNode = (group, lspace = 0.3, rspace = 0) => {
2762
+ const paddedNode = (group, lspace = 0.3, rspace = 0, mustSmash = false) => {
2683
2763
  if (group == null && rspace === 0) { return padding$2(lspace) }
2684
2764
  const row = group ? [group] : [];
2685
2765
  if (lspace !== 0) { row.unshift(padding$2(lspace)); }
2686
2766
  if (rspace > 0) { row.push(padding$2(rspace)); }
2687
- return new mathMLTree.MathNode("mrow", row)
2767
+ if (mustSmash) {
2768
+ // Used for the bottom arrow in a {CD} environment
2769
+ const mpadded = new mathMLTree.MathNode("mpadded", row);
2770
+ mpadded.setAttribute("height", "0");
2771
+ return mpadded
2772
+ } else {
2773
+ return new mathMLTree.MathNode("mrow", row)
2774
+ }
2688
2775
  };
2689
2776
 
2690
2777
  const labelSize = (size, scriptLevel) => Number(size) / emScale(scriptLevel);
@@ -2724,7 +2811,8 @@ var temml = (function () {
2724
2811
  (body.body.body || body.body.length > 0));
2725
2812
  if (gotUpper) {
2726
2813
  let label = buildGroup$1(body, labelStyle);
2727
- label = paddedNode(label, space, space);
2814
+ const mustSmash = (fName === "\\\\cdrightarrow" || fName === "\\\\cdleftarrow");
2815
+ label = paddedNode(label, space, space, mustSmash);
2728
2816
  // Since Firefox does not support minsize, stack a invisible node
2729
2817
  // on top of the label. Its width will serve as a min-width.
2730
2818
  // TODO: Refactor this after Firefox supports minsize.
@@ -3119,6 +3207,8 @@ var temml = (function () {
3119
3207
  type: "array",
3120
3208
  mode: "math",
3121
3209
  body,
3210
+ tags: null,
3211
+ labels: new Array(body.length + 1).fill(""),
3122
3212
  envClasses: ["jot", "cd"],
3123
3213
  cols: [],
3124
3214
  hLinesBeforeRow: new Array(body.length + 1).fill([])
@@ -3147,18 +3237,23 @@ var temml = (function () {
3147
3237
  };
3148
3238
  },
3149
3239
  mathmlBuilder(group, style) {
3150
- let label = new mathMLTree.MathNode("mrow", [buildGroup$1(group.label, style)]);
3151
- label = new mathMLTree.MathNode("mpadded", [label]);
3152
- label.setAttribute("width", "0");
3153
- if (group.side === "left") {
3154
- label.setAttribute("lspace", "-1width");
3240
+ if (group.label.body.length === 0) {
3241
+ return new mathMLTree.MathNode("mrow", style) // empty label
3155
3242
  }
3156
- // We have to guess at vertical alignment. We know the arrow is 1.8em tall,
3157
- // But we don't know the height or depth of the label.
3158
- label.setAttribute("voffset", "0.7em");
3159
- label = new mathMLTree.MathNode("mstyle", [label]);
3243
+ // Abuse an <mtable> to create vertically centered content.
3244
+ const mtd = new mathMLTree.MathNode("mtd", [buildGroup$1(group.label, style)]);
3245
+ mtd.style.padding = "0";
3246
+ const mtr = new mathMLTree.MathNode("mtr", [mtd]);
3247
+ const mtable = new mathMLTree.MathNode("mtable", [mtr]);
3248
+ const label = new mathMLTree.MathNode("mpadded", [mtable]);
3249
+ // Set the label width to zero so that the arrow will be centered under the corner cell.
3250
+ label.setAttribute("width", "0");
3160
3251
  label.setAttribute("displaystyle", "false");
3161
3252
  label.setAttribute("scriptlevel", "1");
3253
+ if (group.side === "left") {
3254
+ label.style.display = "flex";
3255
+ label.style.justifyContent = "flex-end";
3256
+ }
3162
3257
  return label;
3163
3258
  }
3164
3259
  });
@@ -3748,10 +3843,13 @@ var temml = (function () {
3748
3843
  // replacement text, enclosed in '{' and '}' and properly nested
3749
3844
  const { tokens } = parser.gullet.consumeArg();
3750
3845
 
3751
- parser.gullet.macros.set(
3752
- name,
3753
- { tokens, numArgs }
3754
- );
3846
+ if (!(funcName === "\\providecommand" && parser.gullet.macros.has(name))) {
3847
+ // Ignore \providecommand
3848
+ parser.gullet.macros.set(
3849
+ name,
3850
+ { tokens, numArgs }
3851
+ );
3852
+ }
3755
3853
 
3756
3854
  return { type: "internal", mode: parser.mode };
3757
3855
 
@@ -3845,6 +3943,7 @@ var temml = (function () {
3845
3943
  "\\vert",
3846
3944
  "\\|",
3847
3945
  "\\Vert",
3946
+ "\u2016",
3848
3947
  "\\uparrow",
3849
3948
  "\\Uparrow",
3850
3949
  "\\downarrow",
@@ -4350,6 +4449,75 @@ var temml = (function () {
4350
4449
  }
4351
4450
  }
4352
4451
 
4452
+ /**
4453
+ * Lexing or parsing positional information for error reporting.
4454
+ * This object is immutable.
4455
+ */
4456
+ class SourceLocation {
4457
+ constructor(lexer, start, end) {
4458
+ this.lexer = lexer; // Lexer holding the input string.
4459
+ this.start = start; // Start offset, zero-based inclusive.
4460
+ this.end = end; // End offset, zero-based exclusive.
4461
+ }
4462
+
4463
+ /**
4464
+ * Merges two `SourceLocation`s from location providers, given they are
4465
+ * provided in order of appearance.
4466
+ * - Returns the first one's location if only the first is provided.
4467
+ * - Returns a merged range of the first and the last if both are provided
4468
+ * and their lexers match.
4469
+ * - Otherwise, returns null.
4470
+ */
4471
+ static range(first, second) {
4472
+ if (!second) {
4473
+ return first && first.loc;
4474
+ } else if (!first || !first.loc || !second.loc || first.loc.lexer !== second.loc.lexer) {
4475
+ return null;
4476
+ } else {
4477
+ return new SourceLocation(first.loc.lexer, first.loc.start, second.loc.end);
4478
+ }
4479
+ }
4480
+ }
4481
+
4482
+ /**
4483
+ * Interface required to break circular dependency between Token, Lexer, and
4484
+ * ParseError.
4485
+ */
4486
+
4487
+ /**
4488
+ * The resulting token returned from `lex`.
4489
+ *
4490
+ * It consists of the token text plus some position information.
4491
+ * The position information is essentially a range in an input string,
4492
+ * but instead of referencing the bare input string, we refer to the lexer.
4493
+ * That way it is possible to attach extra metadata to the input string,
4494
+ * like for example a file name or similar.
4495
+ *
4496
+ * The position information is optional, so it is OK to construct synthetic
4497
+ * tokens if appropriate. Not providing available position information may
4498
+ * lead to degraded error reporting, though.
4499
+ */
4500
+ class Token {
4501
+ constructor(
4502
+ text, // the text of this token
4503
+ loc
4504
+ ) {
4505
+ this.text = text;
4506
+ this.loc = loc;
4507
+ }
4508
+
4509
+ /**
4510
+ * Given a pair of tokens (this and endToken), compute a `Token` encompassing
4511
+ * the whole input range enclosed by these two.
4512
+ */
4513
+ range(
4514
+ endToken, // last token of the range, inclusive
4515
+ text // the text of the newly constructed token
4516
+ ) {
4517
+ return new Token(text, SourceLocation.range(this, endToken));
4518
+ }
4519
+ }
4520
+
4353
4521
  // In TeX, there are actually three sets of dimensions, one for each of
4354
4522
  // textstyle, scriptstyle, and scriptscriptstyle. These are
4355
4523
  // provided in the the arrays below, in that order.
@@ -4614,7 +4782,7 @@ var temml = (function () {
4614
4782
  // \kern6\p@\hbox{.}\hbox{.}\hbox{.}}}
4615
4783
  // We'll call \varvdots, which gets a glyph from symbols.js.
4616
4784
  // The zero-width rule gets us an equivalent to the vertical 6pt kern.
4617
- defineMacro("\\vdots", "\\TextOrMath{\\textvdots}{{\\varvdots\\rule{0pt}{15pt}}}\\relax");
4785
+ defineMacro("\\vdots", "{\\varvdots\\rule{0pt}{15pt}}");
4618
4786
  defineMacro("\u22ee", "\\vdots");
4619
4787
 
4620
4788
  // {array} environment gaps
@@ -4834,8 +5002,10 @@ var temml = (function () {
4834
5002
  if (context.macros.get("\\df@tag")) {
4835
5003
  throw new ParseError("Multiple \\tag");
4836
5004
  }
4837
- return "\\def\\df@tag{\\text{#1}}";
5005
+ return "\\gdef\\df@tag{\\text{#1}}";
4838
5006
  });
5007
+ defineMacro("\\notag", "\\nonumber");
5008
+ defineMacro("\\nonumber", "\\gdef\\@eqnsw{0}");
4839
5009
 
4840
5010
  // \renewcommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin
4841
5011
  // {\operator@font mod}\penalty900
@@ -5125,33 +5295,30 @@ var temml = (function () {
5125
5295
  return [arraystretch, arraycolsep]
5126
5296
  };
5127
5297
 
5128
- const getTag = (group, style, rowNum) => {
5129
- let tag;
5130
- const tagContents = group.tags.shift();
5131
- if (tagContents) {
5132
- // The author has written a \tag or a \notag in this row.
5133
- if (tagContents.body) {
5134
- tag = buildExpressionRow(tagContents.body, style, true);
5135
- tag.classes = ["tml-tag"];
5136
- } else {
5137
- // \notag. Return an empty span.
5138
- tag = new mathMLTree.MathNode("mtext", [], []);
5139
- return tag
5140
- }
5141
- } else if (group.envClasses.includes("multline") &&
5142
- ((group.leqno && rowNum !== 0) || (!group.leqno && rowNum !== group.body.length - 1))) {
5143
- // A multiline that does not receive a tag. Return an empty cell.
5144
- tag = new mathMLTree.MathNode("mtext", [], []);
5145
- return tag
5146
- } else {
5147
- // AMS automatcally numbered equaton.
5148
- // Insert a class so the element can be populated by a CSS counter.
5149
- // WebKit will display the CSS counter only inside a span.
5150
- tag = new mathMLTree.MathNode("mtext", [new Span(["tml-eqn"])]);
5298
+ const checkCellForLabels = cell => {
5299
+ // Check if the author wrote a \tag{} inside this cell.
5300
+ let rowLabel = "";
5301
+ for (let i = 0; i < cell.length; i++) {
5302
+ if (cell[i].type === "label") {
5303
+ if (rowLabel) { throw new ParseError(("Multiple \\labels in one row")) }
5304
+ rowLabel = cell[i].string;
5305
+ }
5151
5306
  }
5152
- return tag
5307
+ return rowLabel
5153
5308
  };
5154
5309
 
5310
+ // autoTag (an argument to parseArray) can be one of three values:
5311
+ // * undefined: Regular (not-top-level) array; no tags on each row
5312
+ // * true: Automatic equation numbering, overridable by \tag
5313
+ // * false: Tags allowed on each row, but no automatic numbering
5314
+ // This function *doesn't* work with the "split" environment name.
5315
+ function getAutoTag(name) {
5316
+ if (name.indexOf("ed") === -1) {
5317
+ return name.indexOf("*") === -1;
5318
+ }
5319
+ // return undefined;
5320
+ }
5321
+
5155
5322
  /**
5156
5323
  * Parse the body of the environment, with rows delimited by \\ and
5157
5324
  * columns delimited by &, and create a nested list in row-major order
@@ -5163,7 +5330,7 @@ var temml = (function () {
5163
5330
  {
5164
5331
  cols, // [{ type: string , align: l|c|r|null }]
5165
5332
  envClasses, // align(ed|at|edat) | array | cases | cd | small | multline
5166
- addEqnNum, // boolean
5333
+ autoTag, // boolean
5167
5334
  singleRow, // boolean
5168
5335
  emptySingleRow, // boolean
5169
5336
  maxNumCols, // number
@@ -5179,13 +5346,6 @@ var temml = (function () {
5179
5346
  // TODO: provide helpful error when \cr is used outside array environment
5180
5347
  parser.gullet.macros.set("\\cr", "\\\\\\relax");
5181
5348
  }
5182
- if (addEqnNum) {
5183
- parser.gullet.macros.set("\\tag", "\\@ifstar\\envtag@literal\\envtag@paren");
5184
- parser.gullet.macros.set("\\envtag@paren", "\\env@tag{{(\\text{#1})}}");
5185
- parser.gullet.macros.set("\\envtag@literal", "\\env@tag{\\text{#1}}");
5186
- parser.gullet.macros.set("\\notag", "\\env@notag");
5187
- parser.gullet.macros.set("\\nonumber", "\\env@notag");
5188
- }
5189
5349
 
5190
5350
  // Start group for first cell
5191
5351
  parser.gullet.beginGroup();
@@ -5193,29 +5353,39 @@ var temml = (function () {
5193
5353
  let row = [];
5194
5354
  const body = [row];
5195
5355
  const rowGaps = [];
5196
- const tags = [];
5197
- let rowTag;
5356
+ const labels = [];
5357
+
5198
5358
  const hLinesBeforeRow = [];
5199
5359
 
5360
+ const tags = (autoTag != null ? [] : undefined);
5361
+
5362
+ // amsmath uses \global\@eqnswtrue and \global\@eqnswfalse to represent
5363
+ // whether this row should have an equation number. Simulate this with
5364
+ // a \@eqnsw macro set to 1 or 0.
5365
+ function beginRow() {
5366
+ if (autoTag) {
5367
+ parser.gullet.macros.set("\\@eqnsw", "1", true);
5368
+ }
5369
+ }
5370
+ function endRow() {
5371
+ if (tags) {
5372
+ if (parser.gullet.macros.get("\\df@tag")) {
5373
+ tags.push(parser.subparse([new Token("\\df@tag")]));
5374
+ parser.gullet.macros.set("\\df@tag", undefined, true);
5375
+ } else {
5376
+ tags.push(Boolean(autoTag) &&
5377
+ parser.gullet.macros.get("\\@eqnsw") === "1");
5378
+ }
5379
+ }
5380
+ }
5381
+ beginRow();
5382
+
5200
5383
  // Test for \hline at the top of the array.
5201
5384
  hLinesBeforeRow.push(getHLines(parser));
5202
5385
 
5203
5386
  while (true) {
5204
5387
  // Parse each cell in its own group (namespace)
5205
5388
  let cell = parser.parseExpression(false, singleRow ? "\\end" : "\\\\");
5206
-
5207
- if (addEqnNum && !rowTag) {
5208
- // Check if the author wrote a \tag{} inside this cell.
5209
- for (let i = 0; i < cell.length; i++) {
5210
- if (cell[i].type === "envTag" || cell[i].type === "noTag") {
5211
- // Get the contents of the \text{} nested inside the \env@Tag{}
5212
- rowTag = cell[i].type === "envTag"
5213
- ? cell.splice(i, 1)[0].body.body[0]
5214
- : { body: null };
5215
- break
5216
- }
5217
- }
5218
- }
5219
5389
  parser.gullet.endGroup();
5220
5390
  parser.gullet.beginGroup();
5221
5391
 
@@ -5244,6 +5414,7 @@ var temml = (function () {
5244
5414
  }
5245
5415
  parser.consume();
5246
5416
  } else if (next === "\\end") {
5417
+ endRow();
5247
5418
  // Arrays terminate newlines with `\crcr` which consumes a `\cr` if
5248
5419
  // the last line is empty. However, AMS environments keep the
5249
5420
  // empty row if it's the only one.
@@ -5251,6 +5422,7 @@ var temml = (function () {
5251
5422
  if (row.length === 1 && cell.body.length === 0 && (body.length > 1 || !emptySingleRow)) {
5252
5423
  body.pop();
5253
5424
  }
5425
+ labels.push(checkCellForLabels(cell.body));
5254
5426
  if (hLinesBeforeRow.length < body.length + 1) {
5255
5427
  hLinesBeforeRow.push([]);
5256
5428
  }
@@ -5267,15 +5439,16 @@ var temml = (function () {
5267
5439
  size = parser.parseSizeGroup(true);
5268
5440
  }
5269
5441
  rowGaps.push(size ? size.value : null);
5442
+ endRow();
5270
5443
 
5271
- tags.push(rowTag);
5444
+ labels.push(checkCellForLabels(cell.body));
5272
5445
 
5273
5446
  // check for \hline(s) following the row separator
5274
5447
  hLinesBeforeRow.push(getHLines(parser));
5275
5448
 
5276
5449
  row = [];
5277
- rowTag = null;
5278
5450
  body.push(row);
5451
+ beginRow();
5279
5452
  } else {
5280
5453
  throw new ParseError("Expected & or \\\\ or \\cr or \\end", parser.nextToken);
5281
5454
  }
@@ -5286,8 +5459,6 @@ var temml = (function () {
5286
5459
  // End array group defining \cr
5287
5460
  parser.gullet.endGroup();
5288
5461
 
5289
- tags.push(rowTag);
5290
-
5291
5462
  return {
5292
5463
  type: "array",
5293
5464
  mode: parser.mode,
@@ -5296,9 +5467,10 @@ var temml = (function () {
5296
5467
  rowGaps,
5297
5468
  hLinesBeforeRow,
5298
5469
  envClasses,
5299
- addEqnNum,
5470
+ autoTag,
5300
5471
  scriptLevel,
5301
5472
  tags,
5473
+ labels,
5302
5474
  leqno,
5303
5475
  arraystretch,
5304
5476
  arraycolsep
@@ -5355,19 +5527,43 @@ var temml = (function () {
5355
5527
  }
5356
5528
  row.push(mtd);
5357
5529
  }
5358
- if (group.addEqnNum) {
5359
- row.unshift(glue(group));
5360
- row.push(glue(group));
5361
- const tag = getTag(group, style.withLevel(cellLevel), i);
5362
- if (group.leqno) {
5363
- row[0].children.push(tag);
5364
- row[0].classes.push("tml-left");
5365
- } else {
5366
- row[row.length - 1].children.push(tag);
5367
- row[row.length - 1].classes.push("tml-right");
5530
+ const numColumns = group.body[0].length;
5531
+ // Fill out a short row with empty <mtd> elements.
5532
+ for (let k = 0; k < numColumns - rw.length; k++) {
5533
+ row.push(new mathMLTree.MathNode("mtd", [], style));
5534
+ }
5535
+ if (group.autoTag) {
5536
+ const tag = group.tags[i];
5537
+ let tagElement;
5538
+ if (tag === true) { // automatic numbering
5539
+ tagElement = new mathMLTree.MathNode("mtext", [new Span(["tml-eqn"])]);
5540
+ } else if (tag === false) {
5541
+ // \nonumber/\notag or starred environment
5542
+ tagElement = new mathMLTree.MathNode("mtext", [], []);
5543
+ } else { // manual \tag
5544
+ tagElement = buildExpressionRow(tag[0].body, style.withLevel(cellLevel), true);
5545
+ tagElement = consolidateText(tagElement);
5546
+ tagElement.classes = ["tml-tag"];
5547
+ }
5548
+ if (tagElement) {
5549
+ row.unshift(glue(group));
5550
+ row.push(glue(group));
5551
+ if (group.leqno) {
5552
+ row[0].children.push(tagElement);
5553
+ row[0].classes.push("tml-left");
5554
+ } else {
5555
+ row[row.length - 1].children.push(tagElement);
5556
+ row[row.length - 1].classes.push("tml-right");
5557
+ }
5368
5558
  }
5369
5559
  }
5370
5560
  const mtr = new mathMLTree.MathNode("mtr", row, []);
5561
+ const label = group.labels.shift();
5562
+ if (label && group.tags && group.tags[i]) {
5563
+ mtr.setAttribute("id", label);
5564
+ if (Array.isArray(group.tags[i])) { mtr.classes.push("tml-tageqn"); }
5565
+ }
5566
+
5371
5567
  // Write horizontal rules
5372
5568
  if (i === 0 && hlines[0].length > 0) {
5373
5569
  if (hlines[0].length === 2) {
@@ -5391,16 +5587,17 @@ var temml = (function () {
5391
5587
  }
5392
5588
 
5393
5589
  if (group.envClasses.length > 0) {
5394
- let pad = group.envClasses.includes("jot")
5395
- ? "0.7" // 0.5ex + 0.09em top & bot padding
5396
- : group.envClasses.includes("small")
5397
- ? "0.35"
5398
- : "0.5"; // 0.5ex default top & bot padding
5399
5590
  if (group.arraystretch && group.arraystretch !== 1) {
5400
5591
  // In LaTeX, \arraystretch is a factor applied to a 12pt strut height.
5401
5592
  // It defines a baseline to baseline distance.
5402
5593
  // Here, we do an approximation of that approach.
5403
- pad = String(1.4 * group.arraystretch - 0.8);
5594
+ const pad = String(1.4 * group.arraystretch - 0.8) + "ex";
5595
+ for (let i = 0; i < tbl.length; i++) {
5596
+ for (let j = 0; j < tbl[i].children.length; j++) {
5597
+ tbl[i].children[j].style.paddingTop = pad;
5598
+ tbl[i].children[j].style.paddingBottom = pad;
5599
+ }
5600
+ }
5404
5601
  }
5405
5602
  let sidePadding = group.envClasses.includes("abut")
5406
5603
  ? "0"
@@ -5414,7 +5611,7 @@ var temml = (function () {
5414
5611
  let sidePadUnit = "em";
5415
5612
  if (group.arraycolsep) {
5416
5613
  const arraySidePad = calculateSize(group.arraycolsep, style);
5417
- sidePadding = arraySidePad.number;
5614
+ sidePadding = arraySidePad.number.toFixed(4);
5418
5615
  sidePadUnit = arraySidePad.unit;
5419
5616
  }
5420
5617
 
@@ -5425,18 +5622,18 @@ var temml = (function () {
5425
5622
  if (j === numCols - 1 && hand === 1) { return "0" }
5426
5623
  if (group.envClasses[0] !== "align") { return sidePadding }
5427
5624
  if (hand === 1) { return "0" }
5428
- if (group.addEqnNum) {
5625
+ if (group.autoTag) {
5429
5626
  return (j % 2) ? "1" : "0"
5430
5627
  } else {
5431
5628
  return (j % 2) ? "0" : "1"
5432
5629
  }
5433
5630
  };
5434
5631
 
5435
- // Padding
5632
+ // Side padding
5436
5633
  for (let i = 0; i < tbl.length; i++) {
5437
5634
  for (let j = 0; j < tbl[i].children.length; j++) {
5438
- tbl[i].children[j].style.padding = `${pad}ex ${sidePad(j, 1)}${sidePadUnit}`
5439
- + ` ${pad}ex ${sidePad(j, 0)}${sidePadUnit}`;
5635
+ tbl[i].children[j].style.paddingLeft = `${sidePad(j, 0)}${sidePadUnit}`;
5636
+ tbl[i].children[j].style.paddingRight = `${sidePad(j, 1)}${sidePadUnit}`;
5440
5637
  }
5441
5638
  }
5442
5639
 
@@ -5450,13 +5647,13 @@ var temml = (function () {
5450
5647
  // TODO: Remove -webkit- when Chromium no longer needs it.
5451
5648
  row.children[j].classes = ["tml-" + (j % 2 ? "left" : "right")];
5452
5649
  }
5453
- if (group.addEqnNum) {
5650
+ if (group.autoTag) {
5454
5651
  const k = group.leqno ? 0 : row.children.length - 1;
5455
5652
  row.children[k].classes = ["tml-" + (group.leqno ? "left" : "right")];
5456
5653
  }
5457
5654
  }
5458
5655
  if (row.children.length > 1 && group.envClasses.includes("cases")) {
5459
- row.children[1].style.padding = row.children[1].style.padding.replace(/0em$/, "1em");
5656
+ row.children[1].style.paddingLeft = "1em";
5460
5657
  }
5461
5658
 
5462
5659
  if (group.envClasses.includes("cases") || group.envClasses.includes("subarray")) {
@@ -5476,9 +5673,17 @@ var temml = (function () {
5476
5673
  }
5477
5674
 
5478
5675
  let table = new mathMLTree.MathNode("mtable", tbl);
5676
+ if (group.envClasses.length > 0) {
5677
+ // Top & bottom padding
5678
+ if (group.envClasses.includes("jot")) {
5679
+ table.classes.push("tml-jot");
5680
+ } else if (group.envClasses.includes("small")) {
5681
+ table.classes.push("tml-small");
5682
+ }
5683
+ }
5479
5684
  if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true"); }
5480
5685
 
5481
- if (group.addEqnNum || group.envClasses.includes("multline")) {
5686
+ if (group.autoTag || group.envClasses.includes("multline")) {
5482
5687
  table.style.width = "100%";
5483
5688
  }
5484
5689
 
@@ -5508,7 +5713,7 @@ var temml = (function () {
5508
5713
  row.children[0].style.borderLeft = sep;
5509
5714
  }
5510
5715
  }
5511
- let iCol = group.addEqnNum ? 0 : -1;
5716
+ let iCol = group.autoTag ? 0 : -1;
5512
5717
  for (let i = iStart; i < iEnd; i++) {
5513
5718
  if (cols[i].type === "align") {
5514
5719
  const colAlign = alignMap[cols[i].align];
@@ -5550,7 +5755,7 @@ var temml = (function () {
5550
5755
  }
5551
5756
  }
5552
5757
  }
5553
- if (group.addEqnNum) {
5758
+ if (group.autoTag) {
5554
5759
  // allow for glue cells on each side
5555
5760
  align = "left " + (align.length > 0 ? align : "center ") + "right ";
5556
5761
  }
@@ -5574,13 +5779,14 @@ var temml = (function () {
5574
5779
  if (context.envName.indexOf("ed") === -1) {
5575
5780
  validateAmsEnvironmentContext(context);
5576
5781
  }
5782
+ const isSplit = context.envName === "split";
5577
5783
  const cols = [];
5578
5784
  const res = parseArray(
5579
5785
  context.parser,
5580
5786
  {
5581
5787
  cols,
5582
- addEqnNum: context.envName === "align" || context.envName === "alignat",
5583
5788
  emptySingleRow: true,
5789
+ autoTag: isSplit ? undefined : getAutoTag(context.envName),
5584
5790
  envClasses: ["abut", "jot"], // set row spacing & provisional column spacing
5585
5791
  maxNumCols: context.envName === "split" ? 2 : undefined,
5586
5792
  leqno: context.parser.settings.leqno
@@ -5902,7 +6108,7 @@ var temml = (function () {
5902
6108
  const res = {
5903
6109
  cols: [],
5904
6110
  envClasses: ["abut", "jot"],
5905
- addEqnNum: context.envName === "gather",
6111
+ autoTag: getAutoTag(context.envName),
5906
6112
  emptySingleRow: true,
5907
6113
  leqno: context.parser.settings.leqno
5908
6114
  };
@@ -5920,7 +6126,7 @@ var temml = (function () {
5920
6126
  handler(context) {
5921
6127
  validateAmsEnvironmentContext(context);
5922
6128
  const res = {
5923
- addEqnNum: context.envName === "equation",
6129
+ autoTag: getAutoTag(context.envName),
5924
6130
  emptySingleRow: true,
5925
6131
  singleRow: true,
5926
6132
  maxNumCols: 1,
@@ -5941,7 +6147,7 @@ var temml = (function () {
5941
6147
  handler(context) {
5942
6148
  validateAmsEnvironmentContext(context);
5943
6149
  const res = {
5944
- addEqnNum: context.envName === "multline",
6150
+ autoTag: context.envName === "multline",
5945
6151
  maxNumCols: 1,
5946
6152
  envClasses: ["jot", "multline"],
5947
6153
  leqno: context.parser.settings.leqno
@@ -6163,6 +6369,7 @@ var temml = (function () {
6163
6369
  "\\mathfrak",
6164
6370
  "\\mathscr",
6165
6371
  "\\mathsf",
6372
+ "\\mathsfit",
6166
6373
  "\\mathtt",
6167
6374
 
6168
6375
  // aliases
@@ -6232,10 +6439,19 @@ var temml = (function () {
6232
6439
  ? style.withLevel(StyleLevel.SCRIPT)
6233
6440
  : style.withLevel(StyleLevel.SCRIPTSCRIPT);
6234
6441
 
6235
- let node = new mathMLTree.MathNode("mfrac", [
6236
- buildGroup$1(group.numer, childOptions),
6237
- buildGroup$1(group.denom, childOptions)
6238
- ]);
6442
+ // Chromium (wrongly) continues to shrink fractions beyond scriptscriptlevel.
6443
+ // So we check for levels that Chromium shrinks too small.
6444
+ // If necessary, set an explicit fraction depth.
6445
+ const numer = buildGroup$1(group.numer, childOptions);
6446
+ const denom = buildGroup$1(group.denom, childOptions);
6447
+ if (style.level === 3) {
6448
+ numer.style.mathDepth = "2";
6449
+ numer.setAttribute("scriptlevel", "2");
6450
+ denom.style.mathDepth = "2";
6451
+ denom.setAttribute("scriptlevel", "2");
6452
+ }
6453
+
6454
+ let node = new mathMLTree.MathNode("mfrac", [numer, denom]);
6239
6455
 
6240
6456
  if (!group.hasBarLine) {
6241
6457
  node.setAttribute("linethickness", "0px");
@@ -6628,12 +6844,9 @@ var temml = (function () {
6628
6844
  };
6629
6845
  },
6630
6846
  mathmlBuilder: (group, style) => {
6631
- let math = buildExpressionRow(group.body, style);
6632
- if (!(math instanceof MathNode)) {
6633
- math = new MathNode("mrow", [math]);
6634
- }
6635
- math.setAttribute("href", group.href);
6636
- return math;
6847
+ const math = new MathNode("math", [buildExpressionRow(group.body, style)]);
6848
+ const anchorNode = new AnchorNode(group.href, [], [math]);
6849
+ return anchorNode
6637
6850
  }
6638
6851
  });
6639
6852
 
@@ -6991,7 +7204,7 @@ var temml = (function () {
6991
7204
  // Return a no-width, no-ink element with an HTML id.
6992
7205
  const node = new mathMLTree.MathNode("mrow", [], ["tml-label"]);
6993
7206
  if (group.string.length > 0) {
6994
- node.setAttribute("id", group.string);
7207
+ node.setLabel(group.string);
6995
7208
  }
6996
7209
  return node
6997
7210
  }
@@ -7505,13 +7718,6 @@ var temml = (function () {
7505
7718
  node = new MathNode("mo", [makeText(group.name, group.mode)]);
7506
7719
  if (noSuccessor.includes(group.name)) {
7507
7720
  node.setAttribute("largeop", "false");
7508
- } else if (group.limits) {
7509
- // This is a workaround for a MathML/Chromium bug.
7510
- // This is being applied to singleCharBigOps, which are not really stretchy.
7511
- // But by setting the stretchy attribute, Chromium will vertically center
7512
- // big ops around the math axis. This is needed since STIX TWO does not do so.
7513
- // TODO: Remove this hack when MathML & Chromium fix their problem.
7514
- node.setAttribute("stretchy", "true");
7515
7721
  } else {
7516
7722
  node.setAttribute("movablelimits", "false");
7517
7723
  }
@@ -8146,12 +8352,10 @@ var temml = (function () {
8146
8352
  };
8147
8353
  },
8148
8354
  mathmlBuilder(group, style) {
8149
- // Create an empty text node. Set a class and an href.
8355
+ // Create an empty <a> node. Set a class and an href attribute.
8150
8356
  // The post-processor will populate with the target's tag or equation number.
8151
8357
  const classes = group.funcName === "\\ref" ? ["tml-ref"] : ["tml-ref", "tml-eqref"];
8152
- const node = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode("")], classes);
8153
- node.setAttribute("href", "#" + group.string);
8154
- return node
8358
+ return new AnchorNode("#" + group.string, classes, null)
8155
8359
  }
8156
8360
  });
8157
8361
 
@@ -8198,6 +8402,8 @@ var temml = (function () {
8198
8402
  props: {
8199
8403
  numArgs: 2,
8200
8404
  numOptionalArgs: 1,
8405
+ allowedInText: true,
8406
+ allowedInMath: true,
8201
8407
  argTypes: ["size", "size", "size"]
8202
8408
  },
8203
8409
  handler({ parser }, args, optArgs) {
@@ -8490,16 +8696,25 @@ var temml = (function () {
8490
8696
  ? [buildGroup$1(group.base.body[0], style)]
8491
8697
  : [buildGroup$1(group.base, style)];
8492
8698
 
8699
+ // Note regarding scriptstyle level.
8700
+ // (Sub|super)scripts should not shrink beyond MathML scriptlevel 2 aka \scriptscriptstyle
8701
+ // Ref: https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes
8702
+ // (BTW, MathML scriptlevel 2 is equal to Temml level 3.)
8703
+ // But Chromium continues to shrink the (sub|super)scripts. So we explicitly set scriptlevel 2.
8704
+
8493
8705
  const childStyle = style.inSubOrSup();
8494
8706
  if (group.sub) {
8495
- children.push(buildGroup$1(group.sub, childStyle));
8707
+ const sub = buildGroup$1(group.sub, childStyle);
8708
+ if (style.level === 3) { sub.setAttribute("scriptlevel", "2"); }
8709
+ children.push(sub);
8496
8710
  }
8497
8711
 
8498
8712
  if (group.sup) {
8499
8713
  const sup = buildGroup$1(group.sup, childStyle);
8714
+ if (style.level === 3) { sup.setAttribute("scriptlevel", "2"); }
8500
8715
  const testNode = sup.type === "mrow" ? sup.children[0] : sup;
8501
8716
  if ((testNode && testNode.type === "mo" && testNode.classes.includes("tml-prime"))
8502
- && group.base && group.base.text && group.base.text === "f") {
8717
+ && group.base && group.base.text && "fF".indexOf(group.base.text) > -1) {
8503
8718
  // Chromium does not address italic correction on prime. Prevent f′ from overlapping.
8504
8719
  testNode.classes.push("prime-pad");
8505
8720
  }
@@ -8726,6 +8941,8 @@ var temml = (function () {
8726
8941
  return "script"
8727
8942
  case "mathsf":
8728
8943
  return "sans-serif"
8944
+ case "mathsfit":
8945
+ return "sans-serif-italic"
8729
8946
  case "mathtt":
8730
8947
  return "monospace"
8731
8948
  }
@@ -9190,6 +9407,32 @@ var temml = (function () {
9190
9407
  }
9191
9408
  });
9192
9409
 
9410
+ // \vcenter: Vertically center the argument group on the math axis.
9411
+
9412
+ defineFunction({
9413
+ type: "vcenter",
9414
+ names: ["\\vcenter"],
9415
+ props: {
9416
+ numArgs: 1,
9417
+ argTypes: ["original"],
9418
+ allowedInText: false
9419
+ },
9420
+ handler({ parser }, args) {
9421
+ return {
9422
+ type: "vcenter",
9423
+ mode: parser.mode,
9424
+ body: args[0]
9425
+ };
9426
+ },
9427
+ mathmlBuilder(group, style) {
9428
+ // Use a math table to create vertically centered content.
9429
+ const mtd = new mathMLTree.MathNode("mtd", [buildGroup$1(group.body, style)]);
9430
+ mtd.style.padding = "0";
9431
+ const mtr = new mathMLTree.MathNode("mtr", [mtd]);
9432
+ return new mathMLTree.MathNode("mtable", [mtr])
9433
+ }
9434
+ });
9435
+
9193
9436
  defineFunction({
9194
9437
  type: "verb",
9195
9438
  names: ["\\verb"],
@@ -9224,75 +9467,6 @@ var temml = (function () {
9224
9467
 
9225
9468
  const functions = _functions;
9226
9469
 
9227
- /**
9228
- * Lexing or parsing positional information for error reporting.
9229
- * This object is immutable.
9230
- */
9231
- class SourceLocation {
9232
- constructor(lexer, start, end) {
9233
- this.lexer = lexer; // Lexer holding the input string.
9234
- this.start = start; // Start offset, zero-based inclusive.
9235
- this.end = end; // End offset, zero-based exclusive.
9236
- }
9237
-
9238
- /**
9239
- * Merges two `SourceLocation`s from location providers, given they are
9240
- * provided in order of appearance.
9241
- * - Returns the first one's location if only the first is provided.
9242
- * - Returns a merged range of the first and the last if both are provided
9243
- * and their lexers match.
9244
- * - Otherwise, returns null.
9245
- */
9246
- static range(first, second) {
9247
- if (!second) {
9248
- return first && first.loc;
9249
- } else if (!first || !first.loc || !second.loc || first.loc.lexer !== second.loc.lexer) {
9250
- return null;
9251
- } else {
9252
- return new SourceLocation(first.loc.lexer, first.loc.start, second.loc.end);
9253
- }
9254
- }
9255
- }
9256
-
9257
- /**
9258
- * Interface required to break circular dependency between Token, Lexer, and
9259
- * ParseError.
9260
- */
9261
-
9262
- /**
9263
- * The resulting token returned from `lex`.
9264
- *
9265
- * It consists of the token text plus some position information.
9266
- * The position information is essentially a range in an input string,
9267
- * but instead of referencing the bare input string, we refer to the lexer.
9268
- * That way it is possible to attach extra metadata to the input string,
9269
- * like for example a file name or similar.
9270
- *
9271
- * The position information is optional, so it is OK to construct synthetic
9272
- * tokens if appropriate. Not providing available position information may
9273
- * lead to degraded error reporting, though.
9274
- */
9275
- class Token {
9276
- constructor(
9277
- text, // the text of this token
9278
- loc
9279
- ) {
9280
- this.text = text;
9281
- this.loc = loc;
9282
- }
9283
-
9284
- /**
9285
- * Given a pair of tokens (this and endToken), compute a `Token` encompassing
9286
- * the whole input range enclosed by these two.
9287
- */
9288
- range(
9289
- endToken, // last token of the range, inclusive
9290
- text // the text of the newly constructed token
9291
- ) {
9292
- return new Token(text, SourceLocation.range(this, endToken));
9293
- }
9294
- }
9295
-
9296
9470
  /**
9297
9471
  * The Lexer class handles tokenizing the input in various ways. Since our
9298
9472
  * parser expects us to be able to backtrack, the lexer allows lexing from any
@@ -11456,9 +11630,11 @@ var temml = (function () {
11456
11630
  constructor(data) {
11457
11631
  // Style.level can be 0 | 1 | 2 | 3, which correspond to
11458
11632
  // displaystyle, textstyle, scriptstyle, and scriptscriptstyle.
11459
- // style.level does not directly set MathML's script level. MathML does that itself.
11460
- // We use style.level to track, not set, math style so that we can get the
11461
- // correct scriptlevel when needed in supsub.js, mathchoice.js, or for dimensions in em.
11633
+ // style.level usually does not directly set MathML's script level. MathML does that itself.
11634
+ // However, Chromium does not stop shrinking after scriptscriptstyle, so we do explicitly
11635
+ // set a scriptlevel attribute in those conditions.
11636
+ // We also use style.level to track math style so that we can get the correct
11637
+ // scriptlevel when needed in supsub.js, mathchoice.js, or for dimensions in em.
11462
11638
  this.level = data.level;
11463
11639
  this.color = data.color; // string | void
11464
11640
  // A font family applies to a group of fonts (i.e. SansSerif), while a font
@@ -11582,42 +11758,51 @@ var temml = (function () {
11582
11758
  }
11583
11759
 
11584
11760
  /* Temml Post Process
11585
- * Perform two tasks not done by Temml when it created each individual Temml <math> element.
11586
- * Given a block,
11587
- * 1. At each AMS auto-numbered environment, assign an id.
11588
- * 2. Populate the text contents of each \ref & \eqref
11761
+ * Populate the text contents of each \ref & \eqref
11589
11762
  *
11590
11763
  * As with other Temml code, this file is released under terms of the MIT license.
11591
11764
  * https://mit-license.org/
11592
11765
  */
11593
11766
 
11594
- const version = "0.10.32";
11767
+ const version = "0.10.34";
11595
11768
 
11596
11769
  function postProcess(block) {
11597
11770
  const labelMap = {};
11598
11771
  let i = 0;
11599
11772
 
11600
11773
  // Get a collection of the parents of each \tag & auto-numbered equation
11601
- const parents = block.getElementsByClassName("tml-tageqn");
11602
- for (const parent of parents) {
11603
- const eqns = parent.getElementsByClassName("tml-eqn");
11604
- if (eqns. length > 0 ) {
11605
- // AMS automatically numbered equation.
11606
- // Assign an id.
11607
- i += 1;
11608
- eqns[0].id = "tml-eqn-" + i;
11609
- // No need to write a number into the text content of the element.
11610
- // A CSS counter does that even if this postProcess() function is not used.
11774
+ const amsEqns = document.getElementsByClassName('tml-eqn');
11775
+ for (let parent of amsEqns) {
11776
+ // AMS automatically numbered equation.
11777
+ // Assign an id.
11778
+ i += 1;
11779
+ parent.setAttribute("id", "tml-eqn-" + String(i));
11780
+ // No need to write a number into the text content of the element.
11781
+ // A CSS counter has done that even if this postProcess() function is not used.
11782
+
11783
+ // Find any \label that refers to an AMS automatic eqn number.
11784
+ while (true) {
11785
+ if (parent.tagName === "mtable") { break }
11786
+ const labels = parent.getElementsByClassName("tml-label");
11787
+ if (labels.length > 0) {
11788
+ const id = parent.attributes.id.value;
11789
+ labelMap[id] = String(i);
11790
+ break
11791
+ } else {
11792
+ parent = parent.parentElement;
11793
+ }
11611
11794
  }
11612
- // If there is a \label, add it to labelMap
11795
+ }
11796
+
11797
+ // Find \labels associated with \tag
11798
+ const taggedEqns = document.getElementsByClassName('tml-tageqn');
11799
+ for (const parent of taggedEqns) {
11613
11800
  const labels = parent.getElementsByClassName("tml-label");
11614
- if (labels.length === 0) { continue }
11615
- if (eqns.length > 0) {
11616
- labelMap[labels[0].id] = String(i);
11617
- } else {
11801
+ if (labels.length > 0) {
11618
11802
  const tags = parent.getElementsByClassName("tml-tag");
11619
11803
  if (tags.length > 0) {
11620
- labelMap[labels[0].id] = tags[0].textContent;
11804
+ const id = parent.attributes.id.value;
11805
+ labelMap[id] = tags[0].textContent;
11621
11806
  }
11622
11807
  }
11623
11808
  }
@@ -11625,17 +11810,22 @@ var temml = (function () {
11625
11810
  // Populate \ref & \eqref text content
11626
11811
  const refs = block.getElementsByClassName("tml-ref");
11627
11812
  [...refs].forEach(ref => {
11628
- let str = labelMap[ref.getAttribute("href").slice(1)];
11813
+ const attr = ref.getAttribute("href");
11814
+ let str = labelMap[attr.slice(1)];
11629
11815
  if (ref.className.indexOf("tml-eqref") === -1) {
11630
11816
  // \ref. Omit parens.
11631
11817
  str = str.replace(/^\(/, "");
11632
- str = str.replace(/\($/, "");
11633
- } {
11818
+ str = str.replace(/\)$/, "");
11819
+ } else {
11634
11820
  // \eqref. Include parens
11635
11821
  if (str.charAt(0) !== "(") { str = "(" + str; }
11636
11822
  if (str.slice(-1) !== ")") { str = str + ")"; }
11637
11823
  }
11638
- ref.textContent = str;
11824
+ const mtext = document.createElementNS("http://www.w3.org/1998/Math/MathML", "mtext");
11825
+ mtext.appendChild(document.createTextNode(str));
11826
+ const math = document.createElementNS("http://www.w3.org/1998/Math/MathML", "math");
11827
+ math.appendChild(mtext);
11828
+ ref.appendChild(math);
11639
11829
  });
11640
11830
  }
11641
11831