temml 0.10.33 → 0.11.0

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.
@@ -3,6 +3,7 @@ import { parseCD } from "./cd";
3
3
  import defineFunction from "../defineFunction";
4
4
  import mathMLTree from "../mathMLTree";
5
5
  import { Span } from "../domTree"
6
+ import { Token } from "../Token";
6
7
  import { StyleLevel } from "../constants"
7
8
  import ParseError from "../ParseError";
8
9
  import { assertNodeType, assertSymbolNodeType } from "../parseNode";
@@ -57,31 +58,28 @@ const arrayGaps = macros => {
57
58
  return [arraystretch, arraycolsep]
58
59
  }
59
60
 
60
- const getTag = (group, style, rowNum) => {
61
- let tag
62
- const tagContents = group.tags.shift()
63
- if (tagContents) {
64
- // The author has written a \tag or a \notag in this row.
65
- if (tagContents.body) {
66
- tag = mml.buildExpressionRow(tagContents.body, style, true)
67
- tag.classes = ["tml-tag"]
68
- } else {
69
- // \notag. Return an empty span.
70
- tag = new mathMLTree.MathNode("mtext", [], [])
71
- return tag
61
+ const checkCellForLabels = cell => {
62
+ // Check if the author wrote a \tag{} inside this cell.
63
+ let rowLabel = ""
64
+ for (let i = 0; i < cell.length; i++) {
65
+ if (cell[i].type === "label") {
66
+ if (rowLabel) { throw new ParseError(("Multiple \\labels in one row")) }
67
+ rowLabel = cell[i].string
72
68
  }
73
- } else if (group.envClasses.includes("multline") &&
74
- ((group.leqno && rowNum !== 0) || (!group.leqno && rowNum !== group.body.length - 1))) {
75
- // A multiline that does not receive a tag. Return an empty cell.
76
- tag = new mathMLTree.MathNode("mtext", [], [])
77
- return tag
78
- } else {
79
- // AMS automatcally numbered equaton.
80
- // Insert a class so the element can be populated by a CSS counter.
81
- // WebKit will display the CSS counter only inside a span.
82
- tag = new mathMLTree.MathNode("mtext", [new Span(["tml-eqn"])])
83
69
  }
84
- return tag
70
+ return rowLabel
71
+ }
72
+
73
+ // autoTag (an argument to parseArray) can be one of three values:
74
+ // * undefined: Regular (not-top-level) array; no tags on each row
75
+ // * true: Automatic equation numbering, overridable by \tag
76
+ // * false: Tags allowed on each row, but no automatic numbering
77
+ // This function *doesn't* work with the "split" environment name.
78
+ function getAutoTag(name) {
79
+ if (name.indexOf("ed") === -1) {
80
+ return name.indexOf("*") === -1;
81
+ }
82
+ // return undefined;
85
83
  }
86
84
 
87
85
  /**
@@ -95,7 +93,7 @@ function parseArray(
95
93
  {
96
94
  cols, // [{ type: string , align: l|c|r|null }]
97
95
  envClasses, // align(ed|at|edat) | array | cases | cd | small | multline
98
- addEqnNum, // boolean
96
+ autoTag, // boolean
99
97
  singleRow, // boolean
100
98
  emptySingleRow, // boolean
101
99
  maxNumCols, // number
@@ -111,13 +109,6 @@ function parseArray(
111
109
  // TODO: provide helpful error when \cr is used outside array environment
112
110
  parser.gullet.macros.set("\\cr", "\\\\\\relax");
113
111
  }
114
- if (addEqnNum) {
115
- parser.gullet.macros.set("\\tag", "\\@ifstar\\envtag@literal\\envtag@paren")
116
- parser.gullet.macros.set("\\envtag@paren", "\\env@tag{{(\\text{#1})}}");
117
- parser.gullet.macros.set("\\envtag@literal", "\\env@tag{\\text{#1}}")
118
- parser.gullet.macros.set("\\notag", "\\env@notag");
119
- parser.gullet.macros.set("\\nonumber", "\\env@notag")
120
- }
121
112
 
122
113
  // Start group for first cell
123
114
  parser.gullet.beginGroup();
@@ -125,29 +116,39 @@ function parseArray(
125
116
  let row = [];
126
117
  const body = [row];
127
118
  const rowGaps = [];
128
- const tags = [];
129
- let rowTag;
119
+ const labels = [];
120
+
130
121
  const hLinesBeforeRow = [];
131
122
 
123
+ const tags = (autoTag != null ? [] : undefined);
124
+
125
+ // amsmath uses \global\@eqnswtrue and \global\@eqnswfalse to represent
126
+ // whether this row should have an equation number. Simulate this with
127
+ // a \@eqnsw macro set to 1 or 0.
128
+ function beginRow() {
129
+ if (autoTag) {
130
+ parser.gullet.macros.set("\\@eqnsw", "1", true);
131
+ }
132
+ }
133
+ function endRow() {
134
+ if (tags) {
135
+ if (parser.gullet.macros.get("\\df@tag")) {
136
+ tags.push(parser.subparse([new Token("\\df@tag")]));
137
+ parser.gullet.macros.set("\\df@tag", undefined, true);
138
+ } else {
139
+ tags.push(Boolean(autoTag) &&
140
+ parser.gullet.macros.get("\\@eqnsw") === "1");
141
+ }
142
+ }
143
+ }
144
+ beginRow();
145
+
132
146
  // Test for \hline at the top of the array.
133
147
  hLinesBeforeRow.push(getHLines(parser));
134
148
 
135
149
  while (true) {
136
150
  // Parse each cell in its own group (namespace)
137
151
  let cell = parser.parseExpression(false, singleRow ? "\\end" : "\\\\");
138
-
139
- if (addEqnNum && !rowTag) {
140
- // Check if the author wrote a \tag{} inside this cell.
141
- for (let i = 0; i < cell.length; i++) {
142
- if (cell[i].type === "envTag" || cell[i].type === "noTag") {
143
- // Get the contents of the \text{} nested inside the \env@Tag{}
144
- rowTag = cell[i].type === "envTag"
145
- ? cell.splice(i, 1)[0].body.body[0]
146
- : { body: null };
147
- break
148
- }
149
- }
150
- }
151
152
  parser.gullet.endGroup();
152
153
  parser.gullet.beginGroup();
153
154
 
@@ -176,6 +177,7 @@ function parseArray(
176
177
  }
177
178
  parser.consume();
178
179
  } else if (next === "\\end") {
180
+ endRow()
179
181
  // Arrays terminate newlines with `\crcr` which consumes a `\cr` if
180
182
  // the last line is empty. However, AMS environments keep the
181
183
  // empty row if it's the only one.
@@ -183,6 +185,7 @@ function parseArray(
183
185
  if (row.length === 1 && cell.body.length === 0 && (body.length > 1 || !emptySingleRow)) {
184
186
  body.pop();
185
187
  }
188
+ labels.push(checkCellForLabels(cell.body))
186
189
  if (hLinesBeforeRow.length < body.length + 1) {
187
190
  hLinesBeforeRow.push([]);
188
191
  }
@@ -198,16 +201,17 @@ function parseArray(
198
201
  if (parser.gullet.future().text !== " ") {
199
202
  size = parser.parseSizeGroup(true);
200
203
  }
201
- rowGaps.push(size ? size.value : null);
204
+ rowGaps.push(size ? size.value : null)
205
+ endRow()
202
206
 
203
- tags.push(rowTag)
207
+ labels.push(checkCellForLabels(cell.body))
204
208
 
205
209
  // check for \hline(s) following the row separator
206
210
  hLinesBeforeRow.push(getHLines(parser));
207
211
 
208
212
  row = [];
209
- rowTag = null;
210
213
  body.push(row);
214
+ beginRow();
211
215
  } else {
212
216
  throw new ParseError("Expected & or \\\\ or \\cr or \\end", parser.nextToken);
213
217
  }
@@ -218,8 +222,6 @@ function parseArray(
218
222
  // End array group defining \cr
219
223
  parser.gullet.endGroup();
220
224
 
221
- tags.push(rowTag)
222
-
223
225
  return {
224
226
  type: "array",
225
227
  mode: parser.mode,
@@ -228,9 +230,10 @@ function parseArray(
228
230
  rowGaps,
229
231
  hLinesBeforeRow,
230
232
  envClasses,
231
- addEqnNum,
233
+ autoTag,
232
234
  scriptLevel,
233
235
  tags,
236
+ labels,
234
237
  leqno,
235
238
  arraystretch,
236
239
  arraycolsep
@@ -287,19 +290,43 @@ const mathmlBuilder = function(group, style) {
287
290
  }
288
291
  row.push(mtd)
289
292
  }
290
- if (group.addEqnNum) {
291
- row.unshift(glue(group));
292
- row.push(glue(group));
293
- const tag = getTag(group, style.withLevel(cellLevel), i)
294
- if (group.leqno) {
295
- row[0].children.push(tag)
296
- row[0].classes.push("tml-left")
297
- } else {
298
- row[row.length - 1].children.push(tag)
299
- row[row.length - 1].classes.push("tml-right")
293
+ const numColumns = group.body[0].length
294
+ // Fill out a short row with empty <mtd> elements.
295
+ for (let k = 0; k < numColumns - rw.length; k++) {
296
+ row.push(new mathMLTree.MathNode("mtd", [], style))
297
+ }
298
+ if (group.autoTag) {
299
+ const tag = group.tags[i];
300
+ let tagElement
301
+ if (tag === true) { // automatic numbering
302
+ tagElement = new mathMLTree.MathNode("mtext", [new Span(["tml-eqn"])])
303
+ } else if (tag === false) {
304
+ // \nonumber/\notag or starred environment
305
+ tagElement = new mathMLTree.MathNode("mtext", [], [])
306
+ } else { // manual \tag
307
+ tagElement = mml.buildExpressionRow(tag[0].body, style.withLevel(cellLevel), true)
308
+ tagElement = mml.consolidateText(tagElement)
309
+ tagElement.classes = ["tml-tag"]
310
+ }
311
+ if (tagElement) {
312
+ row.unshift(glue(group))
313
+ row.push(glue(group))
314
+ if (group.leqno) {
315
+ row[0].children.push(tagElement)
316
+ row[0].classes.push("tml-left")
317
+ } else {
318
+ row[row.length - 1].children.push(tagElement)
319
+ row[row.length - 1].classes.push("tml-right")
320
+ }
300
321
  }
301
322
  }
302
323
  const mtr = new mathMLTree.MathNode("mtr", row, [])
324
+ const label = group.labels.shift()
325
+ if (label && group.tags && group.tags[i]) {
326
+ mtr.setAttribute("id", label)
327
+ if (Array.isArray(group.tags[i])) { mtr.classes.push("tml-tageqn") }
328
+ }
329
+
303
330
  // Write horizontal rules
304
331
  if (i === 0 && hlines[0].length > 0) {
305
332
  if (hlines[0].length === 2) {
@@ -323,16 +350,17 @@ const mathmlBuilder = function(group, style) {
323
350
  }
324
351
 
325
352
  if (group.envClasses.length > 0) {
326
- let pad = group.envClasses.includes("jot")
327
- ? "0.7" // 0.5ex + 0.09em top & bot padding
328
- : group.envClasses.includes("small")
329
- ? "0.35"
330
- : "0.5" // 0.5ex default top & bot padding
331
353
  if (group.arraystretch && group.arraystretch !== 1) {
332
354
  // In LaTeX, \arraystretch is a factor applied to a 12pt strut height.
333
355
  // It defines a baseline to baseline distance.
334
356
  // Here, we do an approximation of that approach.
335
- pad = String(1.4 * group.arraystretch - 0.8)
357
+ const pad = String(1.4 * group.arraystretch - 0.8) + "ex"
358
+ for (let i = 0; i < tbl.length; i++) {
359
+ for (let j = 0; j < tbl[i].children.length; j++) {
360
+ tbl[i].children[j].style.paddingTop = pad
361
+ tbl[i].children[j].style.paddingBottom = pad
362
+ }
363
+ }
336
364
  }
337
365
  let sidePadding = group.envClasses.includes("abut")
338
366
  ? "0"
@@ -346,7 +374,7 @@ const mathmlBuilder = function(group, style) {
346
374
  let sidePadUnit = "em"
347
375
  if (group.arraycolsep) {
348
376
  const arraySidePad = calculateSize(group.arraycolsep, style)
349
- sidePadding = arraySidePad.number
377
+ sidePadding = arraySidePad.number.toFixed(4)
350
378
  sidePadUnit = arraySidePad.unit
351
379
  }
352
380
 
@@ -357,18 +385,18 @@ const mathmlBuilder = function(group, style) {
357
385
  if (j === numCols - 1 && hand === 1) { return "0" }
358
386
  if (group.envClasses[0] !== "align") { return sidePadding }
359
387
  if (hand === 1) { return "0" }
360
- if (group.addEqnNum) {
388
+ if (group.autoTag) {
361
389
  return (j % 2) ? "1" : "0"
362
390
  } else {
363
391
  return (j % 2) ? "0" : "1"
364
392
  }
365
393
  }
366
394
 
367
- // Padding
395
+ // Side padding
368
396
  for (let i = 0; i < tbl.length; i++) {
369
397
  for (let j = 0; j < tbl[i].children.length; j++) {
370
- tbl[i].children[j].style.padding = `${pad}ex ${sidePad(j, 1)}${sidePadUnit}`
371
- + ` ${pad}ex ${sidePad(j, 0)}${sidePadUnit}`
398
+ tbl[i].children[j].style.paddingLeft = `${sidePad(j, 0)}${sidePadUnit}`
399
+ tbl[i].children[j].style.paddingRight = `${sidePad(j, 1)}${sidePadUnit}`
372
400
  }
373
401
  }
374
402
 
@@ -382,13 +410,13 @@ const mathmlBuilder = function(group, style) {
382
410
  // TODO: Remove -webkit- when Chromium no longer needs it.
383
411
  row.children[j].classes = ["tml-" + (j % 2 ? "left" : "right")]
384
412
  }
385
- if (group.addEqnNum) {
413
+ if (group.autoTag) {
386
414
  const k = group.leqno ? 0 : row.children.length - 1
387
415
  row.children[k].classes = ["tml-" + (group.leqno ? "left" : "right")]
388
416
  }
389
417
  }
390
418
  if (row.children.length > 1 && group.envClasses.includes("cases")) {
391
- row.children[1].style.padding = row.children[1].style.padding.replace(/0em$/, "1em")
419
+ row.children[1].style.paddingLeft = "1em"
392
420
  }
393
421
 
394
422
  if (group.envClasses.includes("cases") || group.envClasses.includes("subarray")) {
@@ -408,9 +436,17 @@ const mathmlBuilder = function(group, style) {
408
436
  }
409
437
 
410
438
  let table = new mathMLTree.MathNode("mtable", tbl)
439
+ if (group.envClasses.length > 0) {
440
+ // Top & bottom padding
441
+ if (group.envClasses.includes("jot")) {
442
+ table.classes.push("tml-jot")
443
+ } else if (group.envClasses.includes("small")) {
444
+ table.classes.push("tml-small")
445
+ }
446
+ }
411
447
  if (group.scriptLevel === "display") { table.setAttribute("displaystyle", "true") }
412
448
 
413
- if (group.addEqnNum || group.envClasses.includes("multline")) {
449
+ if (group.autoTag || group.envClasses.includes("multline")) {
414
450
  table.style.width = "100%"
415
451
  }
416
452
 
@@ -440,7 +476,7 @@ const mathmlBuilder = function(group, style) {
440
476
  row.children[0].style.borderLeft = sep
441
477
  }
442
478
  }
443
- let iCol = group.addEqnNum ? 0 : -1
479
+ let iCol = group.autoTag ? 0 : -1
444
480
  for (let i = iStart; i < iEnd; i++) {
445
481
  if (cols[i].type === "align") {
446
482
  const colAlign = alignMap[cols[i].align];
@@ -482,7 +518,7 @@ const mathmlBuilder = function(group, style) {
482
518
  }
483
519
  }
484
520
  }
485
- if (group.addEqnNum) {
521
+ if (group.autoTag) {
486
522
  // allow for glue cells on each side
487
523
  align = "left " + (align.length > 0 ? align : "center ") + "right "
488
524
  }
@@ -506,13 +542,14 @@ const alignedHandler = function(context, args) {
506
542
  if (context.envName.indexOf("ed") === -1) {
507
543
  validateAmsEnvironmentContext(context);
508
544
  }
545
+ const isSplit = context.envName === "split";
509
546
  const cols = [];
510
547
  const res = parseArray(
511
548
  context.parser,
512
549
  {
513
550
  cols,
514
- addEqnNum: context.envName === "align" || context.envName === "alignat",
515
551
  emptySingleRow: true,
552
+ autoTag: isSplit ? undefined : getAutoTag(context.envName),
516
553
  envClasses: ["abut", "jot"], // set row spacing & provisional column spacing
517
554
  maxNumCols: context.envName === "split" ? 2 : undefined,
518
555
  leqno: context.parser.settings.leqno
@@ -836,7 +873,7 @@ defineEnvironment({
836
873
  const res = {
837
874
  cols: [],
838
875
  envClasses: ["abut", "jot"],
839
- addEqnNum: context.envName === "gather",
876
+ autoTag: getAutoTag(context.envName),
840
877
  emptySingleRow: true,
841
878
  leqno: context.parser.settings.leqno
842
879
  };
@@ -854,7 +891,7 @@ defineEnvironment({
854
891
  handler(context) {
855
892
  validateAmsEnvironmentContext(context);
856
893
  const res = {
857
- addEqnNum: context.envName === "equation",
894
+ autoTag: getAutoTag(context.envName),
858
895
  emptySingleRow: true,
859
896
  singleRow: true,
860
897
  maxNumCols: 1,
@@ -875,7 +912,7 @@ defineEnvironment({
875
912
  handler(context) {
876
913
  validateAmsEnvironmentContext(context);
877
914
  const res = {
878
- addEqnNum: context.envName === "multline",
915
+ autoTag: context.envName === "multline",
879
916
  maxNumCols: 1,
880
917
  envClasses: ["jot", "multline"],
881
918
  leqno: context.parser.settings.leqno
@@ -190,6 +190,8 @@ export function parseCD(parser) {
190
190
  type: "array",
191
191
  mode: "math",
192
192
  body,
193
+ tags: null,
194
+ labels: new Array(body.length + 1).fill(""),
193
195
  envClasses: ["jot", "cd"],
194
196
  cols: [],
195
197
  hLinesBeforeRow: new Array(body.length + 1).fill([])
@@ -22,7 +22,7 @@ defineFunction({
22
22
  // Return a no-width, no-ink element with an HTML id.
23
23
  const node = new mathMLTree.MathNode("mrow", [], ["tml-label"])
24
24
  if (group.string.length > 0) {
25
- node.setAttribute("id", group.string)
25
+ node.setLabel(group.string)
26
26
  }
27
27
  return node
28
28
  }
@@ -58,7 +58,7 @@ export default function setLineBreaks(expression, wrapMode, isDisplayMode) {
58
58
  }
59
59
  block.push(node);
60
60
  if (node.type && node.type === "mo" && node.children.length === 1 &&
61
- !Object.hasOwn(node.attributes, "movablelimits")) {
61
+ !Object.prototype.hasOwnProperty.call(node.attributes, "movablelimits")) {
62
62
  const ch = node.children[0].text
63
63
  if (openDelims.indexOf(ch) > -1) {
64
64
  level += 1
package/src/macros.js CHANGED
@@ -463,8 +463,10 @@ defineMacro("\\tag@literal", (context) => {
463
463
  if (context.macros.get("\\df@tag")) {
464
464
  throw new ParseError("Multiple \\tag");
465
465
  }
466
- return "\\def\\df@tag{\\text{#1}}";
466
+ return "\\gdef\\df@tag{\\text{#1}}";
467
467
  });
468
+ defineMacro("\\notag", "\\nonumber");
469
+ defineMacro("\\nonumber", "\\gdef\\@eqnsw{0}")
468
470
 
469
471
  // \renewcommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin
470
472
  // {\operator@font mod}\penalty900
package/src/mathMLTree.js CHANGED
@@ -25,6 +25,7 @@ export class MathNode {
25
25
  this.children = children || [];
26
26
  this.classes = classes || [];
27
27
  this.style = style || {}; // Used for <mstyle> elements
28
+ this.label = "";
28
29
  }
29
30
 
30
31
  /**
@@ -42,6 +43,10 @@ export class MathNode {
42
43
  return this.attributes[name];
43
44
  }
44
45
 
46
+ setLabel(value) {
47
+ this.label = value
48
+ }
49
+
45
50
  /**
46
51
  * Converts the math node into a MathML-namespaced DOM element.
47
52
  */
@@ -5,7 +5,7 @@
5
5
  * https://mit-license.org/
6
6
  */
7
7
 
8
- export const version = "0.10.33";
8
+ export const version = "0.11.00";
9
9
 
10
10
  export function postProcess(block) {
11
11
  const labelMap = {}
@@ -21,15 +21,15 @@ export function postProcess(block) {
21
21
  // No need to write a number into the text content of the element.
22
22
  // A CSS counter has done that even if this postProcess() function is not used.
23
23
 
24
- // Find any \label that refers to an AMS eqn number.
24
+ // Find any \label that refers to an AMS automatic eqn number.
25
25
  while (true) {
26
+ if (parent.tagName === "mtable") { break }
26
27
  const labels = parent.getElementsByClassName("tml-label")
27
28
  if (labels.length > 0) {
28
- parent.setAttribute("id", labels[0].id)
29
- labelMap[labels[0].id] = String(i)
29
+ const id = parent.attributes.id.value
30
+ labelMap[id] = String(i)
30
31
  break
31
32
  } else {
32
- if (parent.tagName === "mtable") { break }
33
33
  parent = parent.parentElement
34
34
  }
35
35
  }
@@ -42,7 +42,8 @@ export function postProcess(block) {
42
42
  if (labels.length > 0) {
43
43
  const tags = parent.getElementsByClassName("tml-tag")
44
44
  if (tags.length > 0) {
45
- labelMap[labels[0].id] = tags[0].textContent
45
+ const id = parent.attributes.id.value
46
+ labelMap[id] = tags[0].textContent
46
47
  }
47
48
  }
48
49
  }
package/src/symbols.js CHANGED
@@ -670,7 +670,7 @@ defineSymbol(math, mathord, "\u03db", "\\stigma", true);
670
670
  defineSymbol(math, mathord, "\u2aeb", "\\Bot");
671
671
  defineSymbol(math, bin, "\u2217", "\u2217", true);
672
672
  defineSymbol(math, bin, "+", "+");
673
- defineSymbol(math, bin, "*", "*");
673
+ defineSymbol(math, bin, "\u2217", "*");
674
674
  defineSymbol(math, bin, "\u2044", "/", true);
675
675
  defineSymbol(math, bin, "\u2044", "\u2044");
676
676
  defineSymbol(math, bin, "\u2212", "-", true);
package/temml.js CHANGED
@@ -19,6 +19,7 @@ import { Span, TextNode } from "./src/domTree";
19
19
  import { defineSymbol } from "./src/symbols";
20
20
  import defineMacro from "./src/defineMacro";
21
21
  import { postProcess, version } from "./src/postProcess";
22
+ import { renderMathInElement } from "./src/auto-render"
22
23
 
23
24
  /**
24
25
  * @type {import('./temml').render}
@@ -144,6 +145,11 @@ export default {
144
145
  * for sending to the client.
145
146
  */
146
147
  renderToString,
148
+ /**
149
+ * Finds all the math delimiters in a given element of a running HTML document
150
+ * and converts the contents of each instance into a <math> element.
151
+ */
152
+ renderMathInElement,
147
153
  /**
148
154
  * Post-process an entire HTML block.
149
155
  * Writes AMS auto-numbers and implements \ref{}.
@@ -1,89 +0,0 @@
1
- # Auto-render extension
2
-
3
- This is a client-side extension to automatically render all of the math inside of the
4
- text of a running HTML document. It searches all of the text nodes in a given element
5
- for the given delimiters, and renders the math in place.
6
-
7
-
8
- This extension isn't part of Temml proper, so the script needs to be included
9
- (via a `<script>` tag) in the page along with Temml itself. For example:
10
-
11
- ```html
12
- <head>
13
- ...
14
- <link rel="stylesheet" href="./Temml-Local.css">
15
- <script src="./temml.min.js"></script>
16
- <script src="./auto-render.min.js"></script>
17
- ...
18
- </head>
19
- <body>
20
- ...
21
- <script>renderMathInElement(document.body);</script>
22
- </body>
23
- ```
24
-
25
- The auto-render extension exposes a single function, `window.renderMathInElement`, with
26
- the following API:
27
-
28
- ```js
29
- function renderMathInElement(elem, options)
30
- ```
31
-
32
- `elem` is an HTML DOM element, typically `document.main`. The function will
33
- recursively search for text nodes inside this element and render the math in them.
34
-
35
- `options` is an optional object argument that can have the same keys as [the
36
- options](https://temml.org/docs/en/administration.html#options) passed to
37
- `temml.render`. In addition, there are five auto-render-specific keys:
38
-
39
- - `delimiters`: This is a list of delimiters to look for math, processed in
40
- the same order as the list. Each delimiter has three properties:
41
-
42
- - `left`: A string which starts the math expression (i.e. the left delimiter).
43
- - `right`: A string which ends the math expression (i.e. the right delimiter).
44
- - `display`: A boolean of whether the math in the expression should be
45
- rendered in display mode or not.
46
-
47
- The default `delimiters` value is:
48
-
49
- ```js
50
- [
51
- { left: "$$", right: "$$", display: true },
52
- { left: "\\(", right: "\\)", display: false },
53
- { left: "\\begin{equation}", right: "\\end{equation}", display: true },
54
- { left: "\\begin{align}", right: "\\end{align}", display: true },
55
- { left: "\\begin{alignat}", right: "\\end{alignat}", display: true },
56
- { left: "\\begin{gather}", right: "\\end{gather}", display: true },
57
- { left: "\\begin{CD}", right: "\\end{CD}", display: true },
58
- { left: "\\begin{multline}", right: "\\end{multline}", display: true },
59
- { left: "\\[", right: "\\]", display: true }
60
- ]
61
- ```
62
-
63
- If you want to add support for inline math via `$…$`, be sure to list it
64
- **after** `$$…$$`. Because rules are processed in order, putting a `$` rule first would
65
- match `$$` and treat as an empty math expression. Here is an example that includes `$…$`:
66
-
67
- ```js
68
- [
69
- {left: "$$", right: "$$", display: true},
70
- // Put $ after $$.
71
- {left: "$", right: "$", display: false},
72
- {left: "\\(", right: "\\)", display: false},
73
- // Put \[ last to avoid conflict with possible future \\[1em] row separator.
74
- {left: "\\[", right: "\\]", display: true}
75
- ]
76
- ```
77
-
78
- - `ignoredTags`: This is a list of DOM node types to ignore when recursing
79
- through. The default value is
80
- `["script", "noscript", "style", "textarea", "pre", "code", "option"]`.
81
-
82
- - `ignoredClasses`: This is a list of DOM node class names to ignore when
83
- recursing through. By default, this value is not set.
84
-
85
- - `errorCallback`: A callback method returning a message and an error stack
86
- in case of an critical error during rendering. The default uses `console.error`.
87
-
88
- - `preProcess`: A callback function, `(math: string) => string`, used to process
89
- math expressions before rendering.