katex 0.10.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +141 -0
- package/LICENSE +1 -1
- package/README.md +6 -6
- package/cli.js +0 -0
- package/contrib/auto-render/auto-render.js +12 -3
- package/contrib/copy-tex/README.md +3 -5
- package/contrib/mathtex-script-type/README.md +12 -14
- package/contrib/mhchem/README.md +3 -1
- package/contrib/render-a11y-string/render-a11y-string.js +712 -0
- package/contrib/render-a11y-string/test/render-a11y-string-spec.js +526 -0
- package/dist/README.md +6 -6
- package/dist/contrib/auto-render.js +14 -3
- package/dist/contrib/auto-render.min.js +1 -1
- package/dist/contrib/auto-render.mjs +14 -3
- package/dist/contrib/mhchem.min.js +1 -1
- package/dist/contrib/render-a11y-string.js +870 -0
- package/dist/contrib/render-a11y-string.min.js +1 -0
- package/dist/contrib/render-a11y-string.mjs +753 -0
- package/dist/fonts/KaTeX_AMS-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_AMS-Regular.woff +0 -0
- package/dist/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
- package/dist/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
- package/dist/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- package/dist/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
- package/dist/fonts/KaTeX_Fraktur-Bold.woff +0 -0
- package/dist/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- package/dist/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Fraktur-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Main-Bold.ttf +0 -0
- package/dist/fonts/KaTeX_Main-Bold.woff +0 -0
- package/dist/fonts/KaTeX_Main-Bold.woff2 +0 -0
- package/dist/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
- package/dist/fonts/KaTeX_Main-BoldItalic.woff +0 -0
- package/dist/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- package/dist/fonts/KaTeX_Main-Italic.ttf +0 -0
- package/dist/fonts/KaTeX_Main-Italic.woff +0 -0
- package/dist/fonts/KaTeX_Main-Italic.woff2 +0 -0
- package/dist/fonts/KaTeX_Main-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Main-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Main-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
- package/dist/fonts/KaTeX_Math-BoldItalic.woff +0 -0
- package/dist/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- package/dist/fonts/KaTeX_Math-Italic.ttf +0 -0
- package/dist/fonts/KaTeX_Math-Italic.woff +0 -0
- package/dist/fonts/KaTeX_Math-Italic.woff2 +0 -0
- package/dist/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
- package/dist/fonts/KaTeX_SansSerif-Bold.woff +0 -0
- package/dist/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- package/dist/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
- package/dist/fonts/KaTeX_SansSerif-Italic.woff +0 -0
- package/dist/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- package/dist/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_SansSerif-Regular.woff +0 -0
- package/dist/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Script-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Script-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Script-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Size1-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Size1-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Size2-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Size2-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Size3-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Size3-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Size4-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Size4-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- package/dist/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
- package/dist/fonts/KaTeX_Typewriter-Regular.woff +0 -0
- package/dist/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- package/dist/katex.css +34 -10
- package/dist/katex.js +2906 -2115
- package/dist/katex.min.css +1 -1
- package/dist/katex.min.js +1 -1
- package/dist/katex.mjs +2809 -2020
- package/package.json +12 -11
- package/src/Lexer.js +1 -0
- package/src/MacroExpander.js +39 -10
- package/src/Options.js +15 -75
- package/src/Parser.js +152 -115
- package/src/Settings.js +70 -7
- package/src/Token.js +2 -0
- package/src/buildCommon.js +24 -90
- package/src/buildHTML.js +31 -31
- package/src/buildMathML.js +52 -9
- package/src/buildTree.js +13 -6
- package/src/defineFunction.js +7 -22
- package/src/delimiter.js +66 -27
- package/src/domTree.js +71 -4
- package/src/environments/array.js +235 -25
- package/src/fontMetrics.js +11 -2
- package/src/functions/accent.js +9 -9
- package/src/functions/accentunder.js +2 -2
- package/src/functions/arrow.js +15 -5
- package/src/functions/color.js +9 -38
- package/src/functions/def.js +184 -0
- package/src/functions/delimsizing.js +32 -8
- package/src/functions/enclose.js +33 -6
- package/src/functions/font.js +4 -1
- package/src/functions/genfrac.js +39 -27
- package/src/functions/horizBrace.js +6 -7
- package/src/functions/href.js +16 -0
- package/src/functions/html.js +102 -0
- package/src/functions/includegraphics.js +153 -0
- package/src/functions/lap.js +4 -7
- package/src/functions/math.js +1 -5
- package/src/functions/mclass.js +41 -2
- package/src/functions/op.js +27 -111
- package/src/functions/operatorname.js +136 -92
- package/src/functions/ordgroup.js +1 -1
- package/src/functions/overline.js +3 -2
- package/src/functions/phantom.js +5 -2
- package/src/functions/raisebox.js +4 -16
- package/src/functions/rule.js +20 -9
- package/src/functions/styling.js +0 -9
- package/src/functions/supsub.js +27 -7
- package/src/functions/symbolsOp.js +4 -0
- package/src/functions/tag.js +20 -4
- package/src/functions/text.js +4 -3
- package/src/functions/underline.js +3 -2
- package/src/functions/utils/assembleSupSub.js +110 -0
- package/src/functions.js +3 -0
- package/src/katex.less +45 -9
- package/src/macros.js +259 -98
- package/src/mathMLTree.js +6 -4
- package/src/parseNode.js +37 -57
- package/src/stretchy.js +3 -1
- package/src/svgGeometry.js +136 -44
- package/src/symbols.js +52 -69
- package/src/tree.js +2 -2
- package/src/types.js +2 -1
- package/src/unicodeAccents.js +3 -1
- package/src/unicodeSymbols.js +30 -321
- package/src/utils.js +10 -0
- package/src/wide-character.js +2 -2
- package/src/unicodeMake.js +0 -70
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
//@flow
|
|
2
|
+
import defineFunction from "../defineFunction";
|
|
3
|
+
import ParseError from "../ParseError";
|
|
4
|
+
import {assertNodeType} from "../parseNode";
|
|
5
|
+
|
|
6
|
+
const globalMap = {
|
|
7
|
+
"\\global": "\\global",
|
|
8
|
+
"\\long": "\\\\globallong",
|
|
9
|
+
"\\\\globallong": "\\\\globallong",
|
|
10
|
+
"\\def": "\\gdef",
|
|
11
|
+
"\\gdef": "\\gdef",
|
|
12
|
+
"\\edef": "\\xdef",
|
|
13
|
+
"\\xdef": "\\xdef",
|
|
14
|
+
"\\let": "\\\\globallet",
|
|
15
|
+
"\\futurelet": "\\\\globalfuture",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const checkControlSequence = (tok) => {
|
|
19
|
+
const name = tok.text;
|
|
20
|
+
if (/^(?:[\\{}$&#^_]|EOF)$/.test(name)) {
|
|
21
|
+
throw new ParseError("Expected a control sequence", tok);
|
|
22
|
+
}
|
|
23
|
+
return name;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const getRHS = (parser) => {
|
|
27
|
+
let tok = parser.gullet.popToken();
|
|
28
|
+
if (tok.text === "=") { // consume optional equals
|
|
29
|
+
tok = parser.gullet.popToken();
|
|
30
|
+
if (tok.text === " ") { // consume one optional space
|
|
31
|
+
tok = parser.gullet.popToken();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return tok;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const letCommand = (parser, name, tok, global) => {
|
|
38
|
+
let macro = parser.gullet.macros.get(tok.text);
|
|
39
|
+
if (macro == null) {
|
|
40
|
+
// don't expand it later even if a macro with the same name is defined
|
|
41
|
+
// e.g., \let\foo=\frac \def\frac{\relax} \frac12
|
|
42
|
+
tok.noexpand = true;
|
|
43
|
+
macro = {
|
|
44
|
+
tokens: [tok],
|
|
45
|
+
numArgs: 0,
|
|
46
|
+
// reproduce the same behavior in expansion
|
|
47
|
+
unexpandable: !parser.gullet.isExpandable(tok.text),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
parser.gullet.macros.set(name, macro, global);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// <assignment> -> <non-macro assignment>|<macro assignment>
|
|
54
|
+
// <non-macro assignment> -> <simple assignment>|\global<non-macro assignment>
|
|
55
|
+
// <macro assignment> -> <definition>|<prefix><macro assignment>
|
|
56
|
+
// <prefix> -> \global|\long|\outer
|
|
57
|
+
defineFunction({
|
|
58
|
+
type: "internal",
|
|
59
|
+
names: [
|
|
60
|
+
"\\global", "\\long",
|
|
61
|
+
"\\\\globallong", // can’t be entered directly
|
|
62
|
+
],
|
|
63
|
+
props: {
|
|
64
|
+
numArgs: 0,
|
|
65
|
+
allowedInText: true,
|
|
66
|
+
},
|
|
67
|
+
handler({parser, funcName}) {
|
|
68
|
+
parser.consumeSpaces();
|
|
69
|
+
const token = parser.fetch();
|
|
70
|
+
if (globalMap[token.text]) {
|
|
71
|
+
// KaTeX doesn't have \par, so ignore \long
|
|
72
|
+
if (funcName === "\\global" || funcName === "\\\\globallong") {
|
|
73
|
+
token.text = globalMap[token.text];
|
|
74
|
+
}
|
|
75
|
+
return assertNodeType(parser.parseFunction(), "internal");
|
|
76
|
+
}
|
|
77
|
+
throw new ParseError(`Invalid token after macro prefix`, token);
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Basic support for macro definitions: \def, \gdef, \edef, \xdef
|
|
82
|
+
// <definition> -> <def><control sequence><definition text>
|
|
83
|
+
// <def> -> \def|\gdef|\edef|\xdef
|
|
84
|
+
// <definition text> -> <parameter text><left brace><balanced text><right brace>
|
|
85
|
+
defineFunction({
|
|
86
|
+
type: "internal",
|
|
87
|
+
names: ["\\def", "\\gdef", "\\edef", "\\xdef"],
|
|
88
|
+
props: {
|
|
89
|
+
numArgs: 0,
|
|
90
|
+
allowedInText: true,
|
|
91
|
+
},
|
|
92
|
+
handler({parser, funcName}) {
|
|
93
|
+
let arg = parser.gullet.consumeArgs(1)[0];
|
|
94
|
+
if (arg.length !== 1) {
|
|
95
|
+
throw new ParseError("\\gdef's first argument must be a macro name");
|
|
96
|
+
}
|
|
97
|
+
const name = arg[0].text;
|
|
98
|
+
// Count argument specifiers, and check they are in the order #1 #2 ...
|
|
99
|
+
let numArgs = 0;
|
|
100
|
+
arg = parser.gullet.consumeArgs(1)[0];
|
|
101
|
+
while (arg.length === 1 && arg[0].text === "#") {
|
|
102
|
+
arg = parser.gullet.consumeArgs(1)[0];
|
|
103
|
+
if (arg.length !== 1) {
|
|
104
|
+
throw new ParseError(
|
|
105
|
+
`Invalid argument number length "${arg.length}"`);
|
|
106
|
+
}
|
|
107
|
+
if (!(/^[1-9]$/.test(arg[0].text))) {
|
|
108
|
+
throw new ParseError(
|
|
109
|
+
`Invalid argument number "${arg[0].text}"`);
|
|
110
|
+
}
|
|
111
|
+
numArgs++;
|
|
112
|
+
if (parseInt(arg[0].text) !== numArgs) {
|
|
113
|
+
throw new ParseError(
|
|
114
|
+
`Argument number "${arg[0].text}" out of order`);
|
|
115
|
+
}
|
|
116
|
+
arg = parser.gullet.consumeArgs(1)[0];
|
|
117
|
+
}
|
|
118
|
+
if (funcName === "\\edef" || funcName === "\\xdef") {
|
|
119
|
+
arg = parser.gullet.expandTokens(arg);
|
|
120
|
+
arg.reverse(); // to fit in with stack order
|
|
121
|
+
}
|
|
122
|
+
// Final arg is the expansion of the macro
|
|
123
|
+
parser.gullet.macros.set(name, {
|
|
124
|
+
tokens: arg,
|
|
125
|
+
numArgs,
|
|
126
|
+
}, funcName === globalMap[funcName]);
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
type: "internal",
|
|
130
|
+
mode: parser.mode,
|
|
131
|
+
};
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// <simple assignment> -> <let assignment>
|
|
136
|
+
// <let assignment> -> \futurelet<control sequence><token><token>
|
|
137
|
+
// | \let<control sequence><equals><one optional space><token>
|
|
138
|
+
// <equals> -> <optional spaces>|<optional spaces>=
|
|
139
|
+
defineFunction({
|
|
140
|
+
type: "internal",
|
|
141
|
+
names: [
|
|
142
|
+
"\\let",
|
|
143
|
+
"\\\\globallet", // can’t be entered directly
|
|
144
|
+
],
|
|
145
|
+
props: {
|
|
146
|
+
numArgs: 0,
|
|
147
|
+
allowedInText: true,
|
|
148
|
+
},
|
|
149
|
+
handler({parser, funcName}) {
|
|
150
|
+
const name = checkControlSequence(parser.gullet.popToken());
|
|
151
|
+
parser.gullet.consumeSpaces();
|
|
152
|
+
const tok = getRHS(parser);
|
|
153
|
+
letCommand(parser, name, tok, funcName === "\\\\globallet");
|
|
154
|
+
return {
|
|
155
|
+
type: "internal",
|
|
156
|
+
mode: parser.mode,
|
|
157
|
+
};
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// ref: https://www.tug.org/TUGboat/tb09-3/tb22bechtolsheim.pdf
|
|
162
|
+
defineFunction({
|
|
163
|
+
type: "internal",
|
|
164
|
+
names: [
|
|
165
|
+
"\\futurelet",
|
|
166
|
+
"\\\\globalfuture", // can’t be entered directly
|
|
167
|
+
],
|
|
168
|
+
props: {
|
|
169
|
+
numArgs: 0,
|
|
170
|
+
allowedInText: true,
|
|
171
|
+
},
|
|
172
|
+
handler({parser, funcName}) {
|
|
173
|
+
const name = checkControlSequence(parser.gullet.popToken());
|
|
174
|
+
const middle = parser.gullet.popToken();
|
|
175
|
+
const tok = parser.gullet.popToken();
|
|
176
|
+
letCommand(parser, name, tok, funcName === "\\\\globalfuture");
|
|
177
|
+
parser.gullet.pushToken(tok);
|
|
178
|
+
parser.gullet.pushToken(middle);
|
|
179
|
+
return {
|
|
180
|
+
type: "internal",
|
|
181
|
+
mode: parser.mode,
|
|
182
|
+
};
|
|
183
|
+
},
|
|
184
|
+
});
|
|
@@ -62,11 +62,12 @@ function checkDelimiter(
|
|
|
62
62
|
const symDelim = checkSymbolNodeType(delim);
|
|
63
63
|
if (symDelim && utils.contains(delimiters, symDelim.text)) {
|
|
64
64
|
return symDelim;
|
|
65
|
-
} else {
|
|
65
|
+
} else if (symDelim) {
|
|
66
66
|
throw new ParseError(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`,
|
|
68
|
+
delim);
|
|
69
|
+
} else {
|
|
70
|
+
throw new ParseError(`Invalid delimiter type '${delim.type}'`, delim);
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
|
|
@@ -145,10 +146,16 @@ defineFunction({
|
|
|
145
146
|
// \left case below triggers parsing of \right in
|
|
146
147
|
// `const right = parser.parseFunction();`
|
|
147
148
|
// uses this return value.
|
|
149
|
+
const color = context.parser.gullet.macros.get("\\current@color");
|
|
150
|
+
if (color && typeof color !== "string") {
|
|
151
|
+
throw new ParseError(
|
|
152
|
+
"\\current@color set to non-string in \\right");
|
|
153
|
+
}
|
|
148
154
|
return {
|
|
149
155
|
type: "leftright-right",
|
|
150
156
|
mode: context.parser.mode,
|
|
151
157
|
delim: checkDelimiter(args[0], context).text,
|
|
158
|
+
color, // undefined if not set via \color
|
|
152
159
|
};
|
|
153
160
|
},
|
|
154
161
|
});
|
|
@@ -178,6 +185,7 @@ defineFunction({
|
|
|
178
185
|
body,
|
|
179
186
|
left: delim.text,
|
|
180
187
|
right: right.delim,
|
|
188
|
+
rightColor: right.color,
|
|
181
189
|
};
|
|
182
190
|
},
|
|
183
191
|
htmlBuilder: (group, options) => {
|
|
@@ -241,12 +249,14 @@ defineFunction({
|
|
|
241
249
|
}
|
|
242
250
|
|
|
243
251
|
let rightDelim;
|
|
244
|
-
// Same for the right delimiter
|
|
252
|
+
// Same for the right delimiter, but using color specified by \color
|
|
245
253
|
if (group.right === ".") {
|
|
246
254
|
rightDelim = html.makeNullDelimiter(options, ["mclose"]);
|
|
247
255
|
} else {
|
|
256
|
+
const colorOptions = group.rightColor ?
|
|
257
|
+
options.withColor(group.rightColor) : options;
|
|
248
258
|
rightDelim = delimiter.leftRightDelim(
|
|
249
|
-
group.right, innerHeight, innerDepth,
|
|
259
|
+
group.right, innerHeight, innerDepth, colorOptions,
|
|
250
260
|
group.mode, ["mclose"]);
|
|
251
261
|
}
|
|
252
262
|
// Add it to the end of the expression.
|
|
@@ -273,6 +283,10 @@ defineFunction({
|
|
|
273
283
|
|
|
274
284
|
rightNode.setAttribute("fence", "true");
|
|
275
285
|
|
|
286
|
+
if (group.rightColor) {
|
|
287
|
+
rightNode.setAttribute("mathcolor", group.rightColor);
|
|
288
|
+
}
|
|
289
|
+
|
|
276
290
|
inner.push(rightNode);
|
|
277
291
|
}
|
|
278
292
|
|
|
@@ -318,9 +332,19 @@ defineFunction({
|
|
|
318
332
|
return middleDelim;
|
|
319
333
|
},
|
|
320
334
|
mathmlBuilder: (group, options) => {
|
|
321
|
-
|
|
322
|
-
|
|
335
|
+
// A Firefox \middle will strech a character vertically only if it
|
|
336
|
+
// is in the fence part of the operator dictionary at:
|
|
337
|
+
// https://www.w3.org/TR/MathML3/appendixc.html.
|
|
338
|
+
// So we need to avoid U+2223 and use plain "|" instead.
|
|
339
|
+
const textNode = (group.delim === "\\vert" || group.delim === "|")
|
|
340
|
+
? mml.makeText("|", "text")
|
|
341
|
+
: mml.makeText(group.delim, group.mode);
|
|
342
|
+
const middleNode = new mathMLTree.MathNode("mo", [textNode]);
|
|
323
343
|
middleNode.setAttribute("fence", "true");
|
|
344
|
+
// MathML gives 5/18em spacing to each <mo> element.
|
|
345
|
+
// \middle should get delimiter spacing instead.
|
|
346
|
+
middleNode.setAttribute("lspace", "0.05em");
|
|
347
|
+
middleNode.setAttribute("rspace", "0.05em");
|
|
324
348
|
return middleNode;
|
|
325
349
|
},
|
|
326
350
|
});
|
package/src/functions/enclose.js
CHANGED
|
@@ -46,15 +46,24 @@ const htmlBuilder = (group, options) => {
|
|
|
46
46
|
|
|
47
47
|
// Add vertical padding
|
|
48
48
|
let vertPad = 0;
|
|
49
|
-
|
|
49
|
+
let ruleThickness = 0;
|
|
50
50
|
// ref: cancel package: \advance\totalheight2\p@ % "+2"
|
|
51
51
|
if (/box/.test(label)) {
|
|
52
|
-
|
|
52
|
+
ruleThickness = Math.max(
|
|
53
|
+
options.fontMetrics().fboxrule, // default
|
|
54
|
+
options.minRuleThickness, // User override.
|
|
55
|
+
);
|
|
56
|
+
vertPad = options.fontMetrics().fboxsep +
|
|
57
|
+
(label === "colorbox" ? 0 : ruleThickness);
|
|
53
58
|
} else {
|
|
54
59
|
vertPad = isSingleChar ? 0.2 : 0;
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
img = stretchy.encloseSpan(inner, label, vertPad, options);
|
|
63
|
+
if (/fbox|boxed|fcolorbox/.test(label)) {
|
|
64
|
+
img.style.borderStyle = "solid";
|
|
65
|
+
img.style.borderWidth = `${ruleThickness}em`;
|
|
66
|
+
}
|
|
58
67
|
imgShift = inner.depth + vertPad;
|
|
59
68
|
|
|
60
69
|
if (group.backgroundColor) {
|
|
@@ -111,8 +120,11 @@ const htmlBuilder = (group, options) => {
|
|
|
111
120
|
};
|
|
112
121
|
|
|
113
122
|
const mathmlBuilder = (group, options) => {
|
|
123
|
+
let fboxsep = 0;
|
|
114
124
|
const node = new mathMLTree.MathNode(
|
|
115
|
-
|
|
125
|
+
(group.label.indexOf("colorbox") > -1) ? "mpadded" : "menclose",
|
|
126
|
+
[mml.buildGroup(group.body, options)]
|
|
127
|
+
);
|
|
116
128
|
switch (group.label) {
|
|
117
129
|
case "\\cancel":
|
|
118
130
|
node.setAttribute("notation", "updiagonalstrike");
|
|
@@ -127,8 +139,23 @@ const mathmlBuilder = (group, options) => {
|
|
|
127
139
|
node.setAttribute("notation", "box");
|
|
128
140
|
break;
|
|
129
141
|
case "\\fcolorbox":
|
|
130
|
-
|
|
131
|
-
|
|
142
|
+
case "\\colorbox":
|
|
143
|
+
// <menclose> doesn't have a good notation option. So use <mpadded>
|
|
144
|
+
// instead. Set some attributes that come included with <menclose>.
|
|
145
|
+
fboxsep = options.fontMetrics().fboxsep *
|
|
146
|
+
options.fontMetrics().ptPerEm;
|
|
147
|
+
node.setAttribute("width", `+${2 * fboxsep}pt`);
|
|
148
|
+
node.setAttribute("height", `+${2 * fboxsep}pt`);
|
|
149
|
+
node.setAttribute("lspace", `${fboxsep}pt`); //
|
|
150
|
+
node.setAttribute("voffset", `${fboxsep}pt`);
|
|
151
|
+
if (group.label === "\\fcolorbox") {
|
|
152
|
+
const thk = Math.max(
|
|
153
|
+
options.fontMetrics().fboxrule, // default
|
|
154
|
+
options.minRuleThickness, // user override
|
|
155
|
+
);
|
|
156
|
+
node.setAttribute("style", "border: " + thk + "em solid " +
|
|
157
|
+
String(group.borderColor));
|
|
158
|
+
}
|
|
132
159
|
break;
|
|
133
160
|
case "\\xcancel":
|
|
134
161
|
node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
|
|
@@ -195,7 +222,7 @@ defineFunction({
|
|
|
195
222
|
names: ["\\fbox"],
|
|
196
223
|
props: {
|
|
197
224
|
numArgs: 1,
|
|
198
|
-
argTypes: ["
|
|
225
|
+
argTypes: ["hbox"],
|
|
199
226
|
allowedInText: true,
|
|
200
227
|
},
|
|
201
228
|
handler({parser}, args) {
|
package/src/functions/font.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import {binrelClass} from "./mclass";
|
|
5
5
|
import defineFunction from "../defineFunction";
|
|
6
|
+
import utils from "../utils";
|
|
6
7
|
|
|
7
8
|
import * as html from "../buildHTML";
|
|
8
9
|
import * as mml from "../buildMathML";
|
|
@@ -71,6 +72,7 @@ defineFunction({
|
|
|
71
72
|
},
|
|
72
73
|
handler: ({parser}, args) => {
|
|
73
74
|
const body = args[0];
|
|
75
|
+
const isCharacterBox = utils.isCharacterBox(body);
|
|
74
76
|
// amsbsy.sty's \boldsymbol uses \binrel spacing to inherit the
|
|
75
77
|
// argument's bin|rel|ord status
|
|
76
78
|
return {
|
|
@@ -85,6 +87,7 @@ defineFunction({
|
|
|
85
87
|
body,
|
|
86
88
|
},
|
|
87
89
|
],
|
|
90
|
+
isCharacterBox: isCharacterBox,
|
|
88
91
|
};
|
|
89
92
|
},
|
|
90
93
|
});
|
|
@@ -92,7 +95,7 @@ defineFunction({
|
|
|
92
95
|
// Old font changing functions
|
|
93
96
|
defineFunction({
|
|
94
97
|
type: "font",
|
|
95
|
-
names: ["\\rm", "\\sf", "\\tt", "\\bf", "\\it"],
|
|
98
|
+
names: ["\\rm", "\\sf", "\\tt", "\\bf", "\\it", "\\cal"],
|
|
96
99
|
props: {
|
|
97
100
|
numArgs: 0,
|
|
98
101
|
allowedInText: true,
|
package/src/functions/genfrac.js
CHANGED
|
@@ -4,29 +4,36 @@ import buildCommon from "../buildCommon";
|
|
|
4
4
|
import delimiter from "../delimiter";
|
|
5
5
|
import mathMLTree from "../mathMLTree";
|
|
6
6
|
import Style from "../Style";
|
|
7
|
-
import {assertNodeType
|
|
7
|
+
import {assertNodeType} from "../parseNode";
|
|
8
8
|
import {assert} from "../utils";
|
|
9
9
|
|
|
10
10
|
import * as html from "../buildHTML";
|
|
11
11
|
import * as mml from "../buildMathML";
|
|
12
12
|
import {calculateSize} from "../units";
|
|
13
13
|
|
|
14
|
-
const
|
|
15
|
-
// Fractions are handled in the TeXbook on pages 444-445, rules 15(a-e).
|
|
14
|
+
const adjustStyle = (size, originalStyle) => {
|
|
16
15
|
// Figure out what style this fraction should be in based on the
|
|
17
16
|
// function used
|
|
18
|
-
let style =
|
|
19
|
-
if (
|
|
20
|
-
style
|
|
21
|
-
|
|
17
|
+
let style = originalStyle;
|
|
18
|
+
if (size === "display") {
|
|
19
|
+
// Get display style as a default.
|
|
20
|
+
// If incoming style is sub/sup, use style.text() to get correct size.
|
|
21
|
+
style = style.id >= Style.SCRIPT.id ? style.text() : Style.DISPLAY;
|
|
22
|
+
} else if (size === "text" &&
|
|
22
23
|
style.size === Style.DISPLAY.size) {
|
|
23
24
|
// We're in a \tfrac but incoming style is displaystyle, so:
|
|
24
25
|
style = Style.TEXT;
|
|
25
|
-
} else if (
|
|
26
|
+
} else if (size === "script") {
|
|
26
27
|
style = Style.SCRIPT;
|
|
27
|
-
} else if (
|
|
28
|
+
} else if (size === "scriptscript") {
|
|
28
29
|
style = Style.SCRIPTSCRIPT;
|
|
29
30
|
}
|
|
31
|
+
return style;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const htmlBuilder = (group, options) => {
|
|
35
|
+
// Fractions are handled in the TeXbook on pages 444-445, rules 15(a-e).
|
|
36
|
+
const style = adjustStyle(group.size, options.style);
|
|
30
37
|
|
|
31
38
|
const nstyle = style.fracNum();
|
|
32
39
|
const dstyle = style.fracDen();
|
|
@@ -69,7 +76,7 @@ const htmlBuilder = (group, options) => {
|
|
|
69
76
|
let numShift;
|
|
70
77
|
let clearance;
|
|
71
78
|
let denomShift;
|
|
72
|
-
if (style.size === Style.DISPLAY.size) {
|
|
79
|
+
if (style.size === Style.DISPLAY.size || group.size === "display") {
|
|
73
80
|
numShift = options.fontMetrics().num1;
|
|
74
81
|
if (ruleWidth > 0) {
|
|
75
82
|
clearance = 3 * ruleSpacing;
|
|
@@ -176,7 +183,7 @@ const htmlBuilder = (group, options) => {
|
|
|
176
183
|
};
|
|
177
184
|
|
|
178
185
|
const mathmlBuilder = (group, options) => {
|
|
179
|
-
|
|
186
|
+
let node = new mathMLTree.MathNode(
|
|
180
187
|
"mfrac",
|
|
181
188
|
[
|
|
182
189
|
mml.buildGroup(group.numer, options),
|
|
@@ -190,12 +197,22 @@ const mathmlBuilder = (group, options) => {
|
|
|
190
197
|
node.setAttribute("linethickness", ruleWidth + "em");
|
|
191
198
|
}
|
|
192
199
|
|
|
200
|
+
const style = adjustStyle(group.size, options.style);
|
|
201
|
+
if (style.size !== options.style.size) {
|
|
202
|
+
node = new mathMLTree.MathNode("mstyle", [node]);
|
|
203
|
+
const isDisplay = (style.size === Style.DISPLAY.size) ? "true" : "false";
|
|
204
|
+
node.setAttribute("displaystyle", isDisplay);
|
|
205
|
+
node.setAttribute("scriptlevel", "0");
|
|
206
|
+
}
|
|
207
|
+
|
|
193
208
|
if (group.leftDelim != null || group.rightDelim != null) {
|
|
194
209
|
const withDelims = [];
|
|
195
210
|
|
|
196
211
|
if (group.leftDelim != null) {
|
|
197
212
|
const leftOp = new mathMLTree.MathNode(
|
|
198
|
-
"mo",
|
|
213
|
+
"mo",
|
|
214
|
+
[new mathMLTree.TextNode(group.leftDelim.replace("\\", ""))]
|
|
215
|
+
);
|
|
199
216
|
|
|
200
217
|
leftOp.setAttribute("fence", "true");
|
|
201
218
|
|
|
@@ -206,7 +223,9 @@ const mathmlBuilder = (group, options) => {
|
|
|
206
223
|
|
|
207
224
|
if (group.rightDelim != null) {
|
|
208
225
|
const rightOp = new mathMLTree.MathNode(
|
|
209
|
-
"mo",
|
|
226
|
+
"mo",
|
|
227
|
+
[new mathMLTree.TextNode(group.rightDelim.replace("\\", ""))]
|
|
228
|
+
);
|
|
210
229
|
|
|
211
230
|
rightOp.setAttribute("fence", "true");
|
|
212
231
|
|
|
@@ -363,17 +382,10 @@ defineFunction({
|
|
|
363
382
|
const denom = args[5];
|
|
364
383
|
|
|
365
384
|
// Look into the parse nodes to get the desired delimiters.
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
const leftDelim = leftNode ? delimFromValue(leftNode.text) : null;
|
|
371
|
-
|
|
372
|
-
let rightNode = checkNodeType(args[1], "atom");
|
|
373
|
-
if (rightNode) {
|
|
374
|
-
rightNode = assertAtomFamily(args[1], "close");
|
|
375
|
-
}
|
|
376
|
-
const rightDelim = rightNode ? delimFromValue(rightNode.text) : null;
|
|
385
|
+
const leftDelim = args[0].type === "atom" && args[0].family === "open"
|
|
386
|
+
? delimFromValue(args[0].text) : null;
|
|
387
|
+
const rightDelim = args[1].type === "atom" && args[1].family === "close"
|
|
388
|
+
? delimFromValue(args[1].text) : null;
|
|
377
389
|
|
|
378
390
|
const barNode = assertNodeType(args[2], "size");
|
|
379
391
|
let hasBarLine;
|
|
@@ -390,14 +402,14 @@ defineFunction({
|
|
|
390
402
|
|
|
391
403
|
// Find out if we want displaystyle, textstyle, etc.
|
|
392
404
|
let size = "auto";
|
|
393
|
-
let styl =
|
|
394
|
-
if (styl) {
|
|
405
|
+
let styl = args[3];
|
|
406
|
+
if (styl.type === "ordgroup") {
|
|
395
407
|
if (styl.body.length > 0) {
|
|
396
408
|
const textOrd = assertNodeType(styl.body[0], "textord");
|
|
397
409
|
size = stylArray[Number(textOrd.text)];
|
|
398
410
|
}
|
|
399
411
|
} else {
|
|
400
|
-
styl = assertNodeType(
|
|
412
|
+
styl = assertNodeType(styl, "textord");
|
|
401
413
|
size = stylArray[Number(styl.text)];
|
|
402
414
|
}
|
|
403
415
|
|
|
@@ -4,7 +4,7 @@ import buildCommon from "../buildCommon";
|
|
|
4
4
|
import mathMLTree from "../mathMLTree";
|
|
5
5
|
import stretchy from "../stretchy";
|
|
6
6
|
import Style from "../Style";
|
|
7
|
-
import {assertNodeType
|
|
7
|
+
import {assertNodeType} from "../parseNode";
|
|
8
8
|
|
|
9
9
|
import * as html from "../buildHTML";
|
|
10
10
|
import * as mml from "../buildMathML";
|
|
@@ -20,15 +20,14 @@ export const htmlBuilder: HtmlBuilderSupSub<"horizBrace"> = (grp, options) => {
|
|
|
20
20
|
// Pull out the `ParseNode<"horizBrace">` if `grp` is a "supsub" node.
|
|
21
21
|
let supSubGroup;
|
|
22
22
|
let group: ParseNode<"horizBrace">;
|
|
23
|
-
|
|
24
|
-
if (supSub) {
|
|
23
|
+
if (grp.type === "supsub") {
|
|
25
24
|
// Ref: LaTeX source2e: }}}}\limits}
|
|
26
25
|
// i.e. LaTeX treats the brace similar to an op and passes it
|
|
27
26
|
// with \limits, so we need to assign supsub style.
|
|
28
|
-
supSubGroup =
|
|
29
|
-
html.buildGroup(
|
|
30
|
-
html.buildGroup(
|
|
31
|
-
group = assertNodeType(
|
|
27
|
+
supSubGroup = grp.sup ?
|
|
28
|
+
html.buildGroup(grp.sup, options.havingStyle(style.sup()), options) :
|
|
29
|
+
html.buildGroup(grp.sub, options.havingStyle(style.sub()), options);
|
|
30
|
+
group = assertNodeType(grp.base, "horizBrace");
|
|
32
31
|
} else {
|
|
33
32
|
group = assertNodeType(grp, "horizBrace");
|
|
34
33
|
}
|
package/src/functions/href.js
CHANGED
|
@@ -18,6 +18,14 @@ defineFunction({
|
|
|
18
18
|
handler: ({parser}, args) => {
|
|
19
19
|
const body = args[1];
|
|
20
20
|
const href = assertNodeType(args[0], "url").url;
|
|
21
|
+
|
|
22
|
+
if (!parser.settings.isTrusted({
|
|
23
|
+
command: "\\href",
|
|
24
|
+
url: href,
|
|
25
|
+
})) {
|
|
26
|
+
return parser.formatUnsupportedCmd("\\href");
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
return {
|
|
22
30
|
type: "href",
|
|
23
31
|
mode: parser.mode,
|
|
@@ -49,6 +57,14 @@ defineFunction({
|
|
|
49
57
|
},
|
|
50
58
|
handler: ({parser}, args) => {
|
|
51
59
|
const href = assertNodeType(args[0], "url").url;
|
|
60
|
+
|
|
61
|
+
if (!parser.settings.isTrusted({
|
|
62
|
+
command: "\\url",
|
|
63
|
+
url: href,
|
|
64
|
+
})) {
|
|
65
|
+
return parser.formatUnsupportedCmd("\\url");
|
|
66
|
+
}
|
|
67
|
+
|
|
52
68
|
const chars = [];
|
|
53
69
|
for (let i = 0; i < href.length; i++) {
|
|
54
70
|
let c = href[i];
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import defineFunction, {ordargument} from "../defineFunction";
|
|
3
|
+
import buildCommon from "../buildCommon";
|
|
4
|
+
import {assertNodeType} from "../parseNode";
|
|
5
|
+
import ParseError from "../ParseError";
|
|
6
|
+
|
|
7
|
+
import * as html from "../buildHTML";
|
|
8
|
+
import * as mml from "../buildMathML";
|
|
9
|
+
|
|
10
|
+
defineFunction({
|
|
11
|
+
type: "html",
|
|
12
|
+
names: ["\\htmlClass", "\\htmlId", "\\htmlStyle", "\\htmlData"],
|
|
13
|
+
props: {
|
|
14
|
+
numArgs: 2,
|
|
15
|
+
argTypes: ["raw", "original"],
|
|
16
|
+
allowedInText: true,
|
|
17
|
+
},
|
|
18
|
+
handler: ({parser, funcName, token}, args) => {
|
|
19
|
+
const value = assertNodeType(args[0], "raw").string;
|
|
20
|
+
const body = args[1];
|
|
21
|
+
|
|
22
|
+
if (parser.settings.strict) {
|
|
23
|
+
parser.settings.reportNonstrict("htmlExtension",
|
|
24
|
+
"HTML extension is disabled on strict mode");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let trustContext;
|
|
28
|
+
const attributes = {};
|
|
29
|
+
|
|
30
|
+
switch (funcName) {
|
|
31
|
+
case "\\htmlClass":
|
|
32
|
+
attributes.class = value;
|
|
33
|
+
trustContext = {
|
|
34
|
+
command: "\\htmlClass",
|
|
35
|
+
class: value,
|
|
36
|
+
};
|
|
37
|
+
break;
|
|
38
|
+
case "\\htmlId":
|
|
39
|
+
attributes.id = value;
|
|
40
|
+
trustContext = {
|
|
41
|
+
command: "\\htmlId",
|
|
42
|
+
id: value,
|
|
43
|
+
};
|
|
44
|
+
break;
|
|
45
|
+
case "\\htmlStyle":
|
|
46
|
+
attributes.style = value;
|
|
47
|
+
trustContext = {
|
|
48
|
+
command: "\\htmlStyle",
|
|
49
|
+
style: value,
|
|
50
|
+
};
|
|
51
|
+
break;
|
|
52
|
+
case "\\htmlData": {
|
|
53
|
+
const data = value.split(",");
|
|
54
|
+
for (let i = 0; i < data.length; i++) {
|
|
55
|
+
const keyVal = data[i].split("=");
|
|
56
|
+
if (keyVal.length !== 2) {
|
|
57
|
+
throw new ParseError(
|
|
58
|
+
"Error parsing key-value for \\htmlData");
|
|
59
|
+
}
|
|
60
|
+
attributes["data-" + keyVal[0].trim()] = keyVal[1].trim();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
trustContext = {
|
|
64
|
+
command: "\\htmlData",
|
|
65
|
+
attributes,
|
|
66
|
+
};
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
default:
|
|
70
|
+
throw new Error("Unrecognized html command");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!parser.settings.isTrusted(trustContext)) {
|
|
74
|
+
return parser.formatUnsupportedCmd(funcName);
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
type: "html",
|
|
78
|
+
mode: parser.mode,
|
|
79
|
+
attributes,
|
|
80
|
+
body: ordargument(body),
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
htmlBuilder: (group, options) => {
|
|
84
|
+
const elements = html.buildExpression(group.body, options, false);
|
|
85
|
+
|
|
86
|
+
const classes = ["enclosing"];
|
|
87
|
+
if (group.attributes.class) {
|
|
88
|
+
classes.push(...group.attributes.class.trim().split(/\s+/));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const span = buildCommon.makeSpan(classes, elements, options);
|
|
92
|
+
for (const attr in group.attributes) {
|
|
93
|
+
if (attr !== "class" && group.attributes.hasOwnProperty(attr)) {
|
|
94
|
+
span.setAttribute(attr, group.attributes[attr]);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return span;
|
|
98
|
+
},
|
|
99
|
+
mathmlBuilder: (group, options) => {
|
|
100
|
+
return mml.buildExpressionRow(group.body, options);
|
|
101
|
+
},
|
|
102
|
+
});
|