temml 0.10.15 → 0.10.17

Sign up to get free protection for your applications and to get access to all the features.
@@ -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);