temml 0.9.1
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/LICENSE +21 -0
- package/README.md +44 -0
- package/contrib/auto-render/README.md +89 -0
- package/contrib/auto-render/auto-render.js +128 -0
- package/contrib/auto-render/dist/auto-render.js +217 -0
- package/contrib/auto-render/dist/auto-render.min.js +1 -0
- package/contrib/auto-render/splitAtDelimiters.js +84 -0
- package/contrib/auto-render/test/auto-render-spec.js +234 -0
- package/contrib/auto-render/test/auto-render.js +217 -0
- package/contrib/auto-render/test/test_page.html +59 -0
- package/contrib/mhchem/README.md +26 -0
- package/contrib/mhchem/mhchem.js +1705 -0
- package/contrib/mhchem/mhchem.min.js +1 -0
- package/contrib/physics/README.md +20 -0
- package/contrib/physics/physics.js +131 -0
- package/contrib/texvc/README.md +23 -0
- package/contrib/texvc/texvc.js +61 -0
- package/dist/Temml-Asana.css +201 -0
- package/dist/Temml-Latin-Modern.css +216 -0
- package/dist/Temml-Libertinus.css +214 -0
- package/dist/Temml-Local.css +194 -0
- package/dist/Temml-STIX2.css +203 -0
- package/dist/Temml.woff2 +0 -0
- package/dist/temml.cjs +13122 -0
- package/dist/temml.js +11225 -0
- package/dist/temml.min.js +1 -0
- package/dist/temml.mjs +13120 -0
- package/dist/temmlPostProcess.js +70 -0
- package/package.json +34 -0
- package/src/Lexer.js +121 -0
- package/src/MacroExpander.js +437 -0
- package/src/Namespace.js +107 -0
- package/src/ParseError.js +64 -0
- package/src/Parser.js +977 -0
- package/src/Settings.js +49 -0
- package/src/SourceLocation.js +29 -0
- package/src/Style.js +144 -0
- package/src/Token.js +40 -0
- package/src/buildMathML.js +235 -0
- package/src/constants.js +25 -0
- package/src/defineEnvironment.js +25 -0
- package/src/defineFunction.js +69 -0
- package/src/defineMacro.js +11 -0
- package/src/domTree.js +185 -0
- package/src/environments/array.js +791 -0
- package/src/environments/cd.js +252 -0
- package/src/environments.js +8 -0
- package/src/functions/accent.js +127 -0
- package/src/functions/accentunder.js +38 -0
- package/src/functions/arrow.js +204 -0
- package/src/functions/cancelto.js +36 -0
- package/src/functions/char.js +33 -0
- package/src/functions/color.js +253 -0
- package/src/functions/cr.js +46 -0
- package/src/functions/def.js +259 -0
- package/src/functions/delimsizing.js +304 -0
- package/src/functions/enclose.js +193 -0
- package/src/functions/envTag.js +38 -0
- package/src/functions/environment.js +59 -0
- package/src/functions/font.js +123 -0
- package/src/functions/genfrac.js +333 -0
- package/src/functions/hbox.js +29 -0
- package/src/functions/horizBrace.js +32 -0
- package/src/functions/href.js +90 -0
- package/src/functions/html.js +95 -0
- package/src/functions/includegraphics.js +131 -0
- package/src/functions/kern.js +75 -0
- package/src/functions/label.js +29 -0
- package/src/functions/lap.js +75 -0
- package/src/functions/math.js +40 -0
- package/src/functions/mathchoice.js +41 -0
- package/src/functions/mclass.js +201 -0
- package/src/functions/multiscript.js +91 -0
- package/src/functions/not.js +46 -0
- package/src/functions/op.js +338 -0
- package/src/functions/operatorname.js +139 -0
- package/src/functions/ordgroup.js +9 -0
- package/src/functions/phantom.js +73 -0
- package/src/functions/pmb.js +31 -0
- package/src/functions/raise.js +68 -0
- package/src/functions/ref.js +28 -0
- package/src/functions/relax.js +16 -0
- package/src/functions/rule.js +52 -0
- package/src/functions/sizing.js +64 -0
- package/src/functions/smash.js +66 -0
- package/src/functions/sqrt.js +31 -0
- package/src/functions/styling.js +58 -0
- package/src/functions/supsub.js +135 -0
- package/src/functions/symbolsOp.js +53 -0
- package/src/functions/symbolsOrd.js +102 -0
- package/src/functions/symbolsSpacing.js +53 -0
- package/src/functions/tag.js +8 -0
- package/src/functions/text.js +75 -0
- package/src/functions/tip.js +63 -0
- package/src/functions/toggle.js +13 -0
- package/src/functions/verb.js +33 -0
- package/src/functions.js +57 -0
- package/src/linebreaking.js +159 -0
- package/src/macros.js +708 -0
- package/src/mathMLTree.js +175 -0
- package/src/parseNode.js +42 -0
- package/src/parseTree.js +40 -0
- package/src/postProcess.js +57 -0
- package/src/replace.js +225 -0
- package/src/stretchy.js +66 -0
- package/src/svg.js +110 -0
- package/src/symbols.js +972 -0
- package/src/tree.js +50 -0
- package/src/unicodeAccents.js +16 -0
- package/src/unicodeScripts.js +119 -0
- package/src/unicodeSupOrSub.js +108 -0
- package/src/unicodeSymbolBuilder.js +31 -0
- package/src/unicodeSymbols.js +320 -0
- package/src/units.js +109 -0
- package/src/utils.js +109 -0
- package/src/variant.js +103 -0
- package/temml.js +181 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import defineFunction, { normalizeArgument } from "../defineFunction"
|
|
2
|
+
import * as mml from "../buildMathML"
|
|
3
|
+
import mathMLTree from "../mathMLTree"
|
|
4
|
+
|
|
5
|
+
const mathmlBuilder = (group, style) => {
|
|
6
|
+
const font = group.font
|
|
7
|
+
const newStyle = style.withFont(font)
|
|
8
|
+
const mathGroup = mml.buildGroup(group.body, newStyle)
|
|
9
|
+
|
|
10
|
+
if (mathGroup.children.length === 0) { return mathGroup } // empty group, e.g., \mathrm{}
|
|
11
|
+
if (font === "boldsymbol" && ["mo", "mpadded"].includes(mathGroup.type)) {
|
|
12
|
+
mathGroup.style.fontWeight = "bold"
|
|
13
|
+
return mathGroup
|
|
14
|
+
}
|
|
15
|
+
// Check if it is possible to consolidate elements into a single <mi> element.
|
|
16
|
+
let canConsolidate = mathGroup.children[0].type === "mo"
|
|
17
|
+
for (let i = 1; i < mathGroup.children.length; i++) {
|
|
18
|
+
if (mathGroup.children[i].type === "mo" && font === "boldsymbol") {
|
|
19
|
+
mathGroup.children[i].style.fontWeight = "bold"
|
|
20
|
+
}
|
|
21
|
+
if (mathGroup.children[i].type !== "mi") { canConsolidate = false }
|
|
22
|
+
const localVariant = mathGroup.children[i].attributes &&
|
|
23
|
+
mathGroup.children[i].attributes.mathvariant || ""
|
|
24
|
+
if (localVariant !== "normal") { canConsolidate = false }
|
|
25
|
+
}
|
|
26
|
+
if (!canConsolidate) { return mathGroup }
|
|
27
|
+
// Consolidate the <mi> elements.
|
|
28
|
+
const mi = mathGroup.children[0]
|
|
29
|
+
for (let i = 1; i < mathGroup.children.length; i++) {
|
|
30
|
+
mi.children.push(mathGroup.children[i].children[0])
|
|
31
|
+
}
|
|
32
|
+
if (mathGroup.attributes.mathcolor) { mi.attributes.mathcolor = mathGroup.attributes.mathcolor }
|
|
33
|
+
if (mi.attributes.mathvariant && mi.attributes.mathvariant === "normal") {
|
|
34
|
+
// Workaround for a Firefox bug that renders spurious space around
|
|
35
|
+
// a <mi mathvariant="normal">
|
|
36
|
+
// Ref: https://bugs.webkit.org/show_bug.cgi?id=129097
|
|
37
|
+
// We insert a text node that contains a zero-width space and wrap in an mrow.
|
|
38
|
+
// TODO: Get rid of this <mi> workaround when the Firefox bug is fixed.
|
|
39
|
+
const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b"))
|
|
40
|
+
return new mathMLTree.MathNode("mrow", [bogus, mi])
|
|
41
|
+
}
|
|
42
|
+
return mi
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const fontAliases = {
|
|
46
|
+
"\\Bbb": "\\mathbb",
|
|
47
|
+
"\\bold": "\\mathbf",
|
|
48
|
+
"\\frak": "\\mathfrak",
|
|
49
|
+
"\\bm": "\\boldsymbol"
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
defineFunction({
|
|
53
|
+
type: "font",
|
|
54
|
+
names: [
|
|
55
|
+
// styles
|
|
56
|
+
"\\mathrm",
|
|
57
|
+
"\\mathit",
|
|
58
|
+
"\\mathbf",
|
|
59
|
+
"\\mathnormal",
|
|
60
|
+
"\\up@greek",
|
|
61
|
+
"\\boldsymbol",
|
|
62
|
+
|
|
63
|
+
// families
|
|
64
|
+
"\\mathbb",
|
|
65
|
+
"\\mathcal",
|
|
66
|
+
"\\mathfrak",
|
|
67
|
+
"\\mathscr",
|
|
68
|
+
"\\mathsf",
|
|
69
|
+
"\\mathtt",
|
|
70
|
+
"\\oldstylenums",
|
|
71
|
+
|
|
72
|
+
// aliases
|
|
73
|
+
"\\Bbb",
|
|
74
|
+
"\\bm",
|
|
75
|
+
"\\bold",
|
|
76
|
+
"\\frak"
|
|
77
|
+
],
|
|
78
|
+
props: {
|
|
79
|
+
numArgs: 1,
|
|
80
|
+
allowedInArgument: true
|
|
81
|
+
},
|
|
82
|
+
handler: ({ parser, funcName }, args) => {
|
|
83
|
+
const body = normalizeArgument(args[0]);
|
|
84
|
+
let func = funcName;
|
|
85
|
+
if (func in fontAliases) {
|
|
86
|
+
func = fontAliases[func];
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
type: "font",
|
|
90
|
+
mode: parser.mode,
|
|
91
|
+
font: func.slice(1),
|
|
92
|
+
body
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
mathmlBuilder
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Old font changing functions
|
|
99
|
+
defineFunction({
|
|
100
|
+
type: "font",
|
|
101
|
+
names: ["\\rm", "\\sf", "\\tt", "\\bf", "\\it", "\\cal"],
|
|
102
|
+
props: {
|
|
103
|
+
numArgs: 0,
|
|
104
|
+
allowedInText: true
|
|
105
|
+
},
|
|
106
|
+
handler: ({ parser, funcName, breakOnTokenText }, args) => {
|
|
107
|
+
const { mode } = parser;
|
|
108
|
+
const body = parser.parseExpression(true, breakOnTokenText);
|
|
109
|
+
const fontStyle = `math${funcName.slice(1)}`;
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
type: "font",
|
|
113
|
+
mode: mode,
|
|
114
|
+
font: fontStyle,
|
|
115
|
+
body: {
|
|
116
|
+
type: "ordgroup",
|
|
117
|
+
mode: parser.mode,
|
|
118
|
+
body
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
},
|
|
122
|
+
mathmlBuilder
|
|
123
|
+
});
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import defineFunction, { normalizeArgument } from "../defineFunction";
|
|
2
|
+
import mathMLTree from "../mathMLTree";
|
|
3
|
+
import { StyleLevel } from "../constants"
|
|
4
|
+
import { assertNodeType } from "../parseNode";
|
|
5
|
+
import { assert } from "../utils";
|
|
6
|
+
import * as mml from "../buildMathML";
|
|
7
|
+
import { calculateSize } from "../units";
|
|
8
|
+
|
|
9
|
+
const stylArray = ["display", "text", "script", "scriptscript"];
|
|
10
|
+
const scriptLevel = { auto: -1, display: 0, text: 0, script: 1, scriptscript: 2 };
|
|
11
|
+
|
|
12
|
+
const mathmlBuilder = (group, style) => {
|
|
13
|
+
// Track the scriptLevel of the numerator and denominator.
|
|
14
|
+
// We may need that info for \mathchoice or for adjusting em dimensions.
|
|
15
|
+
const childOptions = group.scriptLevel === "auto"
|
|
16
|
+
? style.incrementLevel()
|
|
17
|
+
: group.scriptLevel === "display"
|
|
18
|
+
? style.withLevel(StyleLevel.TEXT)
|
|
19
|
+
: group.scriptLevel === "text"
|
|
20
|
+
? style.withLevel(StyleLevel.SCRIPT)
|
|
21
|
+
: style.withLevel(StyleLevel.SCRIPTSCRIPT);
|
|
22
|
+
|
|
23
|
+
let node = new mathMLTree.MathNode("mfrac", [
|
|
24
|
+
mml.buildGroup(group.numer, childOptions),
|
|
25
|
+
mml.buildGroup(group.denom, childOptions)
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
if (!group.hasBarLine) {
|
|
29
|
+
node.setAttribute("linethickness", "0px");
|
|
30
|
+
} else if (group.barSize) {
|
|
31
|
+
const ruleWidth = calculateSize(group.barSize, style);
|
|
32
|
+
node.setAttribute("linethickness", ruleWidth.number + ruleWidth.unit);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (group.leftDelim != null || group.rightDelim != null) {
|
|
36
|
+
const withDelims = [];
|
|
37
|
+
|
|
38
|
+
if (group.leftDelim != null) {
|
|
39
|
+
const leftOp = new mathMLTree.MathNode("mo", [
|
|
40
|
+
new mathMLTree.TextNode(group.leftDelim.replace("\\", ""))
|
|
41
|
+
]);
|
|
42
|
+
leftOp.setAttribute("fence", "true");
|
|
43
|
+
withDelims.push(leftOp);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
withDelims.push(node);
|
|
47
|
+
|
|
48
|
+
if (group.rightDelim != null) {
|
|
49
|
+
const rightOp = new mathMLTree.MathNode("mo", [
|
|
50
|
+
new mathMLTree.TextNode(group.rightDelim.replace("\\", ""))
|
|
51
|
+
]);
|
|
52
|
+
rightOp.setAttribute("fence", "true");
|
|
53
|
+
withDelims.push(rightOp);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
node = mml.makeRow(withDelims);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (group.scriptLevel !== "auto") {
|
|
60
|
+
node = new mathMLTree.MathNode("mstyle", [node]);
|
|
61
|
+
node.setAttribute("displaystyle", String(group.scriptLevel === "display"));
|
|
62
|
+
node.setAttribute("scriptlevel", scriptLevel[group.scriptLevel]);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return node;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
defineFunction({
|
|
69
|
+
type: "genfrac",
|
|
70
|
+
names: [
|
|
71
|
+
"\\dfrac",
|
|
72
|
+
"\\frac",
|
|
73
|
+
"\\tfrac",
|
|
74
|
+
"\\dbinom",
|
|
75
|
+
"\\binom",
|
|
76
|
+
"\\tbinom",
|
|
77
|
+
"\\\\atopfrac", // can’t be entered directly
|
|
78
|
+
"\\\\bracefrac",
|
|
79
|
+
"\\\\brackfrac" // ditto
|
|
80
|
+
],
|
|
81
|
+
props: {
|
|
82
|
+
numArgs: 2,
|
|
83
|
+
allowedInArgument: true
|
|
84
|
+
},
|
|
85
|
+
handler: ({ parser, funcName }, args) => {
|
|
86
|
+
const numer = args[0];
|
|
87
|
+
const denom = args[1];
|
|
88
|
+
let hasBarLine = false;
|
|
89
|
+
let leftDelim = null;
|
|
90
|
+
let rightDelim = null;
|
|
91
|
+
let scriptLevel = "auto";
|
|
92
|
+
|
|
93
|
+
switch (funcName) {
|
|
94
|
+
case "\\dfrac":
|
|
95
|
+
case "\\frac":
|
|
96
|
+
case "\\tfrac":
|
|
97
|
+
hasBarLine = true;
|
|
98
|
+
break;
|
|
99
|
+
case "\\\\atopfrac":
|
|
100
|
+
hasBarLine = false;
|
|
101
|
+
break;
|
|
102
|
+
case "\\dbinom":
|
|
103
|
+
case "\\binom":
|
|
104
|
+
case "\\tbinom":
|
|
105
|
+
leftDelim = "(";
|
|
106
|
+
rightDelim = ")";
|
|
107
|
+
break;
|
|
108
|
+
case "\\\\bracefrac":
|
|
109
|
+
leftDelim = "\\{";
|
|
110
|
+
rightDelim = "\\}";
|
|
111
|
+
break;
|
|
112
|
+
case "\\\\brackfrac":
|
|
113
|
+
leftDelim = "[";
|
|
114
|
+
rightDelim = "]";
|
|
115
|
+
break;
|
|
116
|
+
default:
|
|
117
|
+
throw new Error("Unrecognized genfrac command");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
switch (funcName) {
|
|
121
|
+
case "\\dfrac":
|
|
122
|
+
case "\\dbinom":
|
|
123
|
+
scriptLevel = "display";
|
|
124
|
+
break;
|
|
125
|
+
case "\\tfrac":
|
|
126
|
+
case "\\tbinom":
|
|
127
|
+
scriptLevel = "text";
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
type: "genfrac",
|
|
133
|
+
mode: parser.mode,
|
|
134
|
+
continued: false,
|
|
135
|
+
numer,
|
|
136
|
+
denom,
|
|
137
|
+
hasBarLine,
|
|
138
|
+
leftDelim,
|
|
139
|
+
rightDelim,
|
|
140
|
+
scriptLevel,
|
|
141
|
+
barSize: null
|
|
142
|
+
};
|
|
143
|
+
},
|
|
144
|
+
mathmlBuilder
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
defineFunction({
|
|
148
|
+
type: "genfrac",
|
|
149
|
+
names: ["\\cfrac"],
|
|
150
|
+
props: {
|
|
151
|
+
numArgs: 2
|
|
152
|
+
},
|
|
153
|
+
handler: ({ parser, funcName }, args) => {
|
|
154
|
+
const numer = args[0];
|
|
155
|
+
const denom = args[1];
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
type: "genfrac",
|
|
159
|
+
mode: parser.mode,
|
|
160
|
+
continued: true,
|
|
161
|
+
numer,
|
|
162
|
+
denom,
|
|
163
|
+
hasBarLine: true,
|
|
164
|
+
leftDelim: null,
|
|
165
|
+
rightDelim: null,
|
|
166
|
+
scriptLevel: "display",
|
|
167
|
+
barSize: null
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Infix generalized fractions -- these are not rendered directly, but replaced
|
|
173
|
+
// immediately by one of the variants above.
|
|
174
|
+
defineFunction({
|
|
175
|
+
type: "infix",
|
|
176
|
+
names: ["\\over", "\\choose", "\\atop", "\\brace", "\\brack"],
|
|
177
|
+
props: {
|
|
178
|
+
numArgs: 0,
|
|
179
|
+
infix: true
|
|
180
|
+
},
|
|
181
|
+
handler({ parser, funcName, token }) {
|
|
182
|
+
let replaceWith;
|
|
183
|
+
switch (funcName) {
|
|
184
|
+
case "\\over":
|
|
185
|
+
replaceWith = "\\frac";
|
|
186
|
+
break;
|
|
187
|
+
case "\\choose":
|
|
188
|
+
replaceWith = "\\binom";
|
|
189
|
+
break;
|
|
190
|
+
case "\\atop":
|
|
191
|
+
replaceWith = "\\\\atopfrac";
|
|
192
|
+
break;
|
|
193
|
+
case "\\brace":
|
|
194
|
+
replaceWith = "\\\\bracefrac";
|
|
195
|
+
break;
|
|
196
|
+
case "\\brack":
|
|
197
|
+
replaceWith = "\\\\brackfrac";
|
|
198
|
+
break;
|
|
199
|
+
default:
|
|
200
|
+
throw new Error("Unrecognized infix genfrac command");
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
type: "infix",
|
|
204
|
+
mode: parser.mode,
|
|
205
|
+
replaceWith,
|
|
206
|
+
token
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const delimFromValue = function(delimString) {
|
|
212
|
+
let delim = null;
|
|
213
|
+
if (delimString.length > 0) {
|
|
214
|
+
delim = delimString;
|
|
215
|
+
delim = delim === "." ? null : delim;
|
|
216
|
+
}
|
|
217
|
+
return delim;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
defineFunction({
|
|
221
|
+
type: "genfrac",
|
|
222
|
+
names: ["\\genfrac"],
|
|
223
|
+
props: {
|
|
224
|
+
numArgs: 6,
|
|
225
|
+
allowedInArgument: true,
|
|
226
|
+
argTypes: ["math", "math", "size", "text", "math", "math"]
|
|
227
|
+
},
|
|
228
|
+
handler({ parser }, args) {
|
|
229
|
+
const numer = args[4];
|
|
230
|
+
const denom = args[5];
|
|
231
|
+
|
|
232
|
+
// Look into the parse nodes to get the desired delimiters.
|
|
233
|
+
const leftNode = normalizeArgument(args[0]);
|
|
234
|
+
const leftDelim = leftNode.type === "atom" && leftNode.family === "open"
|
|
235
|
+
? delimFromValue(leftNode.text)
|
|
236
|
+
: null;
|
|
237
|
+
const rightNode = normalizeArgument(args[1]);
|
|
238
|
+
const rightDelim =
|
|
239
|
+
rightNode.type === "atom" && rightNode.family === "close"
|
|
240
|
+
? delimFromValue(rightNode.text)
|
|
241
|
+
: null;
|
|
242
|
+
|
|
243
|
+
const barNode = assertNodeType(args[2], "size");
|
|
244
|
+
let hasBarLine;
|
|
245
|
+
let barSize = null;
|
|
246
|
+
if (barNode.isBlank) {
|
|
247
|
+
// \genfrac acts differently than \above.
|
|
248
|
+
// \genfrac treats an empty size group as a signal to use a
|
|
249
|
+
// standard bar size. \above would see size = 0 and omit the bar.
|
|
250
|
+
hasBarLine = true;
|
|
251
|
+
} else {
|
|
252
|
+
barSize = barNode.value;
|
|
253
|
+
hasBarLine = barSize.number > 0;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Find out if we want displaystyle, textstyle, etc.
|
|
257
|
+
let scriptLevel = "auto";
|
|
258
|
+
let styl = args[3];
|
|
259
|
+
if (styl.type === "ordgroup") {
|
|
260
|
+
if (styl.body.length > 0) {
|
|
261
|
+
const textOrd = assertNodeType(styl.body[0], "textord");
|
|
262
|
+
scriptLevel = stylArray[Number(textOrd.text)];
|
|
263
|
+
}
|
|
264
|
+
} else {
|
|
265
|
+
styl = assertNodeType(styl, "textord");
|
|
266
|
+
scriptLevel = stylArray[Number(styl.text)];
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return {
|
|
270
|
+
type: "genfrac",
|
|
271
|
+
mode: parser.mode,
|
|
272
|
+
numer,
|
|
273
|
+
denom,
|
|
274
|
+
continued: false,
|
|
275
|
+
hasBarLine,
|
|
276
|
+
barSize,
|
|
277
|
+
leftDelim,
|
|
278
|
+
rightDelim,
|
|
279
|
+
scriptLevel
|
|
280
|
+
};
|
|
281
|
+
},
|
|
282
|
+
mathmlBuilder
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// \above is an infix fraction that also defines a fraction bar size.
|
|
286
|
+
defineFunction({
|
|
287
|
+
type: "infix",
|
|
288
|
+
names: ["\\above"],
|
|
289
|
+
props: {
|
|
290
|
+
numArgs: 1,
|
|
291
|
+
argTypes: ["size"],
|
|
292
|
+
infix: true
|
|
293
|
+
},
|
|
294
|
+
handler({ parser, funcName, token }, args) {
|
|
295
|
+
return {
|
|
296
|
+
type: "infix",
|
|
297
|
+
mode: parser.mode,
|
|
298
|
+
replaceWith: "\\\\abovefrac",
|
|
299
|
+
barSize: assertNodeType(args[0], "size").value,
|
|
300
|
+
token
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
defineFunction({
|
|
306
|
+
type: "genfrac",
|
|
307
|
+
names: ["\\\\abovefrac"],
|
|
308
|
+
props: {
|
|
309
|
+
numArgs: 3,
|
|
310
|
+
argTypes: ["math", "size", "math"]
|
|
311
|
+
},
|
|
312
|
+
handler: ({ parser, funcName }, args) => {
|
|
313
|
+
const numer = args[0];
|
|
314
|
+
const barSize = assert(assertNodeType(args[1], "infix").barSize);
|
|
315
|
+
const denom = args[2];
|
|
316
|
+
|
|
317
|
+
const hasBarLine = barSize.number > 0;
|
|
318
|
+
return {
|
|
319
|
+
type: "genfrac",
|
|
320
|
+
mode: parser.mode,
|
|
321
|
+
numer,
|
|
322
|
+
denom,
|
|
323
|
+
continued: false,
|
|
324
|
+
hasBarLine,
|
|
325
|
+
barSize,
|
|
326
|
+
leftDelim: null,
|
|
327
|
+
rightDelim: null,
|
|
328
|
+
scriptLevel: "auto"
|
|
329
|
+
};
|
|
330
|
+
},
|
|
331
|
+
|
|
332
|
+
mathmlBuilder
|
|
333
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import defineFunction, { ordargument } from "../defineFunction";
|
|
2
|
+
import { StyleLevel } from "../constants"
|
|
3
|
+
import mathMLTree from "../mathMLTree";
|
|
4
|
+
import * as mml from "../buildMathML";
|
|
5
|
+
|
|
6
|
+
// \hbox is provided for compatibility with LaTeX functions that act on a box.
|
|
7
|
+
// This function by itself doesn't do anything but prevent a soft line break.
|
|
8
|
+
|
|
9
|
+
defineFunction({
|
|
10
|
+
type: "hbox",
|
|
11
|
+
names: ["\\hbox"],
|
|
12
|
+
props: {
|
|
13
|
+
numArgs: 1,
|
|
14
|
+
argTypes: ["hbox"],
|
|
15
|
+
allowedInArgument: true,
|
|
16
|
+
allowedInText: false
|
|
17
|
+
},
|
|
18
|
+
handler({ parser }, args) {
|
|
19
|
+
return {
|
|
20
|
+
type: "hbox",
|
|
21
|
+
mode: parser.mode,
|
|
22
|
+
body: ordargument(args[0])
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
mathmlBuilder(group, style) {
|
|
26
|
+
const newOptions = style.withLevel(StyleLevel.TEXT)
|
|
27
|
+
return new mathMLTree.MathNode("mrow", mml.buildExpression(group.body, newOptions));
|
|
28
|
+
}
|
|
29
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import defineFunction from "../defineFunction";
|
|
2
|
+
import mathMLTree from "../mathMLTree";
|
|
3
|
+
import stretchy from "../stretchy";
|
|
4
|
+
import * as mml from "../buildMathML";
|
|
5
|
+
|
|
6
|
+
const mathmlBuilder = (group, style) => {
|
|
7
|
+
const accentNode = stretchy.mathMLnode(group.label);
|
|
8
|
+
accentNode.style["math-depth"] = 0
|
|
9
|
+
return new mathMLTree.MathNode(group.isOver ? "mover" : "munder", [
|
|
10
|
+
mml.buildGroup(group.base, style),
|
|
11
|
+
accentNode
|
|
12
|
+
]);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Horizontal stretchy braces
|
|
16
|
+
defineFunction({
|
|
17
|
+
type: "horizBrace",
|
|
18
|
+
names: ["\\overbrace", "\\underbrace"],
|
|
19
|
+
props: {
|
|
20
|
+
numArgs: 1
|
|
21
|
+
},
|
|
22
|
+
handler({ parser, funcName }, args) {
|
|
23
|
+
return {
|
|
24
|
+
type: "horizBrace",
|
|
25
|
+
mode: parser.mode,
|
|
26
|
+
label: funcName,
|
|
27
|
+
isOver: /^\\over/.test(funcName),
|
|
28
|
+
base: args[0]
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
mathmlBuilder
|
|
32
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import defineFunction, { ordargument } from "../defineFunction";
|
|
2
|
+
import { assertNodeType } from "../parseNode";
|
|
3
|
+
import { MathNode } from "../mathMLTree";
|
|
4
|
+
import * as mml from "../buildMathML";
|
|
5
|
+
import ParseError from "../ParseError";
|
|
6
|
+
|
|
7
|
+
defineFunction({
|
|
8
|
+
type: "href",
|
|
9
|
+
names: ["\\href"],
|
|
10
|
+
props: {
|
|
11
|
+
numArgs: 2,
|
|
12
|
+
argTypes: ["url", "original"],
|
|
13
|
+
allowedInText: true
|
|
14
|
+
},
|
|
15
|
+
handler: ({ parser, token }, args) => {
|
|
16
|
+
const body = args[1];
|
|
17
|
+
const href = assertNodeType(args[0], "url").url;
|
|
18
|
+
|
|
19
|
+
if (
|
|
20
|
+
!parser.settings.isTrusted({
|
|
21
|
+
command: "\\href",
|
|
22
|
+
url: href
|
|
23
|
+
})
|
|
24
|
+
) {
|
|
25
|
+
throw new ParseError(`Function "\\href" is not trusted`, token)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
type: "href",
|
|
30
|
+
mode: parser.mode,
|
|
31
|
+
href,
|
|
32
|
+
body: ordargument(body)
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
mathmlBuilder: (group, style) => {
|
|
36
|
+
let math = mml.buildExpressionRow(group.body, style);
|
|
37
|
+
if (!(math instanceof MathNode)) {
|
|
38
|
+
math = new MathNode("mrow", [math]);
|
|
39
|
+
}
|
|
40
|
+
math.setAttribute("href", group.href);
|
|
41
|
+
return math;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
defineFunction({
|
|
46
|
+
type: "href",
|
|
47
|
+
names: ["\\url"],
|
|
48
|
+
props: {
|
|
49
|
+
numArgs: 1,
|
|
50
|
+
argTypes: ["url"],
|
|
51
|
+
allowedInText: true
|
|
52
|
+
},
|
|
53
|
+
handler: ({ parser, token }, args) => {
|
|
54
|
+
const href = assertNodeType(args[0], "url").url;
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
!parser.settings.isTrusted({
|
|
58
|
+
command: "\\url",
|
|
59
|
+
url: href
|
|
60
|
+
})
|
|
61
|
+
) {
|
|
62
|
+
throw new ParseError(`Function "\\url" is not trusted`, token)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const chars = [];
|
|
66
|
+
for (let i = 0; i < href.length; i++) {
|
|
67
|
+
let c = href[i];
|
|
68
|
+
if (c === "~") {
|
|
69
|
+
c = "\\textasciitilde";
|
|
70
|
+
}
|
|
71
|
+
chars.push({
|
|
72
|
+
type: "textord",
|
|
73
|
+
mode: "text",
|
|
74
|
+
text: c
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const body = {
|
|
78
|
+
type: "text",
|
|
79
|
+
mode: parser.mode,
|
|
80
|
+
font: "\\texttt",
|
|
81
|
+
body: chars
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
type: "href",
|
|
85
|
+
mode: parser.mode,
|
|
86
|
+
href,
|
|
87
|
+
body: ordargument(body)
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import defineFunction, { ordargument } from "../defineFunction";
|
|
2
|
+
import { assertNodeType } from "../parseNode";
|
|
3
|
+
import ParseError from "../ParseError";
|
|
4
|
+
|
|
5
|
+
import * as mml from "../buildMathML";
|
|
6
|
+
|
|
7
|
+
defineFunction({
|
|
8
|
+
type: "html",
|
|
9
|
+
names: ["\\class", "\\id", "\\style", "\\data"],
|
|
10
|
+
props: {
|
|
11
|
+
numArgs: 2,
|
|
12
|
+
argTypes: ["raw", "original"],
|
|
13
|
+
allowedInText: true
|
|
14
|
+
},
|
|
15
|
+
handler: ({ parser, funcName, token }, args) => {
|
|
16
|
+
const value = assertNodeType(args[0], "raw").string;
|
|
17
|
+
const body = args[1];
|
|
18
|
+
|
|
19
|
+
if (parser.settings.strict) {
|
|
20
|
+
throw new ParseError(`Function "${funcName}" is disabled in strict mode`, token)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let trustContext;
|
|
24
|
+
const attributes = {};
|
|
25
|
+
|
|
26
|
+
switch (funcName) {
|
|
27
|
+
case "\\class":
|
|
28
|
+
attributes.class = value;
|
|
29
|
+
trustContext = {
|
|
30
|
+
command: "\\class",
|
|
31
|
+
class: value
|
|
32
|
+
};
|
|
33
|
+
break;
|
|
34
|
+
case "\\id":
|
|
35
|
+
attributes.id = value;
|
|
36
|
+
trustContext = {
|
|
37
|
+
command: "\\id",
|
|
38
|
+
id: value
|
|
39
|
+
};
|
|
40
|
+
break;
|
|
41
|
+
case "\\style":
|
|
42
|
+
attributes.style = value;
|
|
43
|
+
trustContext = {
|
|
44
|
+
command: "\\style",
|
|
45
|
+
style: value
|
|
46
|
+
};
|
|
47
|
+
break;
|
|
48
|
+
case "\\data": {
|
|
49
|
+
const data = value.split(",");
|
|
50
|
+
for (let i = 0; i < data.length; i++) {
|
|
51
|
+
const keyVal = data[i].split("=");
|
|
52
|
+
if (keyVal.length !== 2) {
|
|
53
|
+
throw new ParseError("Error parsing key-value for \\data");
|
|
54
|
+
}
|
|
55
|
+
attributes["data-" + keyVal[0].trim()] = keyVal[1].trim();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
trustContext = {
|
|
59
|
+
command: "\\data",
|
|
60
|
+
attributes
|
|
61
|
+
};
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
default:
|
|
65
|
+
throw new Error("Unrecognized html command");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!parser.settings.isTrusted(trustContext)) {
|
|
69
|
+
throw new ParseError(`Function "${funcName}" is not trusted`, token)
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
type: "html",
|
|
73
|
+
mode: parser.mode,
|
|
74
|
+
attributes,
|
|
75
|
+
body: ordargument(body)
|
|
76
|
+
};
|
|
77
|
+
},
|
|
78
|
+
mathmlBuilder: (group, style) => {
|
|
79
|
+
const element = mml.buildExpressionRow(group.body, style);
|
|
80
|
+
|
|
81
|
+
const classes = [];
|
|
82
|
+
if (group.attributes.class) {
|
|
83
|
+
classes.push(...group.attributes.class.trim().split(/\s+/));
|
|
84
|
+
}
|
|
85
|
+
element.classes = classes;
|
|
86
|
+
|
|
87
|
+
for (const attr in group.attributes) {
|
|
88
|
+
if (attr !== "class" && Object.prototype.hasOwnProperty.call(group.attributes, attr)) {
|
|
89
|
+
element.setAttribute(attr, group.attributes[attr]);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return element;
|
|
94
|
+
}
|
|
95
|
+
});
|