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/README.md +1 -1
- package/dist/Temml-Asana.css +16 -1
- package/dist/Temml-Fira.css +16 -1
- package/dist/Temml-Latin-Modern.css +16 -1
- package/dist/Temml-Libertinus.css +16 -1
- package/dist/Temml-Local.css +16 -1
- package/dist/Temml-STIX2.css +16 -1
- package/dist/temml.cjs +473 -283
- package/dist/temml.js +473 -283
- package/dist/temml.min.js +1 -1
- package/dist/temml.mjs +473 -283
- package/dist/temmlPostProcess.js +39 -25
- package/package.json +1 -1
- package/src/Style.js +5 -3
- package/src/buildMathML.js +104 -62
- package/src/domTree.js +34 -0
- package/src/environments/array.js +119 -82
- package/src/environments/cd.js +17 -10
- package/src/functions/arrow.js +11 -3
- package/src/functions/def.js +7 -4
- package/src/functions/delimsizing.js +1 -0
- package/src/functions/font.js +1 -0
- package/src/functions/genfrac.js +13 -4
- package/src/functions/href.js +4 -6
- package/src/functions/label.js +1 -1
- package/src/functions/op.js +0 -7
- package/src/functions/ref.js +3 -5
- package/src/functions/rule.js +2 -0
- package/src/functions/supsub.js +12 -3
- package/src/functions/vcenter.js +30 -0
- package/src/functions.js +1 -0
- package/src/macros.js +4 -2
- package/src/mathMLTree.js +5 -0
- package/src/postProcess.js +39 -25
- package/src/symbols.js +3 -3
- package/src/variant.js +2 -0
package/dist/temmlPostProcess.js
CHANGED
@@ -5,42 +5,51 @@
|
|
5
5
|
})(this, (function (exports) { 'use strict';
|
6
6
|
|
7
7
|
/* Temml Post Process
|
8
|
-
*
|
9
|
-
* Given a block,
|
10
|
-
* 1. At each AMS auto-numbered environment, assign an id.
|
11
|
-
* 2. Populate the text contents of each \ref & \eqref
|
8
|
+
* Populate the text contents of each \ref & \eqref
|
12
9
|
*
|
13
10
|
* As with other Temml code, this file is released under terms of the MIT license.
|
14
11
|
* https://mit-license.org/
|
15
12
|
*/
|
16
13
|
|
17
|
-
const version = "0.10.
|
14
|
+
const version = "0.10.34";
|
18
15
|
|
19
16
|
function postProcess(block) {
|
20
17
|
const labelMap = {};
|
21
18
|
let i = 0;
|
22
19
|
|
23
20
|
// Get a collection of the parents of each \tag & auto-numbered equation
|
24
|
-
const
|
25
|
-
for (
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
21
|
+
const amsEqns = document.getElementsByClassName('tml-eqn');
|
22
|
+
for (let parent of amsEqns) {
|
23
|
+
// AMS automatically numbered equation.
|
24
|
+
// Assign an id.
|
25
|
+
i += 1;
|
26
|
+
parent.setAttribute("id", "tml-eqn-" + String(i));
|
27
|
+
// No need to write a number into the text content of the element.
|
28
|
+
// A CSS counter has done that even if this postProcess() function is not used.
|
29
|
+
|
30
|
+
// Find any \label that refers to an AMS automatic eqn number.
|
31
|
+
while (true) {
|
32
|
+
if (parent.tagName === "mtable") { break }
|
33
|
+
const labels = parent.getElementsByClassName("tml-label");
|
34
|
+
if (labels.length > 0) {
|
35
|
+
const id = parent.attributes.id.value;
|
36
|
+
labelMap[id] = String(i);
|
37
|
+
break
|
38
|
+
} else {
|
39
|
+
parent = parent.parentElement;
|
40
|
+
}
|
34
41
|
}
|
35
|
-
|
42
|
+
}
|
43
|
+
|
44
|
+
// Find \labels associated with \tag
|
45
|
+
const taggedEqns = document.getElementsByClassName('tml-tageqn');
|
46
|
+
for (const parent of taggedEqns) {
|
36
47
|
const labels = parent.getElementsByClassName("tml-label");
|
37
|
-
if (labels.length
|
38
|
-
if (eqns.length > 0) {
|
39
|
-
labelMap[labels[0].id] = String(i);
|
40
|
-
} else {
|
48
|
+
if (labels.length > 0) {
|
41
49
|
const tags = parent.getElementsByClassName("tml-tag");
|
42
50
|
if (tags.length > 0) {
|
43
|
-
|
51
|
+
const id = parent.attributes.id.value;
|
52
|
+
labelMap[id] = tags[0].textContent;
|
44
53
|
}
|
45
54
|
}
|
46
55
|
}
|
@@ -48,17 +57,22 @@
|
|
48
57
|
// Populate \ref & \eqref text content
|
49
58
|
const refs = block.getElementsByClassName("tml-ref");
|
50
59
|
[...refs].forEach(ref => {
|
51
|
-
|
60
|
+
const attr = ref.getAttribute("href");
|
61
|
+
let str = labelMap[attr.slice(1)];
|
52
62
|
if (ref.className.indexOf("tml-eqref") === -1) {
|
53
63
|
// \ref. Omit parens.
|
54
64
|
str = str.replace(/^\(/, "");
|
55
|
-
str = str.replace(/\
|
56
|
-
}
|
65
|
+
str = str.replace(/\)$/, "");
|
66
|
+
} else {
|
57
67
|
// \eqref. Include parens
|
58
68
|
if (str.charAt(0) !== "(") { str = "(" + str; }
|
59
69
|
if (str.slice(-1) !== ")") { str = str + ")"; }
|
60
70
|
}
|
61
|
-
|
71
|
+
const mtext = document.createElementNS("http://www.w3.org/1998/Math/MathML", "mtext");
|
72
|
+
mtext.appendChild(document.createTextNode(str));
|
73
|
+
const math = document.createElementNS("http://www.w3.org/1998/Math/MathML", "math");
|
74
|
+
math.appendChild(mtext);
|
75
|
+
ref.appendChild(math);
|
62
76
|
});
|
63
77
|
}
|
64
78
|
|
package/package.json
CHANGED
package/src/Style.js
CHANGED
@@ -16,9 +16,11 @@ class Style {
|
|
16
16
|
constructor(data) {
|
17
17
|
// Style.level can be 0 | 1 | 2 | 3, which correspond to
|
18
18
|
// displaystyle, textstyle, scriptstyle, and scriptscriptstyle.
|
19
|
-
// style.level does not directly set MathML's script level. MathML does that itself.
|
20
|
-
//
|
21
|
-
//
|
19
|
+
// style.level usually does not directly set MathML's script level. MathML does that itself.
|
20
|
+
// However, Chromium does not stop shrinking after scriptscriptstyle, so we do explicitly
|
21
|
+
// set a scriptlevel attribute in those conditions.
|
22
|
+
// We also use style.level to track math style so that we can get the correct
|
23
|
+
// scriptlevel when needed in supsub.js, mathchoice.js, or for dimensions in em.
|
22
24
|
this.level = data.level;
|
23
25
|
this.color = data.color; // string | void
|
24
26
|
// A font family applies to a group of fonts (i.e. SansSerif), while a font
|
package/src/buildMathML.js
CHANGED
@@ -8,9 +8,10 @@ import mathMLTree from "./mathMLTree"
|
|
8
8
|
import ParseError from "./ParseError"
|
9
9
|
import symbols, { ligatures } from "./symbols"
|
10
10
|
import { _mathmlGroupBuilders as groupBuilders } from "./defineFunction"
|
11
|
-
import { MathNode } from "./mathMLTree"
|
11
|
+
import { MathNode, TextNode } from "./mathMLTree"
|
12
12
|
import { DocumentFragment } from "./tree"
|
13
13
|
import setLineBreaks from "./linebreaking"
|
14
|
+
import { AnchorNode } from "./domTree"
|
14
15
|
|
15
16
|
/**
|
16
17
|
* Takes a symbol and converts it into a MathML text node after performing
|
@@ -102,61 +103,6 @@ export const consolidateText = mrow => {
|
|
102
103
|
}
|
103
104
|
}
|
104
105
|
|
105
|
-
const numberRegEx = /^[0-9]$/
|
106
|
-
const isDotOrComma = (node, followingNode) => {
|
107
|
-
return ((node.type === "textord" && node.text === ".") ||
|
108
|
-
(node.type === "atom" && node.text === ",")) &&
|
109
|
-
// Don't consolidate if there is a space after the comma.
|
110
|
-
node.loc && followingNode.loc && node.loc.end === followingNode.loc.start
|
111
|
-
}
|
112
|
-
const consolidateNumbers = expression => {
|
113
|
-
// Consolidate adjacent numbers. We want to return <mn>1,506.3</mn>,
|
114
|
-
// not <mn>1</mn><mo>,</mo><mn>5</mn><mn>0</mn><mn>6</mn><mi>.</mi><mn>3</mn>
|
115
|
-
if (expression.length < 2) { return }
|
116
|
-
const nums = [];
|
117
|
-
let inNum = false
|
118
|
-
// Find adjacent numerals
|
119
|
-
for (let i = 0; i < expression.length; i++) {
|
120
|
-
const node = expression[i];
|
121
|
-
if (node.type === "textord" && numberRegEx.test(node.text)) {
|
122
|
-
if (!inNum) { nums.push({ start: i }) }
|
123
|
-
inNum = true
|
124
|
-
} else {
|
125
|
-
if (inNum) { nums[nums.length - 1].end = i - 1 }
|
126
|
-
inNum = false
|
127
|
-
}
|
128
|
-
}
|
129
|
-
if (inNum) { nums[nums.length - 1].end = expression.length - 1 }
|
130
|
-
|
131
|
-
// Determine if numeral groups are separated by a comma or dot.
|
132
|
-
for (let i = nums.length - 1; i > 0; i--) {
|
133
|
-
if (nums[i - 1].end === nums[i].start - 2 &&
|
134
|
-
isDotOrComma(expression[nums[i].start - 1], expression[nums[i].start])) {
|
135
|
-
// Merge the two groups.
|
136
|
-
nums[i - 1].end = nums[i].end
|
137
|
-
nums.splice(i, 1)
|
138
|
-
}
|
139
|
-
}
|
140
|
-
|
141
|
-
// Consolidate the number nodes
|
142
|
-
for (let i = nums.length - 1; i >= 0; i--) {
|
143
|
-
for (let j = nums[i].start + 1; j <= nums[i].end; j++) {
|
144
|
-
expression[nums[i].start].text += expression[j].text
|
145
|
-
}
|
146
|
-
expression.splice(nums[i].start + 1, nums[i].end - nums[i].start)
|
147
|
-
// Check if the <mn> is followed by a numeric base in a supsub, e.g. the "3" in 123^4
|
148
|
-
// If so, merge the first <mn> into the base.
|
149
|
-
if (expression.length > nums[i].start + 1) {
|
150
|
-
const nextTerm = expression[nums[i].start + 1];
|
151
|
-
if (nextTerm.type === "supsub" && nextTerm.base && nextTerm.base.type === "textord" &&
|
152
|
-
numberRegEx.test(nextTerm.base.text)) {
|
153
|
-
nextTerm.base.text = expression[nums[i].start].text + nextTerm.base.text
|
154
|
-
expression.splice(nums[i].start, 1)
|
155
|
-
}
|
156
|
-
}
|
157
|
-
}
|
158
|
-
}
|
159
|
-
|
160
106
|
/**
|
161
107
|
* Wrap the given array of nodes in an <mrow> node if needed, i.e.,
|
162
108
|
* unless the array has length 1. Always returns a single node.
|
@@ -179,6 +125,39 @@ export const makeRow = function(body, semisimple = false) {
|
|
179
125
|
return new mathMLTree.MathNode("mrow", body);
|
180
126
|
};
|
181
127
|
|
128
|
+
/**
|
129
|
+
* Check for <mi>.</mi> which is how a dot renders in MathML,
|
130
|
+
* or <mo separator="true" lspace="0em" rspace="0em">,</mo>
|
131
|
+
* which is how a braced comma {,} renders in MathML
|
132
|
+
*/
|
133
|
+
function isNumberPunctuation(group) {
|
134
|
+
if (!group) {
|
135
|
+
return false
|
136
|
+
}
|
137
|
+
if (group.type === 'mi' && group.children.length === 1) {
|
138
|
+
const child = group.children[0];
|
139
|
+
return child instanceof TextNode && child.text === '.'
|
140
|
+
} else if (group.type === "mtext" && group.children.length === 1) {
|
141
|
+
const child = group.children[0];
|
142
|
+
return child instanceof TextNode && child.text === '\u2008' // punctuation space
|
143
|
+
} else if (group.type === 'mo' && group.children.length === 1 &&
|
144
|
+
group.getAttribute('separator') === 'true' &&
|
145
|
+
group.getAttribute('lspace') === '0em' &&
|
146
|
+
group.getAttribute('rspace') === '0em') {
|
147
|
+
const child = group.children[0];
|
148
|
+
return child instanceof TextNode && child.text === ','
|
149
|
+
} else {
|
150
|
+
return false
|
151
|
+
}
|
152
|
+
}
|
153
|
+
const isComma = (expression, i) => {
|
154
|
+
const node = expression[i];
|
155
|
+
const followingNode = expression[i + 1];
|
156
|
+
return (node.type === "atom" && node.text === ",") &&
|
157
|
+
// Don't consolidate if there is a space after the comma.
|
158
|
+
node.loc && followingNode.loc && node.loc.end === followingNode.loc.start
|
159
|
+
}
|
160
|
+
|
182
161
|
const isRel = item => {
|
183
162
|
return (item.type === "atom" && item.family === "rel") ||
|
184
163
|
(item.type === "mclass" && item.mclass === "mrel")
|
@@ -202,11 +181,16 @@ export const buildExpression = function(expression, style, semisimple = false) {
|
|
202
181
|
return [group];
|
203
182
|
}
|
204
183
|
|
205
|
-
consolidateNumbers(expression)
|
206
|
-
|
207
184
|
const groups = [];
|
185
|
+
const groupArray = [];
|
186
|
+
let lastGroup
|
208
187
|
for (let i = 0; i < expression.length; i++) {
|
209
|
-
|
188
|
+
groupArray.push(buildGroup(expression[i], style))
|
189
|
+
}
|
190
|
+
|
191
|
+
for (let i = 0; i < groupArray.length; i++) {
|
192
|
+
const group = groupArray[i];
|
193
|
+
|
210
194
|
// Suppress spacing between adjacent relations
|
211
195
|
if (i < expression.length - 1 && isRel(expression[i]) && isRel(expression[i + 1])) {
|
212
196
|
group.setAttribute("rspace", "0em")
|
@@ -214,9 +198,39 @@ export const buildExpression = function(expression, style, semisimple = false) {
|
|
214
198
|
if (i > 0 && isRel(expression[i]) && isRel(expression[i - 1])) {
|
215
199
|
group.setAttribute("lspace", "0em")
|
216
200
|
}
|
217
|
-
|
201
|
+
|
202
|
+
// Concatenate numbers
|
203
|
+
if (group.type === 'mn' && lastGroup && lastGroup.type === 'mn') {
|
204
|
+
// Concatenate <mn>...</mn> followed by <mi>.</mi>
|
205
|
+
lastGroup.children.push(...group.children)
|
206
|
+
continue
|
207
|
+
} else if (isNumberPunctuation(group) && lastGroup && lastGroup.type === 'mn') {
|
208
|
+
// Concatenate <mn>...</mn> followed by <mi>.</mi>
|
209
|
+
lastGroup.children.push(...group.children)
|
210
|
+
continue
|
211
|
+
} else if (lastGroup && lastGroup.type === "mn" && i < groupArray.length - 1 &&
|
212
|
+
groupArray[i + 1].type === "mn" && isComma(expression, i)) {
|
213
|
+
lastGroup.children.push(...group.children)
|
214
|
+
continue
|
215
|
+
} else if (group.type === 'mn' && isNumberPunctuation(lastGroup)) {
|
216
|
+
// Concatenate <mi>.</mi> followed by <mn>...</mn>
|
217
|
+
group.children = [...lastGroup.children, ...group.children];
|
218
|
+
groups.pop()
|
219
|
+
} else if ((group.type === 'msup' || group.type === 'msub') &&
|
220
|
+
group.children.length >= 1 && lastGroup &&
|
221
|
+
(lastGroup.type === 'mn' || isNumberPunctuation(lastGroup))) {
|
222
|
+
// Put preceding <mn>...</mn> or <mi>.</mi> inside base of
|
223
|
+
// <msup><mn>...base...</mn>...exponent...</msup> (or <msub>)
|
224
|
+
const base = group.children[0];
|
225
|
+
if (base instanceof MathNode && base.type === 'mn' && lastGroup) {
|
226
|
+
base.children = [...lastGroup.children, ...base.children];
|
227
|
+
groups.pop()
|
228
|
+
}
|
229
|
+
}
|
230
|
+
groups.push(group)
|
231
|
+
lastGroup = group
|
218
232
|
}
|
219
|
-
return groups
|
233
|
+
return groups
|
220
234
|
};
|
221
235
|
|
222
236
|
/**
|
@@ -249,16 +263,36 @@ const glue = _ => {
|
|
249
263
|
return new mathMLTree.MathNode("mtd", [], [], { padding: "0", width: "50%" })
|
250
264
|
}
|
251
265
|
|
266
|
+
const labelContainers = ["mrow", "mtd", "mtable", "mtr"];
|
267
|
+
const getLabel = parent => {
|
268
|
+
for (const node of parent.children) {
|
269
|
+
if (node.type && labelContainers.includes(node.type)) {
|
270
|
+
if (node.classes && node.classes[0] === "tml-label") {
|
271
|
+
const label = node.label
|
272
|
+
return label
|
273
|
+
} else {
|
274
|
+
const label = getLabel(node)
|
275
|
+
if (label) { return label }
|
276
|
+
}
|
277
|
+
} else if (!node.type) {
|
278
|
+
const label = getLabel(node)
|
279
|
+
if (label) { return label }
|
280
|
+
}
|
281
|
+
}
|
282
|
+
}
|
283
|
+
|
252
284
|
const taggedExpression = (expression, tag, style, leqno) => {
|
253
285
|
tag = buildExpressionRow(tag[0].body, style)
|
254
286
|
tag = consolidateText(tag)
|
255
287
|
tag.classes.push("tml-tag")
|
256
288
|
|
289
|
+
const label = getLabel(expression) // from a \label{} function.
|
257
290
|
expression = new mathMLTree.MathNode("mtd", [expression])
|
258
291
|
const rowArray = [glue(), expression, glue()]
|
259
292
|
rowArray[leqno ? 0 : 2].classes.push(leqno ? "tml-left" : "tml-right")
|
260
293
|
rowArray[leqno ? 0 : 2].children.push(tag)
|
261
294
|
const mtr = new mathMLTree.MathNode("mtr", rowArray, ["tml-tageqn"])
|
295
|
+
if (label) { mtr.setAttribute("id", label) }
|
262
296
|
const table = new mathMLTree.MathNode("mtable", [mtr])
|
263
297
|
table.style.width = "100%"
|
264
298
|
table.setAttribute("displaystyle", "true")
|
@@ -277,7 +311,12 @@ export default function buildMathML(tree, texExpression, style, settings) {
|
|
277
311
|
tree = tree[0].body
|
278
312
|
}
|
279
313
|
|
280
|
-
const expression = buildExpression(tree, style)
|
314
|
+
const expression = buildExpression(tree, style)
|
315
|
+
|
316
|
+
if (expression.length === 1 && expression[0] instanceof AnchorNode) {
|
317
|
+
return expression[0]
|
318
|
+
}
|
319
|
+
|
281
320
|
const wrap = (settings.displayMode || settings.annotate) ? "none" : settings.wrap
|
282
321
|
|
283
322
|
const n1 = expression.length === 0 ? null : expression[0]
|
@@ -302,6 +341,9 @@ export default function buildMathML(tree, texExpression, style, settings) {
|
|
302
341
|
if (settings.xml) {
|
303
342
|
math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML")
|
304
343
|
}
|
344
|
+
if (wrapper.style.width) {
|
345
|
+
math.style.width = "100%"
|
346
|
+
}
|
305
347
|
if (settings.displayMode) {
|
306
348
|
math.setAttribute("display", "block");
|
307
349
|
math.style.display = "block math" // necessary in Chromium.
|
package/src/domTree.js
CHANGED
@@ -134,6 +134,40 @@ export class TextNode {
|
|
134
134
|
}
|
135
135
|
}
|
136
136
|
|
137
|
+
// Create an <a href="…"> node.
|
138
|
+
export class AnchorNode {
|
139
|
+
constructor(href, classes, children) {
|
140
|
+
this.href = href;
|
141
|
+
this.classes = classes;
|
142
|
+
this.children = children || [];
|
143
|
+
}
|
144
|
+
|
145
|
+
toNode() {
|
146
|
+
const node = document.createElement("a")
|
147
|
+
node.setAttribute("href", this.href)
|
148
|
+
if (this.classes.length > 0) {
|
149
|
+
node.className = createClass(this.classes)
|
150
|
+
}
|
151
|
+
for (let i = 0; i < this.children.length; i++) {
|
152
|
+
node.appendChild(this.children[i].toNode());
|
153
|
+
}
|
154
|
+
return node
|
155
|
+
}
|
156
|
+
|
157
|
+
toMarkup() {
|
158
|
+
let markup = `<a href='${utils.escape(this.href)}'`
|
159
|
+
if (this.classes.length > 0) {
|
160
|
+
markup += ` class="${utils.escape(createClass(this.classes))}"`
|
161
|
+
}
|
162
|
+
markup += ">"
|
163
|
+
for (let i = 0; i < this.children.length; i++) {
|
164
|
+
markup += this.children[i].toMarkup();
|
165
|
+
}
|
166
|
+
markup += "</a>"
|
167
|
+
return markup
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
137
171
|
/*
|
138
172
|
* This node represents an image embed (<img>) element.
|
139
173
|
*/
|