temml 0.10.32 → 0.10.33
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.cjs +252 -128
- package/dist/temml.js +252 -128
- package/dist/temml.min.js +1 -1
- package/dist/temml.mjs +252 -128
- package/dist/temmlPostProcess.js +37 -24
- package/package.json +1 -1
- package/src/Style.js +5 -3
- package/src/buildMathML.js +84 -62
- package/src/domTree.js +34 -0
- package/src/environments/cd.js +15 -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/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 +1 -1
- package/src/postProcess.js +37 -24
- package/src/symbols.js +2 -2
- package/src/variant.js +2 -0
package/dist/temmlPostProcess.js
CHANGED
@@ -5,39 +5,47 @@
|
|
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.33";
|
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 eqn number.
|
31
|
+
while (true) {
|
32
|
+
const labels = parent.getElementsByClassName("tml-label");
|
33
|
+
if (labels.length > 0) {
|
34
|
+
parent.setAttribute("id", labels[0].id);
|
35
|
+
labelMap[labels[0].id] = String(i);
|
36
|
+
break
|
37
|
+
} else {
|
38
|
+
if (parent.tagName === "mtable") { break }
|
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
|
labelMap[labels[0].id] = tags[0].textContent;
|
@@ -48,17 +56,22 @@
|
|
48
56
|
// Populate \ref & \eqref text content
|
49
57
|
const refs = block.getElementsByClassName("tml-ref");
|
50
58
|
[...refs].forEach(ref => {
|
51
|
-
|
59
|
+
const attr = ref.getAttribute("href");
|
60
|
+
let str = labelMap[attr.slice(1)];
|
52
61
|
if (ref.className.indexOf("tml-eqref") === -1) {
|
53
62
|
// \ref. Omit parens.
|
54
63
|
str = str.replace(/^\(/, "");
|
55
|
-
str = str.replace(/\
|
56
|
-
}
|
64
|
+
str = str.replace(/\)$/, "");
|
65
|
+
} else {
|
57
66
|
// \eqref. Include parens
|
58
67
|
if (str.charAt(0) !== "(") { str = "(" + str; }
|
59
68
|
if (str.slice(-1) !== ")") { str = str + ")"; }
|
60
69
|
}
|
61
|
-
|
70
|
+
const mtext = document.createElementNS("http://www.w3.org/1998/Math/MathML", "mtext");
|
71
|
+
mtext.appendChild(document.createTextNode(str));
|
72
|
+
const math = document.createElementNS("http://www.w3.org/1998/Math/MathML", "math");
|
73
|
+
math.appendChild(mtext);
|
74
|
+
ref.appendChild(math);
|
62
75
|
});
|
63
76
|
}
|
64
77
|
|
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
|
/**
|
@@ -277,7 +291,12 @@ export default function buildMathML(tree, texExpression, style, settings) {
|
|
277
291
|
tree = tree[0].body
|
278
292
|
}
|
279
293
|
|
280
|
-
const expression = buildExpression(tree, style)
|
294
|
+
const expression = buildExpression(tree, style)
|
295
|
+
|
296
|
+
if (expression.length === 1 && expression[0] instanceof AnchorNode) {
|
297
|
+
return expression[0]
|
298
|
+
}
|
299
|
+
|
281
300
|
const wrap = (settings.displayMode || settings.annotate) ? "none" : settings.wrap
|
282
301
|
|
283
302
|
const n1 = expression.length === 0 ? null : expression[0]
|
@@ -302,6 +321,9 @@ export default function buildMathML(tree, texExpression, style, settings) {
|
|
302
321
|
if (settings.xml) {
|
303
322
|
math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML")
|
304
323
|
}
|
324
|
+
if (wrapper.style.width) {
|
325
|
+
math.style.width = "100%"
|
326
|
+
}
|
305
327
|
if (settings.displayMode) {
|
306
328
|
math.setAttribute("display", "block");
|
307
329
|
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
|
*/
|
package/src/environments/cd.js
CHANGED
@@ -218,18 +218,23 @@ defineFunction({
|
|
218
218
|
};
|
219
219
|
},
|
220
220
|
mathmlBuilder(group, style) {
|
221
|
-
|
222
|
-
|
223
|
-
|
221
|
+
if (group.label.body.length === 0) {
|
222
|
+
return new mathMLTree.MathNode("mrow", style) // empty label
|
223
|
+
}
|
224
|
+
// Abuse an <mtable> to create vertically centered content.
|
225
|
+
const mtd = new mathMLTree.MathNode("mtd", [mml.buildGroup(group.label, style)])
|
226
|
+
mtd.style.padding = "0"
|
227
|
+
const mtr = new mathMLTree.MathNode("mtr", [mtd])
|
228
|
+
const mtable = new mathMLTree.MathNode("mtable", [mtr])
|
229
|
+
const label = new mathMLTree.MathNode("mpadded", [mtable])
|
230
|
+
// Set the label width to zero so that the arrow will be centered under the corner cell.
|
231
|
+
label.setAttribute("width", "0")
|
232
|
+
label.setAttribute("displaystyle", "false")
|
233
|
+
label.setAttribute("scriptlevel", "1")
|
224
234
|
if (group.side === "left") {
|
225
|
-
label.
|
235
|
+
label.style.display = "flex"
|
236
|
+
label.style.justifyContent = "flex-end"
|
226
237
|
}
|
227
|
-
// We have to guess at vertical alignment. We know the arrow is 1.8em tall,
|
228
|
-
// But we don't know the height or depth of the label.
|
229
|
-
label.setAttribute("voffset", "0.7em");
|
230
|
-
label = new mathMLTree.MathNode("mstyle", [label]);
|
231
|
-
label.setAttribute("displaystyle", "false");
|
232
|
-
label.setAttribute("scriptlevel", "1");
|
233
238
|
return label;
|
234
239
|
}
|
235
240
|
});
|
package/src/functions/arrow.js
CHANGED
@@ -12,12 +12,19 @@ const padding = width => {
|
|
12
12
|
return node
|
13
13
|
}
|
14
14
|
|
15
|
-
const paddedNode = (group, lspace = 0.3, rspace = 0) => {
|
15
|
+
const paddedNode = (group, lspace = 0.3, rspace = 0, mustSmash = false) => {
|
16
16
|
if (group == null && rspace === 0) { return padding(lspace) }
|
17
17
|
const row = group ? [group] : [];
|
18
18
|
if (lspace !== 0) { row.unshift(padding(lspace)) }
|
19
19
|
if (rspace > 0) { row.push(padding(rspace)) }
|
20
|
-
|
20
|
+
if (mustSmash) {
|
21
|
+
// Used for the bottom arrow in a {CD} environment
|
22
|
+
const mpadded = new mathMLTree.MathNode("mpadded", row)
|
23
|
+
mpadded.setAttribute("height", "0")
|
24
|
+
return mpadded
|
25
|
+
} else {
|
26
|
+
return new mathMLTree.MathNode("mrow", row)
|
27
|
+
}
|
21
28
|
}
|
22
29
|
|
23
30
|
const labelSize = (size, scriptLevel) => Number(size) / emScale(scriptLevel);
|
@@ -57,7 +64,8 @@ const munderoverNode = (fName, body, below, style) => {
|
|
57
64
|
(body.body.body || body.body.length > 0))
|
58
65
|
if (gotUpper) {
|
59
66
|
let label = mml.buildGroup(body, labelStyle)
|
60
|
-
|
67
|
+
const mustSmash = (fName === "\\\\cdrightarrow" || fName === "\\\\cdleftarrow")
|
68
|
+
label = paddedNode(label, space, space, mustSmash)
|
61
69
|
// Since Firefox does not support minsize, stack a invisible node
|
62
70
|
// on top of the label. Its width will serve as a min-width.
|
63
71
|
// TODO: Refactor this after Firefox supports minsize.
|
package/src/functions/def.js
CHANGED
@@ -250,10 +250,13 @@ defineFunction({
|
|
250
250
|
// replacement text, enclosed in '{' and '}' and properly nested
|
251
251
|
const { tokens } = parser.gullet.consumeArg();
|
252
252
|
|
253
|
-
parser.gullet.macros.
|
254
|
-
|
255
|
-
|
256
|
-
|
253
|
+
if (!(funcName === "\\providecommand" && parser.gullet.macros.has(name))) {
|
254
|
+
// Ignore \providecommand
|
255
|
+
parser.gullet.macros.set(
|
256
|
+
name,
|
257
|
+
{ tokens, numArgs }
|
258
|
+
)
|
259
|
+
}
|
257
260
|
|
258
261
|
return { type: "internal", mode: parser.mode };
|
259
262
|
|
package/src/functions/font.js
CHANGED
package/src/functions/genfrac.js
CHANGED
@@ -20,10 +20,19 @@ const mathmlBuilder = (group, style) => {
|
|
20
20
|
? style.withLevel(StyleLevel.SCRIPT)
|
21
21
|
: style.withLevel(StyleLevel.SCRIPTSCRIPT);
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
// Chromium (wrongly) continues to shrink fractions beyond scriptscriptlevel.
|
24
|
+
// So we check for levels that Chromium shrinks too small.
|
25
|
+
// If necessary, set an explicit fraction depth.
|
26
|
+
const numer = mml.buildGroup(group.numer, childOptions)
|
27
|
+
const denom = mml.buildGroup(group.denom, childOptions)
|
28
|
+
if (style.level === 3) {
|
29
|
+
numer.style.mathDepth = "2"
|
30
|
+
numer.setAttribute("scriptlevel", "2")
|
31
|
+
denom.style.mathDepth = "2"
|
32
|
+
denom.setAttribute("scriptlevel", "2")
|
33
|
+
}
|
34
|
+
|
35
|
+
let node = new mathMLTree.MathNode("mfrac", [numer, denom]);
|
27
36
|
|
28
37
|
if (!group.hasBarLine) {
|
29
38
|
node.setAttribute("linethickness", "0px");
|
package/src/functions/href.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import defineFunction, { ordargument } from "../defineFunction";
|
2
2
|
import { assertNodeType } from "../parseNode";
|
3
3
|
import { MathNode } from "../mathMLTree";
|
4
|
+
import { AnchorNode } from "../domTree";
|
4
5
|
import * as mml from "../buildMathML";
|
5
6
|
import ParseError from "../ParseError";
|
6
7
|
|
@@ -33,12 +34,9 @@ defineFunction({
|
|
33
34
|
};
|
34
35
|
},
|
35
36
|
mathmlBuilder: (group, style) => {
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
}
|
40
|
-
math.setAttribute("href", group.href);
|
41
|
-
return math;
|
37
|
+
const math = new MathNode("math", [mml.buildExpressionRow(group.body, style)])
|
38
|
+
const anchorNode = new AnchorNode(group.href, [], [math])
|
39
|
+
return anchorNode
|
42
40
|
}
|
43
41
|
});
|
44
42
|
|
package/src/functions/op.js
CHANGED
@@ -32,13 +32,6 @@ const mathmlBuilder = (group, style) => {
|
|
32
32
|
node = new mathMLTree.MathNode("mo", [mml.makeText(group.name, group.mode)]);
|
33
33
|
if (noSuccessor.includes(group.name)) {
|
34
34
|
node.setAttribute("largeop", "false")
|
35
|
-
} else if (group.limits) {
|
36
|
-
// This is a workaround for a MathML/Chromium bug.
|
37
|
-
// This is being applied to singleCharBigOps, which are not really stretchy.
|
38
|
-
// But by setting the stretchy attribute, Chromium will vertically center
|
39
|
-
// big ops around the math axis. This is needed since STIX TWO does not do so.
|
40
|
-
// TODO: Remove this hack when MathML & Chromium fix their problem.
|
41
|
-
node.setAttribute("stretchy", "true")
|
42
35
|
} else {
|
43
36
|
node.setAttribute("movablelimits", "false")
|
44
37
|
}
|
package/src/functions/ref.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import defineFunction from "../defineFunction";
|
2
|
-
import
|
2
|
+
import { AnchorNode } from "../domTree";
|
3
3
|
import { invalidIdRegEx } from "./label";
|
4
4
|
|
5
5
|
defineFunction({
|
@@ -18,11 +18,9 @@ defineFunction({
|
|
18
18
|
};
|
19
19
|
},
|
20
20
|
mathmlBuilder(group, style) {
|
21
|
-
// Create an empty
|
21
|
+
// Create an empty <a> node. Set a class and an href attribute.
|
22
22
|
// The post-processor will populate with the target's tag or equation number.
|
23
23
|
const classes = group.funcName === "\\ref" ? ["tml-ref"] : ["tml-ref", "tml-eqref"]
|
24
|
-
|
25
|
-
node.setAttribute("href", "#" + group.string)
|
26
|
-
return node
|
24
|
+
return new AnchorNode("#" + group.string, classes, null)
|
27
25
|
}
|
28
26
|
});
|
package/src/functions/rule.js
CHANGED
package/src/functions/supsub.js
CHANGED
@@ -45,18 +45,27 @@ defineFunctionBuilders({
|
|
45
45
|
|
46
46
|
const children = group.base && group.base.stack
|
47
47
|
? [mml.buildGroup(group.base.body[0], style)]
|
48
|
-
: [mml.buildGroup(group.base, style)]
|
48
|
+
: [mml.buildGroup(group.base, style)];
|
49
|
+
|
50
|
+
// Note regarding scriptstyle level.
|
51
|
+
// (Sub|super)scripts should not shrink beyond MathML scriptlevel 2 aka \scriptscriptstyle
|
52
|
+
// Ref: https://w3c.github.io/mathml-core/#the-displaystyle-and-scriptlevel-attributes
|
53
|
+
// (BTW, MathML scriptlevel 2 is equal to Temml level 3.)
|
54
|
+
// But Chromium continues to shrink the (sub|super)scripts. So we explicitly set scriptlevel 2.
|
49
55
|
|
50
56
|
const childStyle = style.inSubOrSup()
|
51
57
|
if (group.sub) {
|
52
|
-
|
58
|
+
const sub = mml.buildGroup(group.sub, childStyle)
|
59
|
+
if (style.level === 3) { sub.setAttribute("scriptlevel", "2") }
|
60
|
+
children.push(sub)
|
53
61
|
}
|
54
62
|
|
55
63
|
if (group.sup) {
|
56
64
|
const sup = mml.buildGroup(group.sup, childStyle)
|
65
|
+
if (style.level === 3) { sup.setAttribute("scriptlevel", "2") }
|
57
66
|
const testNode = sup.type === "mrow" ? sup.children[0] : sup
|
58
67
|
if ((testNode && testNode.type === "mo" && testNode.classes.includes("tml-prime"))
|
59
|
-
&& group.base && group.base.text && group.base.text
|
68
|
+
&& group.base && group.base.text && "fF".indexOf(group.base.text) > -1) {
|
60
69
|
// Chromium does not address italic correction on prime. Prevent f′ from overlapping.
|
61
70
|
testNode.classes.push("prime-pad")
|
62
71
|
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import defineFunction from "../defineFunction";
|
2
|
+
import mathMLTree from "../mathMLTree";
|
3
|
+
import * as mml from "../buildMathML";
|
4
|
+
|
5
|
+
// \vcenter: Vertically center the argument group on the math axis.
|
6
|
+
|
7
|
+
defineFunction({
|
8
|
+
type: "vcenter",
|
9
|
+
names: ["\\vcenter"],
|
10
|
+
props: {
|
11
|
+
numArgs: 1,
|
12
|
+
argTypes: ["original"],
|
13
|
+
allowedInText: false
|
14
|
+
},
|
15
|
+
handler({ parser }, args) {
|
16
|
+
return {
|
17
|
+
type: "vcenter",
|
18
|
+
mode: parser.mode,
|
19
|
+
body: args[0]
|
20
|
+
};
|
21
|
+
},
|
22
|
+
mathmlBuilder(group, style) {
|
23
|
+
// Use a math table to create vertically centered content.
|
24
|
+
const mtd = new mathMLTree.MathNode("mtd", [mml.buildGroup(group.body, style)])
|
25
|
+
mtd.style.padding = "0"
|
26
|
+
const mtr = new mathMLTree.MathNode("mtr", [mtd])
|
27
|
+
return new mathMLTree.MathNode("mtable", [mtr])
|
28
|
+
}
|
29
|
+
});
|
30
|
+
|
package/src/functions.js
CHANGED
package/src/macros.js
CHANGED
@@ -243,7 +243,7 @@ defineMacro("\\underbar", "\\underline{\\text{#1}}");
|
|
243
243
|
// \kern6\p@\hbox{.}\hbox{.}\hbox{.}}}
|
244
244
|
// We'll call \varvdots, which gets a glyph from symbols.js.
|
245
245
|
// The zero-width rule gets us an equivalent to the vertical 6pt kern.
|
246
|
-
defineMacro("\\vdots", "
|
246
|
+
defineMacro("\\vdots", "{\\varvdots\\rule{0pt}{15pt}}")
|
247
247
|
defineMacro("\u22ee", "\\vdots");
|
248
248
|
|
249
249
|
// {array} environment gaps
|