temml 0.10.15 → 0.10.17

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.
@@ -14,7 +14,7 @@
14
14
  * https://mit-license.org/
15
15
  */
16
16
 
17
- const version = "0.10.15";
17
+ const version = "0.10.17";
18
18
 
19
19
  function postProcess(block) {
20
20
  const labelMap = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "temml",
3
- "version": "0.10.15",
3
+ "version": "0.10.17",
4
4
  "description": "TeX to MathML conversion in JavaScript.",
5
5
  "main": "dist/temml.js",
6
6
  "engines": {
package/src/Parser.js CHANGED
@@ -972,7 +972,6 @@ export default class Parser {
972
972
  loc: SourceLocation.range(nucleus),
973
973
  label: command,
974
974
  isStretchy: false,
975
- isShifty: true,
976
975
  base: symbol
977
976
  };
978
977
  }
@@ -207,13 +207,8 @@ const taggedExpression = (expression, tag, style, leqno) => {
207
207
 
208
208
  expression = new mathMLTree.MathNode("mtd", [expression])
209
209
  const rowArray = [glue(), expression, glue()]
210
- if (leqno) {
211
- rowArray[0].children.push(tag)
212
- rowArray[0].style.textAlign = "-webkit-left"
213
- } else {
214
- rowArray[2].children.push(tag)
215
- rowArray[2].style.textAlign = "-webkit-right"
216
- }
210
+ rowArray[leqno ? 0 : 2].classes.push(leqno ? "tml-left" : "tml-right")
211
+ rowArray[leqno ? 0 : 2].children.push(tag)
217
212
  const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"])
218
213
  const table = new mathMLTree.MathNode("mtable", [mtr])
219
214
  table.style.width = "100%"
package/src/domTree.js CHANGED
@@ -134,7 +134,7 @@ export class TextNode {
134
134
  }
135
135
  }
136
136
 
137
- /**
137
+ /*
138
138
  * This node represents an image embed (<img>) element.
139
139
  */
140
140
  export class Img {
@@ -179,7 +179,7 @@ export class Img {
179
179
  markup += ` style="${utils.escape(styles)}"`;
180
180
  }
181
181
 
182
- markup += "/>";
182
+ markup += ">";
183
183
  return markup;
184
184
  }
185
185
  }
@@ -2,6 +2,7 @@ import defineEnvironment from "../defineEnvironment";
2
2
  import { parseCD } from "./cd";
3
3
  import defineFunction from "../defineFunction";
4
4
  import mathMLTree from "../mathMLTree";
5
+ import { Span } from "../domTree"
5
6
  import { StyleLevel } from "../constants"
6
7
  import ParseError from "../ParseError";
7
8
  import { assertNodeType, assertSymbolNodeType } from "../parseNode";
@@ -57,8 +58,9 @@ const getTag = (group, style, rowNum) => {
57
58
  return tag
58
59
  } else {
59
60
  // AMS automatcally numbered equaton.
60
- // Insert a class so the element can be populated by a post-processor.
61
- tag = new mathMLTree.MathNode("mtext", [], ["tml-eqn"])
61
+ // Insert a class so the element can be populated by a CSS counter.
62
+ // WebKit will display the CSS counter only inside a span.
63
+ tag = new mathMLTree.MathNode("mtext", [new Span(["tml-eqn"])])
62
64
  }
63
65
  return tag
64
66
  }
@@ -255,7 +257,7 @@ const mathmlBuilder = function(group, style) {
255
257
  const align = i === 0 ? "left" : i === numRows - 1 ? "right" : "center"
256
258
  mtd.setAttribute("columnalign", align)
257
259
  if (align !== "center") {
258
- mtd.style.textAlign = "-webkit-" + align
260
+ mtd.classes.push("tml-" + align)
259
261
  }
260
262
  }
261
263
  row.push(mtd)
@@ -266,10 +268,10 @@ const mathmlBuilder = function(group, style) {
266
268
  const tag = getTag(group, style.withLevel(cellLevel), i)
267
269
  if (group.leqno) {
268
270
  row[0].children.push(tag)
269
- row[0].style.textAlign = "-webkit-left"
271
+ row[0].classes.push("tml-left")
270
272
  } else {
271
273
  row[row.length - 1].children.push(tag)
272
- row[row.length - 1].style.textAlign = "-webkit-right"
274
+ row[row.length - 1].classes.push("tml-right")
273
275
  }
274
276
  }
275
277
  const mtr = new mathMLTree.MathNode("mtr", row, [])
@@ -340,7 +342,11 @@ const mathmlBuilder = function(group, style) {
340
342
  for (let j = 0; j < row.children.length; j++) {
341
343
  // Chromium does not recognize text-align: left. Use -webkit-
342
344
  // TODO: Remove -webkit- when Chromium no longer needs it.
343
- row.children[j].style.textAlign = "-webkit-" + (j % 2 ? "left" : "right")
345
+ row.children[j].classes = ["tml-" + (j % 2 ? "left" : "right")]
346
+ }
347
+ if (group.addEqnNum) {
348
+ const k = group.leqno ? 0 : row.children.length - 1
349
+ row.children[k].classes = ["tml-" + (group.leqno ? "left" : "right")]
344
350
  }
345
351
  }
346
352
  if (row.children.length > 1 && group.envClasses.includes("cases")) {
@@ -349,7 +355,7 @@ const mathmlBuilder = function(group, style) {
349
355
 
350
356
  if (group.envClasses.includes("cases") || group.envClasses.includes("subarray")) {
351
357
  for (const cell of row.children) {
352
- cell.style.textAlign = "-webkit-" + "left"
358
+ cell.classes.push("tml-left")
353
359
  }
354
360
  }
355
361
  }
@@ -404,7 +410,7 @@ const mathmlBuilder = function(group, style) {
404
410
  iCol += 1
405
411
  for (const row of table.children) {
406
412
  if (colAlign.trim() !== "center" && iCol < row.children.length) {
407
- row.children[iCol].style.textAlign = "-webkit-" + colAlign.trim()
413
+ row.children[iCol].classes = ["tml-" + colAlign.trim()]
408
414
  }
409
415
  }
410
416
  prevTypeWasAlign = true;
@@ -2,10 +2,20 @@ import defineFunction, { normalizeArgument } from "../defineFunction"
2
2
  import mathMLTree from "../mathMLTree"
3
3
  import stretchy from "../stretchy"
4
4
  import * as mml from "../buildMathML"
5
+ import utils from "../utils"
6
+
7
+ const smalls = "acegıȷmnopqrsuvwxyzαγεηικμνοπρςστυχωϕ𝐚𝐜𝐞𝐠𝐦𝐧𝐨𝐩𝐪𝐫𝐬𝐮𝐯𝐰𝐱𝐲𝐳"
8
+ const talls = "ABCDEFGHIJKLMNOPQRSTUVWXYZbdfhkltΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩβδλζφθψ"
9
+ + "𝐀𝐁𝐂𝐃𝐄𝐅𝐆𝐇𝐈𝐉𝐊𝐋𝐌𝐍𝐎𝐏𝐐𝐑𝐒𝐓𝐔𝐕𝐖𝐗𝐘𝐙𝐛𝐝𝐟𝐡𝐤𝐥𝐭"
10
+ const longSmalls = new Set(["\\alpha", "\\gamma", "\\delta", "\\epsilon", "\\eta", "\\iota",
11
+ "\\kappa", "\\mu", "\\nu", "\\pi", "\\rho", "\\sigma", "\\tau", "\\upsilon", "\\chi", "\\psi",
12
+ "\\omega", "\\imath", "\\jmath"])
13
+ const longTalls = new Set(["\\Gamma", "\\Delta", "\\Sigma", "\\Omega", "\\beta", "\\delta",
14
+ "\\lambda", "\\theta", "\\psi"])
5
15
 
6
16
  const mathmlBuilder = (group, style) => {
7
17
  const accentNode = group.isStretchy
8
- ? stretchy.mathMLnode(group.label)
18
+ ? stretchy.accentNode(group)
9
19
  : new mathMLTree.MathNode("mo", [mml.makeText(group.label, group.mode)]);
10
20
 
11
21
  if (group.label === "\\vec") {
@@ -13,6 +23,13 @@ const mathmlBuilder = (group, style) => {
13
23
  } else {
14
24
  accentNode.style.mathStyle = "normal"
15
25
  accentNode.style.mathDepth = "0"
26
+ if (needWebkitShift.has(group.label) && utils.isCharacterBox(group.base)) {
27
+ let shift = ""
28
+ const ch = group.base.text
29
+ if (smalls.indexOf(ch) > -1 || longSmalls.has(ch)) { shift = "tml-xshift" }
30
+ if (talls.indexOf(ch) > -1 || longTalls.has(ch)) { shift = "tml-capshift" }
31
+ if (shift) { accentNode.classes.push(shift) }
32
+ }
16
33
  }
17
34
  if (!group.isStretchy) {
18
35
  accentNode.setAttribute("stretchy", "false")
@@ -25,25 +42,34 @@ const mathmlBuilder = (group, style) => {
25
42
  return node;
26
43
  };
27
44
 
28
- const NON_STRETCHY_ACCENT_REGEX = new RegExp(
29
- [
30
- "\\acute",
31
- "\\grave",
32
- "\\ddot",
33
- "\\dddot",
34
- "\\ddddot",
35
- "\\tilde",
36
- "\\bar",
37
- "\\breve",
38
- "\\check",
39
- "\\hat",
40
- "\\vec",
41
- "\\dot",
42
- "\\mathring"
43
- ]
44
- .map((accent) => `\\${accent}`)
45
- .join("|")
46
- );
45
+ const nonStretchyAccents = new Set([
46
+ "\\acute",
47
+ "\\grave",
48
+ "\\ddot",
49
+ "\\dddot",
50
+ "\\ddddot",
51
+ "\\tilde",
52
+ "\\bar",
53
+ "\\breve",
54
+ "\\check",
55
+ "\\hat",
56
+ "\\vec",
57
+ "\\dot",
58
+ "\\mathring"
59
+ ])
60
+
61
+ const needWebkitShift = new Set([
62
+ "\\acute",
63
+ "\\bar",
64
+ "\\breve",
65
+ "\\check",
66
+ "\\dot",
67
+ "\\ddot",
68
+ "\\grave",
69
+ "\\hat",
70
+ "\\mathring",
71
+ "\\'", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"', "\\r", "\\H", "\\v"
72
+ ])
47
73
 
48
74
  // Accents
49
75
  defineFunction({
@@ -81,7 +107,7 @@ defineFunction({
81
107
  handler: (context, args) => {
82
108
  const base = normalizeArgument(args[0]);
83
109
 
84
- const isStretchy = !NON_STRETCHY_ACCENT_REGEX.test(context.funcName);
110
+ const isStretchy = !nonStretchyAccents.has(context.funcName);
85
111
 
86
112
  return {
87
113
  type: "accent",
@@ -119,7 +145,6 @@ defineFunction({
119
145
  mode: mode,
120
146
  label: context.funcName,
121
147
  isStretchy: false,
122
- isShifty: true,
123
148
  base: base
124
149
  };
125
150
  },
@@ -27,7 +27,7 @@ defineFunction({
27
27
  };
28
28
  },
29
29
  mathmlBuilder: (group, style) => {
30
- const accentNode = stretchy.mathMLnode(group.label);
30
+ const accentNode = stretchy.accentNode(group);
31
31
  accentNode.style["math-depth"] = 0
32
32
  const node = new mathMLTree.MathNode("munder", [
33
33
  mml.buildGroup(group.base, style),
@@ -63,7 +63,10 @@ rgba(0,0,0,0) 100%);`
63
63
  node.style.marginRight = "0.03889em"
64
64
  break
65
65
  case "\\sout":
66
- node.style["text-decoration"] = "line-through 0.08em solid"
66
+ node.style.backgroundImage = 'linear-gradient(black, black)'
67
+ node.style.backgroundRepeat = 'no-repeat'
68
+ node.style.backgroundSize = '100% 1.5px'
69
+ node.style.backgroundPosition = '0 center'
67
70
  break
68
71
  case "\\boxed":
69
72
  // \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}} from amsmath.sty
@@ -4,7 +4,7 @@ import mathMLTree from "../mathMLTree"
4
4
  import * as mml from "../buildMathML"
5
5
  import ParseError from "../ParseError";
6
6
 
7
- const textModeLap = ["\\clap", "\\llap", "\\rlap"]
7
+ const textModeLap = ["\\clap", "\\llap", "\\rlap"];
8
8
 
9
9
  defineFunction({
10
10
  type: "lap",
@@ -53,7 +53,14 @@ defineFunctionBuilders({
53
53
  }
54
54
 
55
55
  if (group.sup) {
56
- children.push(mml.buildGroup(group.sup, childStyle))
56
+ const sup = mml.buildGroup(group.sup, childStyle)
57
+ const testNode = sup.type === "mrow" ? sup.children[0] : sup
58
+ if ((testNode.type === "mo" && testNode.classes.includes("tml-prime"))
59
+ && group.base && group.base.text && group.base.text === "f") {
60
+ // Chromium does not address italic correction on prime. Prevent f′ from overlapping.
61
+ testNode.classes.push("prime-pad")
62
+ }
63
+ children.push(sup)
57
64
  }
58
65
 
59
66
  let nodeType;
@@ -9,6 +9,8 @@ import * as mml from "../buildMathML"
9
9
 
10
10
  const numberRegEx = /^\d(?:[\d,.]*\d)?$/
11
11
  const latinRegEx = /[A-Ba-z]/
12
+ const primes = new Set(["\\prime", "\\dprime", "\\trprime", "\\qprime",
13
+ "\\backprime", "\\backdprime", "\\backtrprime"]);
12
14
 
13
15
  const italicNumber = (text, variant, tag) => {
14
16
  const mn = new mathMLTree.MathNode(tag, [text])
@@ -76,7 +78,7 @@ defineFunctionBuilders({
76
78
  text.text = variantChar(text.text, variant)
77
79
  }
78
80
  node = new mathMLTree.MathNode("mtext", [text])
79
- } else if (group.text === "\\prime") {
81
+ } else if (primes.has(group.text)) {
80
82
  node = new mathMLTree.MathNode("mo", [text])
81
83
  // TODO: If/when Chromium uses ssty variant for prime, remove the next line.
82
84
  node.classes.push("tml-prime")
package/src/macros.js CHANGED
@@ -188,6 +188,9 @@ defineMacro("\\char", function(context) {
188
188
  // This macro provides a better rendering.
189
189
  defineMacro("\\surd", '\\sqrt{\\vphantom{|}}')
190
190
 
191
+ // See comment for \oplus in symbols.js.
192
+ defineMacro("\u2295", "\\oplus")
193
+
191
194
  defineMacro("\\hbox", "\\text{#1}");
192
195
 
193
196
  // Per TeXbook p.122, "/" gets zero operator spacing.
@@ -8,7 +8,7 @@
8
8
  * https://mit-license.org/
9
9
  */
10
10
 
11
- export const version = "0.10.15";
11
+ export const version = "0.10.17";
12
12
 
13
13
  export function postProcess(block) {
14
14
  const labelMap = {}
package/src/stretchy.js CHANGED
@@ -4,6 +4,34 @@
4
4
 
5
5
  import mathMLTree from "./mathMLTree"
6
6
 
7
+ // TODO: Remove when Chromium stretches \widetilde & \widehat
8
+ const estimatedWidth = node => {
9
+ let width = 0
10
+ if (node.body) {
11
+ for (const item of node.body) {
12
+ width += estimatedWidth(item)
13
+ }
14
+ } else if (node.type === "supsub") {
15
+ width += estimatedWidth(node.base)
16
+ if (node.sub) { width += 0.7 * estimatedWidth(node.sub) }
17
+ if (node.sup) { width += 0.7 * estimatedWidth(node.sup) }
18
+ } else if (node.type === "mathord" || node.type === "textord") {
19
+ for (const ch of node.text.split('')) {
20
+ const codePoint = ch.codePointAt(0)
21
+ if ((0x60 < codePoint && codePoint < 0x7B) || (0x03B0 < codePoint && codePoint < 0x3CA)) {
22
+ width += 0.56 // lower case latin or greek. Use advance width of letter n
23
+ } else if (0x2F < codePoint && codePoint < 0x3A) {
24
+ width += 0.50 // numerals.
25
+ } else {
26
+ width += 0.92 // advance width of letter M
27
+ }
28
+ }
29
+ } else {
30
+ width += 1.0
31
+ }
32
+ return width
33
+ }
34
+
7
35
  const stretchyCodePoint = {
8
36
  widehat: "^",
9
37
  widecheck: "ˇ",
@@ -61,6 +89,25 @@ const mathMLnode = function(label) {
61
89
  return node
62
90
  }
63
91
 
92
+ const crookedWides = ["\\widetilde", "\\widehat", "\\widecheck", "\\utilde"]
93
+
94
+ // TODO: Remove when Chromium stretches \widetilde & \widehat
95
+ const accentNode = (group) => {
96
+ const mo = mathMLnode(group.label)
97
+ if (crookedWides.includes(group.label)) {
98
+ const width = estimatedWidth(group.base)
99
+ if (1 < width && width < 1.6) {
100
+ mo.classes.push("tml-crooked-2")
101
+ } else if (1.6 <= width && width < 2.5) {
102
+ mo.classes.push("tml-crooked-3")
103
+ } else if (2.5 <= width) {
104
+ mo.classes.push("tml-crooked-4")
105
+ }
106
+ }
107
+ return mo
108
+ }
109
+
64
110
  export default {
65
- mathMLnode
111
+ mathMLnode,
112
+ accentNode
66
113
  }
package/src/symbols.js CHANGED
@@ -294,6 +294,8 @@ defineSymbol(math, textord, "\u2127", "\\mho");
294
294
  defineSymbol(math, textord, "\u2132", "\\Finv", true);
295
295
  defineSymbol(math, textord, "\u2141", "\\Game", true);
296
296
  defineSymbol(math, textord, "\u2035", "\\backprime");
297
+ defineSymbol(math, textord, "\u2036", "\\backdprime");
298
+ defineSymbol(math, textord, "\u2037", "\\backtrprime");
297
299
  defineSymbol(math, textord, "\u25b2", "\\blacktriangle");
298
300
  defineSymbol(math, textord, "\u25bc", "\\blacktriangledown");
299
301
  defineSymbol(math, textord, "\u25a0", "\\blacksquare");
@@ -497,6 +499,9 @@ defineSymbol(text, textord, "\u2423", "\\textvisiblespace", true);
497
499
  defineSymbol(math, textord, "\u2220", "\\angle", true);
498
500
  defineSymbol(math, textord, "\u221e", "\\infty", true);
499
501
  defineSymbol(math, textord, "\u2032", "\\prime");
502
+ defineSymbol(math, textord, "\u2033", "\\dprime");
503
+ defineSymbol(math, textord, "\u2034", "\\trprime");
504
+ defineSymbol(math, textord, "\u2057", "\\qprime");
500
505
  defineSymbol(math, textord, "\u25b3", "\\triangle");
501
506
  defineSymbol(text, textord, "\u0391", "\\Alpha", true);
502
507
  defineSymbol(text, textord, "\u0392", "\\Beta", true);
@@ -676,7 +681,8 @@ defineSymbol(math, punct, ";", ";");
676
681
  defineSymbol(math, bin, "\u22bc", "\\barwedge", true);
677
682
  defineSymbol(math, bin, "\u22bb", "\\veebar", true);
678
683
  defineSymbol(math, bin, "\u2299", "\\odot", true);
679
- defineSymbol(math, bin, "\u2295", "\\oplus", true);
684
+ // Firefox turns ⊕ into an emoji. So append \uFE0E. Define Unicode character in macros, not here.
685
+ defineSymbol(math, bin, "\u2295\uFE0E", "\\oplus");
680
686
  defineSymbol(math, bin, "\u2297", "\\otimes", true);
681
687
  defineSymbol(math, textord, "\u2202", "\\partial", true);
682
688
  defineSymbol(math, bin, "\u2298", "\\oslash", true);