temml 0.10.12 → 0.10.14

Sign up to get free protection for your applications and to get access to all the features.
package/dist/temml.mjs CHANGED
@@ -968,6 +968,7 @@ defineSymbol(math, rel, "\u21c1", "\\rightharpoondown", true);
968
968
  defineSymbol(math, rel, "\u2196", "\\nwarrow", true);
969
969
  defineSymbol(math, rel, "\u21cc", "\\rightleftharpoons", true);
970
970
  defineSymbol(math, mathord, "\u21af", "\\lightning", true);
971
+ defineSymbol(math, mathord, "\u220E", "\\QED", true);
971
972
  defineSymbol(math, mathord, "\u2030", "\\permil", true);
972
973
  defineSymbol(text, textord, "\u2030", "\\permil");
973
974
 
@@ -1114,6 +1115,7 @@ defineSymbol(math, rel, "\u2ab7", "\\precapprox", true);
1114
1115
  defineSymbol(math, rel, "\u22b2", "\\vartriangleleft");
1115
1116
  defineSymbol(math, rel, "\u22b4", "\\trianglelefteq");
1116
1117
  defineSymbol(math, rel, "\u22a8", "\\vDash", true);
1118
+ defineSymbol(math, rel, "\u22ab", "\\VDash", true);
1117
1119
  defineSymbol(math, rel, "\u22aa", "\\Vvdash", true);
1118
1120
  defineSymbol(math, rel, "\u2323", "\\smallsmile");
1119
1121
  defineSymbol(math, rel, "\u2322", "\\smallfrown");
@@ -1763,13 +1765,16 @@ for (let i = 0; i < 10; i++) {
1763
1765
  * much of this module.
1764
1766
  */
1765
1767
 
1768
+ const openDelims = "([{⌊⌈⟨⟮⎰⟦⦃";
1769
+ const closeDelims = ")]}⌋⌉⟩⟯⎱⟦⦄";
1770
+
1766
1771
  function setLineBreaks(expression, wrapMode, isDisplayMode) {
1767
1772
  const mtrs = [];
1768
1773
  let mrows = [];
1769
1774
  let block = [];
1770
1775
  let numTopLevelEquals = 0;
1771
- let canBeBIN = false; // The first node cannot be an infix binary operator.
1772
1776
  let i = 0;
1777
+ let level = 0;
1773
1778
  while (i < expression.length) {
1774
1779
  while (expression[i] instanceof DocumentFragment) {
1775
1780
  expression.splice(i, 1, ...expression[i].children); // Expand the fragment.
@@ -1792,7 +1797,12 @@ function setLineBreaks(expression, wrapMode, isDisplayMode) {
1792
1797
  }
1793
1798
  block.push(node);
1794
1799
  if (node.type && node.type === "mo" && node.children.length === 1) {
1795
- if (wrapMode === "=" && node.children[0].text === "=") {
1800
+ const ch = node.children[0].text;
1801
+ if (openDelims.indexOf(ch) > -1) {
1802
+ level += 1;
1803
+ } else if (closeDelims.indexOf(ch) > -1) {
1804
+ level -= 1;
1805
+ } else if (level === 0 && wrapMode === "=" && ch === "=") {
1796
1806
  numTopLevelEquals += 1;
1797
1807
  if (numTopLevelEquals > 1) {
1798
1808
  block.pop();
@@ -1801,59 +1811,48 @@ function setLineBreaks(expression, wrapMode, isDisplayMode) {
1801
1811
  mrows.push(element);
1802
1812
  block = [node];
1803
1813
  }
1804
- } else if (wrapMode === "tex") {
1805
- // This may be a place for a soft line break.
1806
- if (canBeBIN && !node.attributes.form) {
1807
- // Check if the following node is a \nobreak text node, e.g. "~""
1808
- const next = i < expression.length - 1 ? expression[i + 1] : null;
1809
- let glueIsFreeOfNobreak = true;
1810
- if (
1811
- !(
1812
- next &&
1813
- next.type === "mtext" &&
1814
- next.attributes.linebreak &&
1815
- next.attributes.linebreak === "nobreak"
1816
- )
1817
- ) {
1818
- // We may need to start a new block.
1819
- // First, put any post-operator glue on same line as operator.
1820
- for (let j = i + 1; j < expression.length; j++) {
1821
- const nd = expression[j];
1814
+ } else if (level === 0 && wrapMode === "tex") {
1815
+ // Check if the following node is a \nobreak text node, e.g. "~""
1816
+ const next = i < expression.length - 1 ? expression[i + 1] : null;
1817
+ let glueIsFreeOfNobreak = true;
1818
+ if (
1819
+ !(
1820
+ next &&
1821
+ next.type === "mtext" &&
1822
+ next.attributes.linebreak &&
1823
+ next.attributes.linebreak === "nobreak"
1824
+ )
1825
+ ) {
1826
+ // We may need to start a new block.
1827
+ // First, put any post-operator glue on same line as operator.
1828
+ for (let j = i + 1; j < expression.length; j++) {
1829
+ const nd = expression[j];
1830
+ if (
1831
+ nd.type &&
1832
+ nd.type === "mspace" &&
1833
+ !(nd.attributes.linebreak && nd.attributes.linebreak === "newline")
1834
+ ) {
1835
+ block.push(nd);
1836
+ i += 1;
1822
1837
  if (
1823
- nd.type &&
1824
- nd.type === "mspace" &&
1825
- !(nd.attributes.linebreak && nd.attributes.linebreak === "newline")
1838
+ nd.attributes &&
1839
+ nd.attributes.linebreak &&
1840
+ nd.attributes.linebreak === "nobreak"
1826
1841
  ) {
1827
- block.push(nd);
1828
- i += 1;
1829
- if (
1830
- nd.attributes &&
1831
- nd.attributes.linebreak &&
1832
- nd.attributes.linebreak === "nobreak"
1833
- ) {
1834
- glueIsFreeOfNobreak = false;
1835
- }
1836
- } else {
1837
- break;
1842
+ glueIsFreeOfNobreak = false;
1838
1843
  }
1844
+ } else {
1845
+ break;
1839
1846
  }
1840
1847
  }
1841
- if (glueIsFreeOfNobreak) {
1842
- // Start a new block. (Insert a soft linebreak.)
1843
- const element = new mathMLTree.MathNode("mrow", block);
1844
- mrows.push(element);
1845
- block = [];
1846
- }
1847
- canBeBIN = false;
1848
1848
  }
1849
- const isOpenDelimiter = node.attributes.form && node.attributes.form === "prefix";
1850
- // Any operator that follows an open delimiter is unary.
1851
- canBeBIN = !(node.attributes.separator || isOpenDelimiter);
1852
- } else {
1853
- canBeBIN = true;
1849
+ if (glueIsFreeOfNobreak) {
1850
+ // Start a new block. (Insert a soft linebreak.)
1851
+ const element = new mathMLTree.MathNode("mrow", block);
1852
+ mrows.push(element);
1853
+ block = [];
1854
+ }
1854
1855
  }
1855
- } else {
1856
- canBeBIN = true;
1857
1856
  }
1858
1857
  i += 1;
1859
1858
  }
@@ -2132,7 +2131,10 @@ function buildMathML(tree, texExpression, style, settings) {
2132
2131
  math.setAttribute("display", "block");
2133
2132
  math.style.display = math.children.length === 1 && math.children[0].type === "mtable"
2134
2133
  ? "inline"
2135
- : "block math";
2134
+ : "block math"; // necessary in Chromium.
2135
+ // Firefox and Safari do not recognize display: "block math".
2136
+ // Set a class so that the CSS file can set display: block.
2137
+ math.classes = ["tml-display"];
2136
2138
  }
2137
2139
  return math;
2138
2140
  }
@@ -2416,43 +2418,69 @@ const paddedNode = (group, lspace = 0.3, rspace = 0) => {
2416
2418
  return new mathMLTree.MathNode("mrow", row)
2417
2419
  };
2418
2420
 
2419
- const labelSize = (size, scriptLevel) => (size / emScale(scriptLevel)).toFixed(4);
2421
+ const labelSize = (size, scriptLevel) => Number(size) / emScale(scriptLevel);
2420
2422
 
2421
- const munderoverNode = (name, body, below, style) => {
2422
- const arrowNode = stretchy.mathMLnode(name);
2423
+ const munderoverNode = (fName, body, below, style) => {
2424
+ const arrowNode = stretchy.mathMLnode(fName);
2423
2425
  // Is this the short part of a mhchem equilibrium arrow?
2424
- const isEq = name.slice(1, 3) === "eq";
2425
- const minWidth = name.charAt(1) === "x"
2426
- ? "1.75" // mathtools extensible arrows are 1.75em long
2427
- : name.slice(2, 4) === "cd"
2426
+ const isEq = fName.slice(1, 3) === "eq";
2427
+ const minWidth = fName.charAt(1) === "x"
2428
+ ? "1.75" // mathtools extensible arrows are 1.75em long
2429
+ : fName.slice(2, 4) === "cd"
2428
2430
  ? "3.0" // cd package arrows
2429
2431
  : isEq
2430
2432
  ? "1.0" // The shorter harpoon of a mhchem equilibrium arrow
2431
2433
  : "2.0"; // other mhchem arrows
2432
- arrowNode.setAttribute("minsize", String(minWidth) + "em");
2434
+ // TODO: When Firefox supports minsize, use the next line.
2435
+ //arrowNode.setAttribute("minsize", String(minWidth) + "em")
2433
2436
  arrowNode.setAttribute("lspace", "0");
2434
2437
  arrowNode.setAttribute("rspace", (isEq ? "0.5em" : "0"));
2435
2438
 
2436
2439
  // <munderover> upper and lower labels are set to scriptlevel by MathML
2437
- // So we have to adjust our dimensions accordingly.
2440
+ // So we have to adjust our label dimensions accordingly.
2438
2441
  const labelStyle = style.withLevel(style.level < 2 ? 2 : 3);
2439
- const emptyLabelWidth = labelSize(minWidth, labelStyle.level);
2440
- const lspace = labelSize((isEq ? 0 : 0.3), labelStyle.level);
2441
- const rspace = labelSize((isEq ? 0 : 0.3), labelStyle.level);
2442
-
2443
- const upperNode = (body && body.body &&
2442
+ const minArrowWidth = labelSize(minWidth, labelStyle.level);
2443
+ // The dummyNode will be inside a <mover> inside a <mover>
2444
+ // So it will be at scriptlevel 3
2445
+ const dummyWidth = labelSize(minWidth, 3);
2446
+ const emptyLabel = paddedNode(null, minArrowWidth.toFixed(4), 0);
2447
+ const dummyNode = paddedNode(null, dummyWidth.toFixed(4), 0);
2448
+ // The arrow is a little longer than the label. Set a spacer length.
2449
+ const space = labelSize((isEq ? 0 : 0.3), labelStyle.level).toFixed(4);
2450
+ let upperNode;
2451
+ let lowerNode;
2452
+
2453
+ const gotUpper = (body && body.body &&
2444
2454
  // \hphantom visible content
2445
- (body.body.body || body.body.length > 0))
2446
- ? paddedNode(buildGroup$1(body, labelStyle), lspace, rspace)
2447
- // Since Firefox does not recognize minsize set on the arrow,
2448
- // create an upper node w/correct width.
2449
- : paddedNode(null, emptyLabelWidth, 0);
2450
- const lowerNode = (below && below.body &&
2451
- (below.body.body || below.body.length > 0))
2452
- ? paddedNode(buildGroup$1(below, labelStyle), lspace, rspace)
2453
- : paddedNode(null, emptyLabelWidth, 0);
2454
- const node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]);
2455
- if (minWidth === "3.0") { node.style.height = "1em"; }
2455
+ (body.body.body || body.body.length > 0));
2456
+ if (gotUpper) {
2457
+ let label = buildGroup$1(body, labelStyle);
2458
+ label = paddedNode(label, space, space);
2459
+ // Since Firefox does not support minsize, stack a invisible node
2460
+ // on top of the label. Its width will serve as a min-width.
2461
+ // TODO: Refactor this after Firefox supports minsize.
2462
+ upperNode = new mathMLTree.MathNode("mover", [label, dummyNode]);
2463
+ }
2464
+ const gotLower = (below && below.body &&
2465
+ (below.body.body || below.body.length > 0));
2466
+ if (gotLower) {
2467
+ let label = buildGroup$1(below, labelStyle);
2468
+ label = paddedNode(label, space, space);
2469
+ lowerNode = new mathMLTree.MathNode("munder", [label, dummyNode]);
2470
+ }
2471
+
2472
+ let node;
2473
+ if (!gotUpper && !gotLower) {
2474
+ node = new mathMLTree.MathNode("mover", [arrowNode, emptyLabel]);
2475
+ } else if (gotUpper && gotLower) {
2476
+ node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]);
2477
+ } else if (gotUpper) {
2478
+ node = new mathMLTree.MathNode("mover", [arrowNode, upperNode]);
2479
+ } else {
2480
+ node = new mathMLTree.MathNode("munder", [arrowNode, lowerNode]);
2481
+ }
2482
+ if (minWidth === "3.0") { node.style.height = "1em"; } // CD environment
2483
+ node.setAttribute("accent", "false"); // Necessary for MS Word
2456
2484
  return node
2457
2485
  };
2458
2486
 
@@ -2531,7 +2559,7 @@ defineFunction({
2531
2559
  "\\xleftrightharpoons", // mathtools
2532
2560
  "\\xrightleftharpoons", // mathtools
2533
2561
  "\\yieldsLeftRight", // mhchem
2534
- "\\equilibrium", // mhchem
2562
+ "\\equilibrium", // mhchem
2535
2563
  "\\equilibriumRight",
2536
2564
  "\\equilibriumLeft"
2537
2565
  ],
@@ -3635,10 +3663,9 @@ defineFunction({
3635
3663
  // so we have to explicitly set stretchy to true.
3636
3664
  node.setAttribute("stretchy", "true");
3637
3665
  }
3638
-
3639
3666
  node.setAttribute("symmetric", "true"); // Needed for tall arrows in Firefox.
3640
3667
  node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em");
3641
- // Don't set the maxsize attribute. It's broken in Chromium.
3668
+ node.setAttribute("maxsize", sizeToMaxHeight[group.size] + "em");
3642
3669
  return node;
3643
3670
  }
3644
3671
  });
@@ -3773,33 +3800,31 @@ const padding$1 = _ => {
3773
3800
 
3774
3801
  const mathmlBuilder$8 = (group, style) => {
3775
3802
  let node;
3776
- if (group.label.indexOf("colorbox") > -1) {
3777
- // Chrome mpadded +width attribute is broken. Insert <mspace>
3778
- node = new mathMLTree.MathNode("mpadded", [
3803
+ if (group.label.indexOf("colorbox") > -1 || group.label === "\\boxed") {
3804
+ // MathML core does not support +width attribute in <mpadded>.
3805
+ // Firefox does not reliably add side padding.
3806
+ // Insert <mspace>
3807
+ node = new mathMLTree.MathNode("mrow", [
3779
3808
  padding$1(),
3780
3809
  buildGroup$1(group.body, style),
3781
3810
  padding$1()
3782
3811
  ]);
3783
3812
  } else {
3784
- node = new mathMLTree.MathNode("menclose", [buildGroup$1(group.body, style)]);
3813
+ node = new mathMLTree.MathNode("mrow", [buildGroup$1(group.body, style)]);
3785
3814
  }
3786
3815
  switch (group.label) {
3787
3816
  case "\\overline":
3788
- node.setAttribute("notation", "top");
3789
3817
  node.style.padding = "0.1em 0 0 0";
3790
3818
  node.style.borderTop = "0.065em solid";
3791
3819
  break
3792
3820
  case "\\underline":
3793
- node.setAttribute("notation", "bottom");
3794
3821
  node.style.padding = "0 0 0.1em 0";
3795
3822
  node.style.borderBottom = "0.065em solid";
3796
3823
  break
3797
3824
  case "\\cancel":
3798
- node.setAttribute("notation", "updiagonalstrike");
3799
3825
  node.classes.push("cancel");
3800
3826
  break
3801
3827
  case "\\bcancel":
3802
- node.setAttribute("notation", "downdiagonalstrike");
3803
3828
  node.classes.push("bcancel");
3804
3829
  break
3805
3830
  /*
@@ -3810,18 +3835,21 @@ const mathmlBuilder$8 = (group, style) => {
3810
3835
  node.setAttribute("notation", "phasorangle");
3811
3836
  break */
3812
3837
  case "\\angl":
3813
- node.setAttribute("notation", "actuarial");
3814
3838
  node.style.padding = "0.03889em 0.03889em 0 0.03889em";
3815
3839
  node.style.borderTop = "0.049em solid";
3816
3840
  node.style.borderRight = "0.049em solid";
3817
3841
  node.style.marginRight = "0.03889em";
3818
3842
  break
3819
3843
  case "\\sout":
3820
- node.setAttribute("notation", "horizontalstrike");
3821
3844
  node.style["text-decoration"] = "line-through 0.08em solid";
3822
3845
  break
3846
+ case "\\boxed":
3847
+ // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} from amsmath.sty
3848
+ node.style = { padding: "3pt 0 3pt 0", border: "1px solid" };
3849
+ node.setAttribute("scriptlevel", "0");
3850
+ node.setAttribute("displaystyle", "true");
3851
+ break
3823
3852
  case "\\fbox":
3824
- node.setAttribute("notation", "box");
3825
3853
  node.style = { padding: "3pt", border: "1px solid" };
3826
3854
  break
3827
3855
  case "\\fcolorbox":
@@ -3841,7 +3869,6 @@ const mathmlBuilder$8 = (group, style) => {
3841
3869
  break
3842
3870
  }
3843
3871
  case "\\xcancel":
3844
- node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
3845
3872
  node.classes.push("xcancel");
3846
3873
  break
3847
3874
  }
@@ -3936,7 +3963,7 @@ defineFunction({
3936
3963
 
3937
3964
  defineFunction({
3938
3965
  type: "enclose",
3939
- names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline"],
3966
+ names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline", "\\boxed"],
3940
3967
  // , "\\phase", "\\longdiv"
3941
3968
  props: {
3942
3969
  numArgs: 1
@@ -6802,8 +6829,6 @@ defineFunction({
6802
6829
  }
6803
6830
  });
6804
6831
 
6805
- const sign = num => num >= 0 ? "+" : "-";
6806
-
6807
6832
  // \raise, \lower, and \raisebox
6808
6833
 
6809
6834
  const mathmlBuilder = (group, style) => {
@@ -6811,11 +6836,13 @@ const mathmlBuilder = (group, style) => {
6811
6836
  const node = new mathMLTree.MathNode("mpadded", [buildGroup$1(group.body, newStyle)]);
6812
6837
  const dy = calculateSize(group.dy, style);
6813
6838
  node.setAttribute("voffset", dy.number + dy.unit);
6814
- const dyAbs = Math.abs(dy.number);
6815
- // The next two lines do not work in Chromium.
6816
- // TODO: Find some other way to adjust height and depth.
6817
- node.setAttribute("height", sign(dy.number) + dyAbs + dy.unit);
6818
- node.setAttribute("depth", sign(-dy.number) + dyAbs + dy.unit);
6839
+ // Add padding, which acts to increase height in Chromium.
6840
+ // TODO: Figure out some way to change height in Firefox w/o breaking Chromium.
6841
+ if (dy.number > 0) {
6842
+ node.style.padding = dy.number + dy.unit + " 0 0 0";
6843
+ } else {
6844
+ node.style.padding = "0 0 " + Math.abs(dy.number) + dy.unit + " 0";
6845
+ }
6819
6846
  return node
6820
6847
  };
6821
6848
 
@@ -8444,9 +8471,6 @@ defineMacro("\u22ee", "\\vdots");
8444
8471
  //\newcommand{\substack}[1]{\subarray{c}#1\endsubarray}
8445
8472
  defineMacro("\\substack", "\\begin{subarray}{c}#1\\end{subarray}");
8446
8473
 
8447
- // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}}
8448
- defineMacro("\\boxed", "\\fbox{$\\displaystyle{#1}$}");
8449
-
8450
8474
  // \def\iff{\DOTSB\;\Longleftrightarrow\;}
8451
8475
  // \def\implies{\DOTSB\;\Longrightarrow\;}
8452
8476
  // \def\impliedby{\DOTSB\;\Longleftarrow\;}
@@ -8695,7 +8719,7 @@ defineMacro(
8695
8719
  defineMacro(
8696
8720
  "\\Temml",
8697
8721
  // eslint-disable-next-line max-len
8698
- "\\textrm{T}\\kern-0.2em\\lower{0.2em}\\textrm{E}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}"
8722
+ "\\textrm{T}\\kern-0.2em\\lower{0.2em}{\\textrm{E}}\\kern-0.08em{\\textrm{M}\\kern-0.08em\\raise{0.2em}\\textrm{M}\\kern-0.08em\\textrm{L}}"
8699
8723
  );
8700
8724
 
8701
8725
  // \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace}
@@ -12875,7 +12899,7 @@ class Style {
12875
12899
  * https://mit-license.org/
12876
12900
  */
12877
12901
 
12878
- const version = "0.10.12";
12902
+ const version = "0.10.14";
12879
12903
 
12880
12904
  function postProcess(block) {
12881
12905
  const labelMap = {};
@@ -14,7 +14,7 @@
14
14
  * https://mit-license.org/
15
15
  */
16
16
 
17
- const version = "0.10.12";
17
+ const version = "0.10.14";
18
18
 
19
19
  function postProcess(block) {
20
20
  const labelMap = {};
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "temml",
3
- "version": "0.10.12",
3
+ "version": "0.10.14",
4
4
  "description": "TeX to MathML conversion in JavaScript.",
5
5
  "main": "dist/temml.js",
6
+ "engines": {
7
+ "node": ">=18.13.0"
8
+ },
6
9
  "exports": {
7
10
  ".": {
8
11
  "require": "./dist/temml.cjs"
@@ -262,7 +262,10 @@ export default function buildMathML(tree, texExpression, style, settings) {
262
262
  math.setAttribute("display", "block");
263
263
  math.style.display = math.children.length === 1 && math.children[0].type === "mtable"
264
264
  ? "inline"
265
- : "block math"
265
+ : "block math" // necessary in Chromium.
266
+ // Firefox and Safari do not recognize display: "block math".
267
+ // Set a class so that the CSS file can set display: block.
268
+ math.classes = ["tml-display"]
266
269
  }
267
270
  return math;
268
271
  }
@@ -18,45 +18,71 @@ const paddedNode = (group, lspace = 0.3, rspace = 0) => {
18
18
  if (lspace !== 0) { row.unshift(padding(lspace)) }
19
19
  if (rspace > 0) { row.push(padding(rspace)) }
20
20
  return new mathMLTree.MathNode("mrow", row)
21
- };
21
+ }
22
22
 
23
- const labelSize = (size, scriptLevel) => (size / emScale(scriptLevel)).toFixed(4)
23
+ const labelSize = (size, scriptLevel) => Number(size) / emScale(scriptLevel);
24
24
 
25
- const munderoverNode = (name, body, below, style) => {
26
- const arrowNode = stretchy.mathMLnode(name);
25
+ const munderoverNode = (fName, body, below, style) => {
26
+ const arrowNode = stretchy.mathMLnode(fName);
27
27
  // Is this the short part of a mhchem equilibrium arrow?
28
- const isEq = name.slice(1, 3) === "eq"
29
- const minWidth = name.charAt(1) === "x"
30
- ? "1.75" // mathtools extensible arrows are 1.75em long
31
- : name.slice(2, 4) === "cd"
28
+ const isEq = fName.slice(1, 3) === "eq"
29
+ const minWidth = fName.charAt(1) === "x"
30
+ ? "1.75" // mathtools extensible arrows are 1.75em long
31
+ : fName.slice(2, 4) === "cd"
32
32
  ? "3.0" // cd package arrows
33
33
  : isEq
34
34
  ? "1.0" // The shorter harpoon of a mhchem equilibrium arrow
35
35
  : "2.0"; // other mhchem arrows
36
- arrowNode.setAttribute("minsize", String(minWidth) + "em");
36
+ // TODO: When Firefox supports minsize, use the next line.
37
+ //arrowNode.setAttribute("minsize", String(minWidth) + "em")
37
38
  arrowNode.setAttribute("lspace", "0")
38
39
  arrowNode.setAttribute("rspace", (isEq ? "0.5em" : "0"))
39
40
 
40
41
  // <munderover> upper and lower labels are set to scriptlevel by MathML
41
- // So we have to adjust our dimensions accordingly.
42
+ // So we have to adjust our label dimensions accordingly.
42
43
  const labelStyle = style.withLevel(style.level < 2 ? 2 : 3)
43
- const emptyLabelWidth = labelSize(minWidth, labelStyle.level)
44
- const lspace = labelSize((isEq ? 0 : 0.3), labelStyle.level)
45
- const rspace = labelSize((isEq ? 0 : 0.3), labelStyle.level)
44
+ const minArrowWidth = labelSize(minWidth, labelStyle.level)
45
+ // The dummyNode will be inside a <mover> inside a <mover>
46
+ // So it will be at scriptlevel 3
47
+ const dummyWidth = labelSize(minWidth, 3)
48
+ const emptyLabel = paddedNode(null, minArrowWidth.toFixed(4), 0)
49
+ const dummyNode = paddedNode(null, dummyWidth.toFixed(4), 0)
50
+ // The arrow is a little longer than the label. Set a spacer length.
51
+ const space = labelSize((isEq ? 0 : 0.3), labelStyle.level).toFixed(4)
52
+ let upperNode
53
+ let lowerNode
46
54
 
47
- const upperNode = (body && body.body &&
55
+ const gotUpper = (body && body.body &&
48
56
  // \hphantom visible content
49
57
  (body.body.body || body.body.length > 0))
50
- ? paddedNode(mml.buildGroup(body, labelStyle), lspace, rspace)
51
- // Since Firefox does not recognize minsize set on the arrow,
52
- // create an upper node w/correct width.
53
- : paddedNode(null, emptyLabelWidth, 0)
54
- const lowerNode = (below && below.body &&
58
+ if (gotUpper) {
59
+ let label = mml.buildGroup(body, labelStyle)
60
+ label = paddedNode(label, space, space)
61
+ // Since Firefox does not support minsize, stack a invisible node
62
+ // on top of the label. Its width will serve as a min-width.
63
+ // TODO: Refactor this after Firefox supports minsize.
64
+ upperNode = new mathMLTree.MathNode("mover", [label, dummyNode])
65
+ }
66
+ const gotLower = (below && below.body &&
55
67
  (below.body.body || below.body.length > 0))
56
- ? paddedNode(mml.buildGroup(below, labelStyle), lspace, rspace)
57
- : paddedNode(null, emptyLabelWidth, 0)
58
- const node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode]);
59
- if (minWidth === "3.0") { node.style.height = "1em" }
68
+ if (gotLower) {
69
+ let label = mml.buildGroup(below, labelStyle)
70
+ label = paddedNode(label, space, space)
71
+ lowerNode = new mathMLTree.MathNode("munder", [label, dummyNode])
72
+ }
73
+
74
+ let node
75
+ if (!gotUpper && !gotLower) {
76
+ node = new mathMLTree.MathNode("mover", [arrowNode, emptyLabel])
77
+ } else if (gotUpper && gotLower) {
78
+ node = new mathMLTree.MathNode("munderover", [arrowNode, lowerNode, upperNode])
79
+ } else if (gotUpper) {
80
+ node = new mathMLTree.MathNode("mover", [arrowNode, upperNode])
81
+ } else {
82
+ node = new mathMLTree.MathNode("munder", [arrowNode, lowerNode])
83
+ }
84
+ if (minWidth === "3.0") { node.style.height = "1em" } // CD environment
85
+ node.setAttribute("accent", "false") // Necessary for MS Word
60
86
  return node
61
87
  }
62
88
 
@@ -135,7 +161,7 @@ defineFunction({
135
161
  "\\xleftrightharpoons", // mathtools
136
162
  "\\xrightleftharpoons", // mathtools
137
163
  "\\yieldsLeftRight", // mhchem
138
- "\\equilibrium", // mhchem
164
+ "\\equilibrium", // mhchem
139
165
  "\\equilibriumRight",
140
166
  "\\equilibriumLeft"
141
167
  ],
@@ -178,10 +178,9 @@ defineFunction({
178
178
  // so we have to explicitly set stretchy to true.
179
179
  node.setAttribute("stretchy", "true")
180
180
  }
181
-
182
181
  node.setAttribute("symmetric", "true"); // Needed for tall arrows in Firefox.
183
- node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em");
184
- // Don't set the maxsize attribute. It's broken in Chromium.
182
+ node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em")
183
+ node.setAttribute("maxsize", sizeToMaxHeight[group.size] + "em")
185
184
  return node;
186
185
  }
187
186
  });
@@ -12,33 +12,31 @@ const padding = _ => {
12
12
 
13
13
  const mathmlBuilder = (group, style) => {
14
14
  let node
15
- if (group.label.indexOf("colorbox") > -1) {
16
- // Chrome mpadded +width attribute is broken. Insert <mspace>
17
- node = new mathMLTree.MathNode("mpadded", [
15
+ if (group.label.indexOf("colorbox") > -1 || group.label === "\\boxed") {
16
+ // MathML core does not support +width attribute in <mpadded>.
17
+ // Firefox does not reliably add side padding.
18
+ // Insert <mspace>
19
+ node = new mathMLTree.MathNode("mrow", [
18
20
  padding(),
19
21
  mml.buildGroup(group.body, style),
20
22
  padding()
21
23
  ])
22
24
  } else {
23
- node = new mathMLTree.MathNode("menclose", [mml.buildGroup(group.body, style)])
25
+ node = new mathMLTree.MathNode("mrow", [mml.buildGroup(group.body, style)])
24
26
  }
25
27
  switch (group.label) {
26
28
  case "\\overline":
27
- node.setAttribute("notation", "top")
28
29
  node.style.padding = "0.1em 0 0 0"
29
30
  node.style.borderTop = "0.065em solid"
30
31
  break
31
32
  case "\\underline":
32
- node.setAttribute("notation", "bottom")
33
33
  node.style.padding = "0 0 0.1em 0"
34
34
  node.style.borderBottom = "0.065em solid"
35
35
  break
36
36
  case "\\cancel":
37
- node.setAttribute("notation", "updiagonalstrike");
38
37
  node.classes.push("cancel")
39
38
  break
40
39
  case "\\bcancel":
41
- node.setAttribute("notation", "downdiagonalstrike");
42
40
  node.classes.push("bcancel")
43
41
  break
44
42
  /*
@@ -49,18 +47,21 @@ const mathmlBuilder = (group, style) => {
49
47
  node.setAttribute("notation", "phasorangle");
50
48
  break */
51
49
  case "\\angl":
52
- node.setAttribute("notation", "actuarial")
53
50
  node.style.padding = "0.03889em 0.03889em 0 0.03889em"
54
51
  node.style.borderTop = "0.049em solid"
55
52
  node.style.borderRight = "0.049em solid"
56
53
  node.style.marginRight = "0.03889em"
57
54
  break
58
55
  case "\\sout":
59
- node.setAttribute("notation", "horizontalstrike");
60
56
  node.style["text-decoration"] = "line-through 0.08em solid"
61
57
  break
58
+ case "\\boxed":
59
+ // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} from amsmath.sty
60
+ node.style = { padding: "3pt 0 3pt 0", border: "1px solid" }
61
+ node.setAttribute("scriptlevel", "0")
62
+ node.setAttribute("displaystyle", "true")
63
+ break
62
64
  case "\\fbox":
63
- node.setAttribute("notation", "box");
64
65
  node.style = { padding: "3pt", border: "1px solid" }
65
66
  break
66
67
  case "\\fcolorbox":
@@ -80,7 +81,6 @@ const mathmlBuilder = (group, style) => {
80
81
  break
81
82
  }
82
83
  case "\\xcancel":
83
- node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
84
84
  node.classes.push("xcancel")
85
85
  break
86
86
  }
@@ -175,7 +175,7 @@ defineFunction({
175
175
 
176
176
  defineFunction({
177
177
  type: "enclose",
178
- names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline"],
178
+ names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline", "\\boxed"],
179
179
  // , "\\phase", "\\longdiv"
180
180
  props: {
181
181
  numArgs: 1