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,304 @@
|
|
|
1
|
+
import defineFunction from "../defineFunction";
|
|
2
|
+
import mathMLTree from "../mathMLTree";
|
|
3
|
+
import ParseError from "../ParseError";
|
|
4
|
+
import { assertNodeType, checkSymbolNodeType } from "../parseNode";
|
|
5
|
+
|
|
6
|
+
import * as mml from "../buildMathML";
|
|
7
|
+
|
|
8
|
+
// Extra data needed for the delimiter handler down below
|
|
9
|
+
export const delimiterSizes = {
|
|
10
|
+
"\\bigl": { mclass: "mopen", size: 1 },
|
|
11
|
+
"\\Bigl": { mclass: "mopen", size: 2 },
|
|
12
|
+
"\\biggl": { mclass: "mopen", size: 3 },
|
|
13
|
+
"\\Biggl": { mclass: "mopen", size: 4 },
|
|
14
|
+
"\\bigr": { mclass: "mclose", size: 1 },
|
|
15
|
+
"\\Bigr": { mclass: "mclose", size: 2 },
|
|
16
|
+
"\\biggr": { mclass: "mclose", size: 3 },
|
|
17
|
+
"\\Biggr": { mclass: "mclose", size: 4 },
|
|
18
|
+
"\\bigm": { mclass: "mrel", size: 1 },
|
|
19
|
+
"\\Bigm": { mclass: "mrel", size: 2 },
|
|
20
|
+
"\\biggm": { mclass: "mrel", size: 3 },
|
|
21
|
+
"\\Biggm": { mclass: "mrel", size: 4 },
|
|
22
|
+
"\\big": { mclass: "mord", size: 1 },
|
|
23
|
+
"\\Big": { mclass: "mord", size: 2 },
|
|
24
|
+
"\\bigg": { mclass: "mord", size: 3 },
|
|
25
|
+
"\\Bigg": { mclass: "mord", size: 4 }
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const delimiters = [
|
|
29
|
+
"(",
|
|
30
|
+
"\\lparen",
|
|
31
|
+
")",
|
|
32
|
+
"\\rparen",
|
|
33
|
+
"[",
|
|
34
|
+
"\\lbrack",
|
|
35
|
+
"]",
|
|
36
|
+
"\\rbrack",
|
|
37
|
+
"\\{",
|
|
38
|
+
"\\lbrace",
|
|
39
|
+
"\\}",
|
|
40
|
+
"\\rbrace",
|
|
41
|
+
"\\lfloor",
|
|
42
|
+
"\\rfloor",
|
|
43
|
+
"\u230a",
|
|
44
|
+
"\u230b",
|
|
45
|
+
"\\lceil",
|
|
46
|
+
"\\rceil",
|
|
47
|
+
"\u2308",
|
|
48
|
+
"\u2309",
|
|
49
|
+
"<",
|
|
50
|
+
">",
|
|
51
|
+
"\\langle",
|
|
52
|
+
"\u27e8",
|
|
53
|
+
"\\rangle",
|
|
54
|
+
"\u27e9",
|
|
55
|
+
"\\lt",
|
|
56
|
+
"\\gt",
|
|
57
|
+
"\\lvert",
|
|
58
|
+
"\\rvert",
|
|
59
|
+
"\\lVert",
|
|
60
|
+
"\\rVert",
|
|
61
|
+
"\\lgroup",
|
|
62
|
+
"\\rgroup",
|
|
63
|
+
"\u27ee",
|
|
64
|
+
"\u27ef",
|
|
65
|
+
"\\lmoustache",
|
|
66
|
+
"\\rmoustache",
|
|
67
|
+
"\u23b0",
|
|
68
|
+
"\u23b1",
|
|
69
|
+
"\\llbracket",
|
|
70
|
+
"\\rrbracket",
|
|
71
|
+
"\u27e6",
|
|
72
|
+
"\u27e6",
|
|
73
|
+
"\\lBrace",
|
|
74
|
+
"\\rBrace",
|
|
75
|
+
"\u2983",
|
|
76
|
+
"\u2984",
|
|
77
|
+
"/",
|
|
78
|
+
"\\backslash",
|
|
79
|
+
"|",
|
|
80
|
+
"\\vert",
|
|
81
|
+
"\\|",
|
|
82
|
+
"\\Vert",
|
|
83
|
+
"\\uparrow",
|
|
84
|
+
"\\Uparrow",
|
|
85
|
+
"\\downarrow",
|
|
86
|
+
"\\Downarrow",
|
|
87
|
+
"\\updownarrow",
|
|
88
|
+
"\\Updownarrow",
|
|
89
|
+
"."
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
// Metrics of the different sizes. Found by looking at TeX's output of
|
|
93
|
+
// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
|
|
94
|
+
// Used to create stacked delimiters of appropriate sizes in makeSizedDelim.
|
|
95
|
+
const sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0];
|
|
96
|
+
|
|
97
|
+
// Delimiter functions
|
|
98
|
+
function checkDelimiter(delim, context) {
|
|
99
|
+
if (delim.type === "ordgroup" && delim.body.length === 1 && delim.body[0].text === "\u2044") {
|
|
100
|
+
// Recover "/" from the zero spacing group. (See macros.js)
|
|
101
|
+
delim = { type: "textord", text: "/", mode: "math" }
|
|
102
|
+
}
|
|
103
|
+
const symDelim = checkSymbolNodeType(delim)
|
|
104
|
+
if (symDelim && delimiters.includes(symDelim.text)) {
|
|
105
|
+
// If a character is not in the MathML operator dictionary, it will not stretch.
|
|
106
|
+
// Replace such characters w/characters that will stretch.
|
|
107
|
+
if (["<", "\\lt"].includes(symDelim.text)) { symDelim.text = "⟨" }
|
|
108
|
+
if ([">", "\\gt"].includes(symDelim.text)) { symDelim.text = "⟩" }
|
|
109
|
+
if (symDelim.text === "/") { symDelim.text = "\u2215" }
|
|
110
|
+
if (symDelim.text === "\\backslash") { symDelim.text = "\u2216" }
|
|
111
|
+
return symDelim;
|
|
112
|
+
} else if (symDelim) {
|
|
113
|
+
throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim);
|
|
114
|
+
} else {
|
|
115
|
+
throw new ParseError(`Invalid delimiter type '${delim.type}'`, delim);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
defineFunction({
|
|
120
|
+
type: "delimsizing",
|
|
121
|
+
names: [
|
|
122
|
+
"\\bigl",
|
|
123
|
+
"\\Bigl",
|
|
124
|
+
"\\biggl",
|
|
125
|
+
"\\Biggl",
|
|
126
|
+
"\\bigr",
|
|
127
|
+
"\\Bigr",
|
|
128
|
+
"\\biggr",
|
|
129
|
+
"\\Biggr",
|
|
130
|
+
"\\bigm",
|
|
131
|
+
"\\Bigm",
|
|
132
|
+
"\\biggm",
|
|
133
|
+
"\\Biggm",
|
|
134
|
+
"\\big",
|
|
135
|
+
"\\Big",
|
|
136
|
+
"\\bigg",
|
|
137
|
+
"\\Bigg"
|
|
138
|
+
],
|
|
139
|
+
props: {
|
|
140
|
+
numArgs: 1,
|
|
141
|
+
argTypes: ["primitive"]
|
|
142
|
+
},
|
|
143
|
+
handler: (context, args) => {
|
|
144
|
+
const delim = checkDelimiter(args[0], context);
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
type: "delimsizing",
|
|
148
|
+
mode: context.parser.mode,
|
|
149
|
+
size: delimiterSizes[context.funcName].size,
|
|
150
|
+
mclass: delimiterSizes[context.funcName].mclass,
|
|
151
|
+
delim: delim.text
|
|
152
|
+
};
|
|
153
|
+
},
|
|
154
|
+
mathmlBuilder: (group) => {
|
|
155
|
+
const children = [];
|
|
156
|
+
|
|
157
|
+
if (group.delim === ".") { group.delim = "" }
|
|
158
|
+
children.push(mml.makeText(group.delim, group.mode));
|
|
159
|
+
|
|
160
|
+
const node = new mathMLTree.MathNode("mo", children);
|
|
161
|
+
|
|
162
|
+
if (group.mclass === "mopen" || group.mclass === "mclose") {
|
|
163
|
+
// Only some of the delimsizing functions act as fences, and they
|
|
164
|
+
// return "mopen" or "mclose" mclass.
|
|
165
|
+
node.setAttribute("fence", "true");
|
|
166
|
+
} else {
|
|
167
|
+
// Explicitly disable fencing if it's not a fence, to override the
|
|
168
|
+
// defaults.
|
|
169
|
+
node.setAttribute("fence", "false");
|
|
170
|
+
}
|
|
171
|
+
if (group.delim === "\u2216" || group.delim.indexOf("arrow") > -1) {
|
|
172
|
+
// \backslash is not in the operator dictionary,
|
|
173
|
+
// so we have to explicitly set stretchy to true.
|
|
174
|
+
node.setAttribute("stretchy", "true")
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
node.setAttribute("symmetric", "true"); // Needed for tall arrows in Firefox.
|
|
178
|
+
node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em");
|
|
179
|
+
// Don't set the maxsize attribute. It's broken in Chromium.
|
|
180
|
+
return node;
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
function assertParsed(group) {
|
|
185
|
+
if (!group.body) {
|
|
186
|
+
throw new Error("Bug: The leftright ParseNode wasn't fully parsed.");
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
defineFunction({
|
|
191
|
+
type: "leftright-right",
|
|
192
|
+
names: ["\\right"],
|
|
193
|
+
props: {
|
|
194
|
+
numArgs: 1,
|
|
195
|
+
argTypes: ["primitive"]
|
|
196
|
+
},
|
|
197
|
+
handler: (context, args) => {
|
|
198
|
+
// \left case below triggers parsing of \right in
|
|
199
|
+
// `const right = parser.parseFunction();`
|
|
200
|
+
// uses this return value.
|
|
201
|
+
const color = context.parser.gullet.macros.get("\\current@color");
|
|
202
|
+
if (color && typeof color !== "string") {
|
|
203
|
+
throw new ParseError("\\current@color set to non-string in \\right");
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
type: "leftright-right",
|
|
207
|
+
mode: context.parser.mode,
|
|
208
|
+
delim: checkDelimiter(args[0], context).text,
|
|
209
|
+
color // undefined if not set via \color
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
defineFunction({
|
|
215
|
+
type: "leftright",
|
|
216
|
+
names: ["\\left"],
|
|
217
|
+
props: {
|
|
218
|
+
numArgs: 1,
|
|
219
|
+
argTypes: ["primitive"]
|
|
220
|
+
},
|
|
221
|
+
handler: (context, args) => {
|
|
222
|
+
const delim = checkDelimiter(args[0], context);
|
|
223
|
+
|
|
224
|
+
const parser = context.parser;
|
|
225
|
+
// Parse out the implicit body
|
|
226
|
+
++parser.leftrightDepth;
|
|
227
|
+
// parseExpression stops before '\\right'
|
|
228
|
+
const body = parser.parseExpression(false);
|
|
229
|
+
--parser.leftrightDepth;
|
|
230
|
+
// Check the next token
|
|
231
|
+
parser.expect("\\right", false);
|
|
232
|
+
const right = assertNodeType(parser.parseFunction(), "leftright-right");
|
|
233
|
+
return {
|
|
234
|
+
type: "leftright",
|
|
235
|
+
mode: parser.mode,
|
|
236
|
+
body,
|
|
237
|
+
left: delim.text,
|
|
238
|
+
right: right.delim,
|
|
239
|
+
rightColor: right.color
|
|
240
|
+
};
|
|
241
|
+
},
|
|
242
|
+
mathmlBuilder: (group, style) => {
|
|
243
|
+
assertParsed(group);
|
|
244
|
+
const inner = mml.buildExpression(group.body, style);
|
|
245
|
+
|
|
246
|
+
if (group.left === ".") { group.left = "" }
|
|
247
|
+
const leftNode = new mathMLTree.MathNode("mo", [mml.makeText(group.left, group.mode)]);
|
|
248
|
+
leftNode.setAttribute("fence", "true")
|
|
249
|
+
leftNode.setAttribute("form", "prefix")
|
|
250
|
+
if (group.left === "\u2216" || group.left.indexOf("arrow") > -1) {
|
|
251
|
+
leftNode.setAttribute("stretchy", "true")
|
|
252
|
+
}
|
|
253
|
+
inner.unshift(leftNode)
|
|
254
|
+
|
|
255
|
+
if (group.right === ".") { group.right = "" }
|
|
256
|
+
const rightNode = new mathMLTree.MathNode("mo", [mml.makeText(group.right, group.mode)]);
|
|
257
|
+
rightNode.setAttribute("fence", "true")
|
|
258
|
+
rightNode.setAttribute("form", "postfix")
|
|
259
|
+
if (group.right === "\u2216" || group.right.indexOf("arrow") > -1) {
|
|
260
|
+
rightNode.setAttribute("stretchy", "true")
|
|
261
|
+
}
|
|
262
|
+
if (group.rightColor) { rightNode.setAttribute("mathcolor", group.rightColor) }
|
|
263
|
+
inner.push(rightNode)
|
|
264
|
+
|
|
265
|
+
return mml.makeRow(inner);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
defineFunction({
|
|
270
|
+
type: "middle",
|
|
271
|
+
names: ["\\middle"],
|
|
272
|
+
props: {
|
|
273
|
+
numArgs: 1,
|
|
274
|
+
argTypes: ["primitive"]
|
|
275
|
+
},
|
|
276
|
+
handler: (context, args) => {
|
|
277
|
+
const delim = checkDelimiter(args[0], context);
|
|
278
|
+
if (!context.parser.leftrightDepth) {
|
|
279
|
+
throw new ParseError("\\middle without preceding \\left", delim);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
type: "middle",
|
|
284
|
+
mode: context.parser.mode,
|
|
285
|
+
delim: delim.text
|
|
286
|
+
};
|
|
287
|
+
},
|
|
288
|
+
mathmlBuilder: (group, style) => {
|
|
289
|
+
const textNode = mml.makeText(group.delim, group.mode);
|
|
290
|
+
const middleNode = new mathMLTree.MathNode("mo", [textNode]);
|
|
291
|
+
middleNode.setAttribute("fence", "true");
|
|
292
|
+
if (group.delim.indexOf("arrow") > -1) {
|
|
293
|
+
middleNode.setAttribute("stretchy", "true")
|
|
294
|
+
}
|
|
295
|
+
// The next line is not semantically correct, but
|
|
296
|
+
// Chromium fails to stretch if it is not there.
|
|
297
|
+
middleNode.setAttribute("form", "prefix")
|
|
298
|
+
// MathML gives 5/18em spacing to each <mo> element.
|
|
299
|
+
// \middle should get delimiter spacing instead.
|
|
300
|
+
middleNode.setAttribute("lspace", "0.05em");
|
|
301
|
+
middleNode.setAttribute("rspace", "0.05em");
|
|
302
|
+
return middleNode;
|
|
303
|
+
}
|
|
304
|
+
});
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import defineFunction from "../defineFunction";
|
|
2
|
+
import mathMLTree from "../mathMLTree";
|
|
3
|
+
import { assertNodeType } from "../parseNode";
|
|
4
|
+
import { colorFromSpec, validateColor } from "./color"
|
|
5
|
+
import * as mml from "../buildMathML";
|
|
6
|
+
|
|
7
|
+
const padding = _ => {
|
|
8
|
+
const node = new mathMLTree.MathNode("mspace")
|
|
9
|
+
node.setAttribute("width", "3pt")
|
|
10
|
+
return node
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const mathmlBuilder = (group, style) => {
|
|
14
|
+
let node
|
|
15
|
+
if (group.label.indexOf("colorbox") > -1) {
|
|
16
|
+
// Chrome mpadded +width attribute is broken. Insert <mspace>
|
|
17
|
+
node = new mathMLTree.MathNode("mpadded", [
|
|
18
|
+
padding(),
|
|
19
|
+
mml.buildGroup(group.body, style),
|
|
20
|
+
padding()
|
|
21
|
+
])
|
|
22
|
+
} else {
|
|
23
|
+
node = new mathMLTree.MathNode("menclose", [mml.buildGroup(group.body, style)])
|
|
24
|
+
}
|
|
25
|
+
switch (group.label) {
|
|
26
|
+
case "\\overline":
|
|
27
|
+
node.setAttribute("notation", "top")
|
|
28
|
+
node.style.padding = "0.1em 0 0 0"
|
|
29
|
+
node.style.borderTop = "0.065em solid"
|
|
30
|
+
break
|
|
31
|
+
case "\\underline":
|
|
32
|
+
node.setAttribute("notation", "bottom")
|
|
33
|
+
node.style.padding = "0 0 0.1em 0"
|
|
34
|
+
node.style.borderBottom = "0.065em solid"
|
|
35
|
+
break
|
|
36
|
+
case "\\cancel":
|
|
37
|
+
node.setAttribute("notation", "updiagonalstrike");
|
|
38
|
+
node.classes.push("cancel")
|
|
39
|
+
break
|
|
40
|
+
case "\\bcancel":
|
|
41
|
+
node.setAttribute("notation", "downdiagonalstrike");
|
|
42
|
+
node.classes.push("bcancel")
|
|
43
|
+
break
|
|
44
|
+
/*
|
|
45
|
+
case "\\longdiv":
|
|
46
|
+
node.setAttribute("notation", "longdiv");
|
|
47
|
+
break
|
|
48
|
+
case "\\phase":
|
|
49
|
+
node.setAttribute("notation", "phasorangle");
|
|
50
|
+
break */
|
|
51
|
+
case "\\angl":
|
|
52
|
+
node.setAttribute("notation", "actuarial")
|
|
53
|
+
node.style.padding = "0.03889em 0.03889em 0 0.03889em"
|
|
54
|
+
node.style.borderTop = "0.049em solid"
|
|
55
|
+
node.style.borderRight = "0.049em solid"
|
|
56
|
+
node.style.marginRight = "0.03889em"
|
|
57
|
+
break
|
|
58
|
+
case "\\sout":
|
|
59
|
+
node.setAttribute("notation", "horizontalstrike");
|
|
60
|
+
node.style["text-decoration"] = "line-through 0.08em solid"
|
|
61
|
+
break
|
|
62
|
+
case "\\fbox":
|
|
63
|
+
node.setAttribute("notation", "box");
|
|
64
|
+
node.style = { padding: "3pt", border: "1px solid" }
|
|
65
|
+
break
|
|
66
|
+
case "\\fcolorbox":
|
|
67
|
+
case "\\colorbox": {
|
|
68
|
+
// <menclose> doesn't have a good notation option for \colorbox.
|
|
69
|
+
// So use <mpadded> instead. Set some attributes that come
|
|
70
|
+
// included with <menclose>.
|
|
71
|
+
//const fboxsep = 3; // 3 pt from LaTeX source2e
|
|
72
|
+
//node.setAttribute("height", `+${2 * fboxsep}pt`)
|
|
73
|
+
//node.setAttribute("voffset", `${fboxsep}pt`)
|
|
74
|
+
const style = { padding: "3pt 0 3pt 0" }
|
|
75
|
+
|
|
76
|
+
if (group.label === "\\fcolorbox") {
|
|
77
|
+
style.border = "0.06em solid " + String(group.borderColor)
|
|
78
|
+
}
|
|
79
|
+
node.style = style
|
|
80
|
+
break
|
|
81
|
+
}
|
|
82
|
+
case "\\xcancel":
|
|
83
|
+
node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
|
|
84
|
+
node.classes.push("xcancel")
|
|
85
|
+
break
|
|
86
|
+
}
|
|
87
|
+
if (group.backgroundColor) {
|
|
88
|
+
node.setAttribute("mathbackground", group.backgroundColor);
|
|
89
|
+
}
|
|
90
|
+
return node;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
defineFunction({
|
|
94
|
+
type: "enclose",
|
|
95
|
+
names: ["\\colorbox"],
|
|
96
|
+
props: {
|
|
97
|
+
numArgs: 2,
|
|
98
|
+
numOptionalArgs: 1,
|
|
99
|
+
allowedInText: true,
|
|
100
|
+
argTypes: ["raw", "raw", "text"]
|
|
101
|
+
},
|
|
102
|
+
handler({ parser, funcName }, args, optArgs) {
|
|
103
|
+
const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string
|
|
104
|
+
let color = ""
|
|
105
|
+
if (model) {
|
|
106
|
+
const spec = assertNodeType(args[0], "raw").string
|
|
107
|
+
color = colorFromSpec(model, spec)
|
|
108
|
+
} else {
|
|
109
|
+
color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros)
|
|
110
|
+
}
|
|
111
|
+
const body = args[1];
|
|
112
|
+
return {
|
|
113
|
+
type: "enclose",
|
|
114
|
+
mode: parser.mode,
|
|
115
|
+
label: funcName,
|
|
116
|
+
backgroundColor: color,
|
|
117
|
+
body
|
|
118
|
+
};
|
|
119
|
+
},
|
|
120
|
+
mathmlBuilder
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
defineFunction({
|
|
124
|
+
type: "enclose",
|
|
125
|
+
names: ["\\fcolorbox"],
|
|
126
|
+
props: {
|
|
127
|
+
numArgs: 3,
|
|
128
|
+
numOptionalArgs: 1,
|
|
129
|
+
allowedInText: true,
|
|
130
|
+
argTypes: ["raw", "raw", "raw", "text"]
|
|
131
|
+
},
|
|
132
|
+
handler({ parser, funcName }, args, optArgs) {
|
|
133
|
+
const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string
|
|
134
|
+
let borderColor = ""
|
|
135
|
+
let backgroundColor
|
|
136
|
+
if (model) {
|
|
137
|
+
const borderSpec = assertNodeType(args[0], "raw").string
|
|
138
|
+
const backgroundSpec = assertNodeType(args[0], "raw").string
|
|
139
|
+
borderColor = colorFromSpec(model, borderSpec)
|
|
140
|
+
backgroundColor = colorFromSpec(model, backgroundSpec)
|
|
141
|
+
} else {
|
|
142
|
+
borderColor = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros)
|
|
143
|
+
backgroundColor = validateColor(assertNodeType(args[1], "raw").string, parser.gullet.macros)
|
|
144
|
+
}
|
|
145
|
+
const body = args[2];
|
|
146
|
+
return {
|
|
147
|
+
type: "enclose",
|
|
148
|
+
mode: parser.mode,
|
|
149
|
+
label: funcName,
|
|
150
|
+
backgroundColor,
|
|
151
|
+
borderColor,
|
|
152
|
+
body
|
|
153
|
+
};
|
|
154
|
+
},
|
|
155
|
+
mathmlBuilder
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
defineFunction({
|
|
159
|
+
type: "enclose",
|
|
160
|
+
names: ["\\fbox"],
|
|
161
|
+
props: {
|
|
162
|
+
numArgs: 1,
|
|
163
|
+
argTypes: ["hbox"],
|
|
164
|
+
allowedInText: true
|
|
165
|
+
},
|
|
166
|
+
handler({ parser }, args) {
|
|
167
|
+
return {
|
|
168
|
+
type: "enclose",
|
|
169
|
+
mode: parser.mode,
|
|
170
|
+
label: "\\fbox",
|
|
171
|
+
body: args[0]
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
defineFunction({
|
|
177
|
+
type: "enclose",
|
|
178
|
+
names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline", "\\underline"],
|
|
179
|
+
// , "\\phase", "\\longdiv"
|
|
180
|
+
props: {
|
|
181
|
+
numArgs: 1
|
|
182
|
+
},
|
|
183
|
+
handler({ parser, funcName }, args) {
|
|
184
|
+
const body = args[0];
|
|
185
|
+
return {
|
|
186
|
+
type: "enclose",
|
|
187
|
+
mode: parser.mode,
|
|
188
|
+
label: funcName,
|
|
189
|
+
body
|
|
190
|
+
};
|
|
191
|
+
},
|
|
192
|
+
mathmlBuilder
|
|
193
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import defineFunction from "../defineFunction";
|
|
2
|
+
import mathMLTree from "../mathMLTree";
|
|
3
|
+
|
|
4
|
+
defineFunction({
|
|
5
|
+
type: "envTag",
|
|
6
|
+
names: ["\\env@tag"],
|
|
7
|
+
props: {
|
|
8
|
+
numArgs: 1,
|
|
9
|
+
argTypes: ["math"]
|
|
10
|
+
},
|
|
11
|
+
handler({ parser }, args) {
|
|
12
|
+
return {
|
|
13
|
+
type: "envTag",
|
|
14
|
+
mode: parser.mode,
|
|
15
|
+
body: args[0]
|
|
16
|
+
};
|
|
17
|
+
},
|
|
18
|
+
mathmlBuilder(group, style) {
|
|
19
|
+
return new mathMLTree.MathNode("mrow");
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
defineFunction({
|
|
24
|
+
type: "noTag",
|
|
25
|
+
names: ["\\env@notag"],
|
|
26
|
+
props: {
|
|
27
|
+
numArgs: 0
|
|
28
|
+
},
|
|
29
|
+
handler({ parser }) {
|
|
30
|
+
return {
|
|
31
|
+
type: "noTag",
|
|
32
|
+
mode: parser.mode
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
mathmlBuilder(group, style) {
|
|
36
|
+
return new mathMLTree.MathNode("mrow");
|
|
37
|
+
}
|
|
38
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import defineFunction from "../defineFunction";
|
|
2
|
+
import ParseError from "../ParseError";
|
|
3
|
+
import { assertNodeType } from "../parseNode";
|
|
4
|
+
import environments from "../environments";
|
|
5
|
+
|
|
6
|
+
// Environment delimiters. HTML/MathML rendering is defined in the corresponding
|
|
7
|
+
// defineEnvironment definitions.
|
|
8
|
+
defineFunction({
|
|
9
|
+
type: "environment",
|
|
10
|
+
names: ["\\begin", "\\end"],
|
|
11
|
+
props: {
|
|
12
|
+
numArgs: 1,
|
|
13
|
+
argTypes: ["text"]
|
|
14
|
+
},
|
|
15
|
+
handler({ parser, funcName }, args) {
|
|
16
|
+
const nameGroup = args[0];
|
|
17
|
+
if (nameGroup.type !== "ordgroup") {
|
|
18
|
+
throw new ParseError("Invalid environment name", nameGroup);
|
|
19
|
+
}
|
|
20
|
+
let envName = "";
|
|
21
|
+
for (let i = 0; i < nameGroup.body.length; ++i) {
|
|
22
|
+
envName += assertNodeType(nameGroup.body[i], "textord").text;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (funcName === "\\begin") {
|
|
26
|
+
// begin...end is similar to left...right
|
|
27
|
+
if (!Object.prototype.hasOwnProperty.call(environments, envName )) {
|
|
28
|
+
throw new ParseError("No such environment: " + envName, nameGroup);
|
|
29
|
+
}
|
|
30
|
+
// Build the environment object. Arguments and other information will
|
|
31
|
+
// be made available to the begin and end methods using properties.
|
|
32
|
+
const env = environments[envName];
|
|
33
|
+
const { args, optArgs } = parser.parseArguments("\\begin{" + envName + "}", env);
|
|
34
|
+
const context = {
|
|
35
|
+
mode: parser.mode,
|
|
36
|
+
envName,
|
|
37
|
+
parser
|
|
38
|
+
};
|
|
39
|
+
const result = env.handler(context, args, optArgs);
|
|
40
|
+
parser.expect("\\end", false);
|
|
41
|
+
const endNameToken = parser.nextToken;
|
|
42
|
+
const end = assertNodeType(parser.parseFunction(), "environment");
|
|
43
|
+
if (end.name !== envName) {
|
|
44
|
+
throw new ParseError(
|
|
45
|
+
`Mismatch: \\begin{${envName}} matched by \\end{${end.name}}`,
|
|
46
|
+
endNameToken
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
type: "environment",
|
|
54
|
+
mode: parser.mode,
|
|
55
|
+
name: envName,
|
|
56
|
+
nameGroup
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
});
|