katex 0.11.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 +44 -0
- package/LICENSE +1 -1
- package/README.md +5 -5
- 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 +1 -1
- package/contrib/render-a11y-string/render-a11y-string.js +10 -0
- package/dist/README.md +5 -5
- 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 +12 -0
- package/dist/contrib/render-a11y-string.min.js +1 -1
- package/dist/contrib/render-a11y-string.mjs +12 -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 +25 -2
- package/dist/katex.js +1140 -1257
- package/dist/katex.min.css +1 -1
- package/dist/katex.min.js +1 -1
- package/dist/katex.mjs +1119 -1229
- package/package.json +9 -9
- package/src/MacroExpander.js +39 -10
- package/src/Parser.js +28 -24
- package/src/Settings.js +19 -0
- package/src/Token.js +2 -0
- package/src/buildCommon.js +16 -82
- package/src/buildHTML.js +29 -30
- package/src/buildMathML.js +5 -1
- package/src/buildTree.js +3 -2
- package/src/defineFunction.js +1 -4
- package/src/delimiter.js +14 -3
- package/src/environments/array.js +11 -9
- package/src/functions/accent.js +6 -7
- package/src/functions/accentunder.js +2 -2
- package/src/functions/def.js +184 -0
- package/src/functions/delimsizing.js +5 -4
- package/src/functions/font.js +1 -1
- package/src/functions/genfrac.js +8 -15
- package/src/functions/horizBrace.js +6 -7
- package/src/functions/html.js +102 -0
- package/src/functions/lap.js +4 -7
- package/src/functions/op.js +5 -6
- package/src/functions/operatorname.js +5 -6
- package/src/functions/supsub.js +3 -5
- package/src/functions/utils/assembleSupSub.js +0 -2
- package/src/functions.js +2 -0
- package/src/katex.less +29 -1
- package/src/macros.js +97 -56
- package/src/parseNode.js +14 -56
- package/src/svgGeometry.js +4 -0
- package/src/symbols.js +36 -53
- package/src/unicodeAccents.js +3 -1
- package/src/unicodeSymbols.js +30 -321
- package/src/wide-character.js +2 -2
- package/src/unicodeMake.js +0 -70
package/src/delimiter.js
CHANGED
|
@@ -375,9 +375,20 @@ const makeStackedDelim = function(
|
|
|
375
375
|
|
|
376
376
|
// To cover the gap create by the overlaps, insert one more repeat element,
|
|
377
377
|
// at a position that juts 0.005 above the bottom of the top element.
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
378
|
+
if ((repeat === "\u239c" || repeat === "\u239f") && repeatCount === 0) {
|
|
379
|
+
// Parentheses need a short repeat element in order to avoid an overrun.
|
|
380
|
+
// We'll make a 0.3em tall element from a SVG.
|
|
381
|
+
const overlap = buildCommon.svgData.leftParenInner[2] / 2;
|
|
382
|
+
inners.push({type: "kern", size: -overlap});
|
|
383
|
+
const pathName = repeat === "\u239c" ? "leftParenInner" : "rightParenInner";
|
|
384
|
+
const innerSpan = buildCommon.staticSvg(pathName, options);
|
|
385
|
+
inners.push({type: "elem", elem: innerSpan});
|
|
386
|
+
inners.push({type: "kern", size: -overlap});
|
|
387
|
+
} else {
|
|
388
|
+
inners.push({type: "kern", size: shiftOfExtraElement});
|
|
389
|
+
inners.push(makeInner(repeat, font, mode));
|
|
390
|
+
inners.push(lap);
|
|
391
|
+
}
|
|
381
392
|
|
|
382
393
|
// Add the top symbol
|
|
383
394
|
inners.push(makeInner(top, font, mode));
|
|
@@ -6,7 +6,7 @@ import defineFunction from "../defineFunction";
|
|
|
6
6
|
import mathMLTree from "../mathMLTree";
|
|
7
7
|
import ParseError from "../ParseError";
|
|
8
8
|
import {assertNodeType, assertSymbolNodeType} from "../parseNode";
|
|
9
|
-
import {
|
|
9
|
+
import {checkSymbolNodeType} from "../parseNode";
|
|
10
10
|
import {calculateSize} from "../units";
|
|
11
11
|
import utils from "../utils";
|
|
12
12
|
|
|
@@ -435,7 +435,7 @@ const mathmlBuilder: MathMLBuilder<"array"> = function(group, options) {
|
|
|
435
435
|
let menclose = "";
|
|
436
436
|
let align = "";
|
|
437
437
|
|
|
438
|
-
if (group.cols) {
|
|
438
|
+
if (group.cols && group.cols.length > 0) {
|
|
439
439
|
// Find column alignment, column spacing, and vertical lines.
|
|
440
440
|
const cols = group.cols;
|
|
441
441
|
let columnLines = "";
|
|
@@ -547,11 +547,10 @@ const alignedHandler = function(context, args) {
|
|
|
547
547
|
mode: context.mode,
|
|
548
548
|
body: [],
|
|
549
549
|
};
|
|
550
|
-
|
|
551
|
-
if (ordgroup) {
|
|
550
|
+
if (args[0] && args[0].type === "ordgroup") {
|
|
552
551
|
let arg0 = "";
|
|
553
|
-
for (let i = 0; i <
|
|
554
|
-
const textord = assertNodeType(
|
|
552
|
+
for (let i = 0; i < args[0].body.length; i++) {
|
|
553
|
+
const textord = assertNodeType(args[0].body[i], "textord");
|
|
555
554
|
arg0 += textord.text;
|
|
556
555
|
}
|
|
557
556
|
numMaths = Number(arg0);
|
|
@@ -738,7 +737,7 @@ defineEnvironment({
|
|
|
738
737
|
arraystretch: 0.5,
|
|
739
738
|
};
|
|
740
739
|
res = parseArray(context.parser, res, "script");
|
|
741
|
-
if (res.body[0].length > 1) {
|
|
740
|
+
if (res.body.length > 0 && res.body[0].length > 1) {
|
|
742
741
|
throw new ParseError("{subarray} can contain only one column");
|
|
743
742
|
}
|
|
744
743
|
return res;
|
|
@@ -752,11 +751,14 @@ defineEnvironment({
|
|
|
752
751
|
// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right.
|
|
753
752
|
// {dcases} is a {cases} environment where cells are set in \displaystyle,
|
|
754
753
|
// as defined in mathtools.sty.
|
|
754
|
+
// {rcases} is another mathtools environment. It's brace is on the right side.
|
|
755
755
|
defineEnvironment({
|
|
756
756
|
type: "array",
|
|
757
757
|
names: [
|
|
758
758
|
"cases",
|
|
759
759
|
"dcases",
|
|
760
|
+
"rcases",
|
|
761
|
+
"drcases",
|
|
760
762
|
],
|
|
761
763
|
props: {
|
|
762
764
|
numArgs: 0,
|
|
@@ -786,8 +788,8 @@ defineEnvironment({
|
|
|
786
788
|
type: "leftright",
|
|
787
789
|
mode: context.mode,
|
|
788
790
|
body: [res],
|
|
789
|
-
left: "\\{",
|
|
790
|
-
right: ".",
|
|
791
|
+
left: context.envName.indexOf("r") > -1 ? "." : "\\{",
|
|
792
|
+
right: context.envName.indexOf("r") > -1 ? "\\}" : ".",
|
|
791
793
|
rightColor: undefined,
|
|
792
794
|
};
|
|
793
795
|
},
|
package/src/functions/accent.js
CHANGED
|
@@ -4,7 +4,7 @@ import buildCommon from "../buildCommon";
|
|
|
4
4
|
import mathMLTree from "../mathMLTree";
|
|
5
5
|
import utils from "../utils";
|
|
6
6
|
import stretchy from "../stretchy";
|
|
7
|
-
import {assertNodeType
|
|
7
|
+
import {assertNodeType} from "../parseNode";
|
|
8
8
|
import {assertSpan, assertSymbolDomNode} from "../domTree";
|
|
9
9
|
|
|
10
10
|
import * as html from "../buildHTML";
|
|
@@ -20,9 +20,8 @@ export const htmlBuilder: HtmlBuilderSupSub<"accent"> = (grp, options) => {
|
|
|
20
20
|
let base: AnyParseNode;
|
|
21
21
|
let group: ParseNode<"accent">;
|
|
22
22
|
|
|
23
|
-
const supSub: ?ParseNode<"supsub"> = checkNodeType(grp, "supsub");
|
|
24
23
|
let supSubGroup;
|
|
25
|
-
if (
|
|
24
|
+
if (grp && grp.type === "supsub") {
|
|
26
25
|
// If our base is a character box, and we have superscripts and
|
|
27
26
|
// subscripts, the supsub will defer to us. In particular, we want
|
|
28
27
|
// to attach the superscripts and subscripts to the inner body (so
|
|
@@ -32,18 +31,18 @@ export const htmlBuilder: HtmlBuilderSupSub<"accent"> = (grp, options) => {
|
|
|
32
31
|
// rendering that, while keeping track of where the accent is.
|
|
33
32
|
|
|
34
33
|
// The real accent group is the base of the supsub group
|
|
35
|
-
group = assertNodeType(
|
|
34
|
+
group = assertNodeType(grp.base, "accent");
|
|
36
35
|
// The character box is the base of the accent group
|
|
37
36
|
base = group.base;
|
|
38
37
|
// Stick the character box into the base of the supsub group
|
|
39
|
-
|
|
38
|
+
grp.base = base;
|
|
40
39
|
|
|
41
40
|
// Rerender the supsub group with its new base, and store that
|
|
42
41
|
// result.
|
|
43
|
-
supSubGroup = assertSpan(html.buildGroup(
|
|
42
|
+
supSubGroup = assertSpan(html.buildGroup(grp, options));
|
|
44
43
|
|
|
45
44
|
// reset original base
|
|
46
|
-
|
|
45
|
+
grp.base = group;
|
|
47
46
|
} else {
|
|
48
47
|
group = assertNodeType(grp, "accent");
|
|
49
48
|
base = group.base;
|
|
@@ -37,8 +37,8 @@ defineFunction({
|
|
|
37
37
|
|
|
38
38
|
// Generate the vlist, with the appropriate kerns
|
|
39
39
|
const vlist = buildCommon.makeVList({
|
|
40
|
-
positionType: "
|
|
41
|
-
positionData:
|
|
40
|
+
positionType: "top",
|
|
41
|
+
positionData: innerGroup.height,
|
|
42
42
|
children: [
|
|
43
43
|
{type: "elem", elem: accentBody, wrapperClasses: ["svg-align"]},
|
|
44
44
|
{type: "kern", size: kern},
|
|
@@ -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
|
|
package/src/functions/font.js
CHANGED
package/src/functions/genfrac.js
CHANGED
|
@@ -4,7 +4,7 @@ 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";
|
|
@@ -382,17 +382,10 @@ defineFunction({
|
|
|
382
382
|
const denom = args[5];
|
|
383
383
|
|
|
384
384
|
// Look into the parse nodes to get the desired delimiters.
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
const leftDelim = leftNode ? delimFromValue(leftNode.text) : null;
|
|
390
|
-
|
|
391
|
-
let rightNode = checkNodeType(args[1], "atom");
|
|
392
|
-
if (rightNode) {
|
|
393
|
-
rightNode = assertAtomFamily(args[1], "close");
|
|
394
|
-
}
|
|
395
|
-
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;
|
|
396
389
|
|
|
397
390
|
const barNode = assertNodeType(args[2], "size");
|
|
398
391
|
let hasBarLine;
|
|
@@ -409,14 +402,14 @@ defineFunction({
|
|
|
409
402
|
|
|
410
403
|
// Find out if we want displaystyle, textstyle, etc.
|
|
411
404
|
let size = "auto";
|
|
412
|
-
let styl =
|
|
413
|
-
if (styl) {
|
|
405
|
+
let styl = args[3];
|
|
406
|
+
if (styl.type === "ordgroup") {
|
|
414
407
|
if (styl.body.length > 0) {
|
|
415
408
|
const textOrd = assertNodeType(styl.body[0], "textord");
|
|
416
409
|
size = stylArray[Number(textOrd.text)];
|
|
417
410
|
}
|
|
418
411
|
} else {
|
|
419
|
-
styl = assertNodeType(
|
|
412
|
+
styl = assertNodeType(styl, "textord");
|
|
420
413
|
size = stylArray[Number(styl.text)];
|
|
421
414
|
}
|
|
422
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
|
}
|
|
@@ -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
|
+
});
|
package/src/functions/lap.js
CHANGED
|
@@ -44,19 +44,16 @@ defineFunction({
|
|
|
44
44
|
// two items involved in the lap.
|
|
45
45
|
// Next, use a strut to set the height of the HTML bounding box.
|
|
46
46
|
// Otherwise, a tall argument may be misplaced.
|
|
47
|
+
// This code resolved issue #1153
|
|
47
48
|
const strut = buildCommon.makeSpan(["strut"]);
|
|
48
49
|
strut.style.height = (node.height + node.depth) + "em";
|
|
49
50
|
strut.style.verticalAlign = -node.depth + "em";
|
|
50
51
|
node.children.unshift(strut);
|
|
51
52
|
|
|
52
53
|
// Next, prevent vertical misplacement when next to something tall.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}, options);
|
|
57
|
-
|
|
58
|
-
// Get the horizontal spacing correct relative to adjacent items.
|
|
59
|
-
return buildCommon.makeSpan(["mord"], [node], options);
|
|
54
|
+
// This code resolves issue #1234
|
|
55
|
+
node = buildCommon.makeSpan(["thinbox"], [node], options);
|
|
56
|
+
return buildCommon.makeSpan(["mord", "vbox"], [node], options);
|
|
60
57
|
},
|
|
61
58
|
mathmlBuilder: (group, options) => {
|
|
62
59
|
// mathllap, mathrlap, mathclap
|
package/src/functions/op.js
CHANGED
|
@@ -7,7 +7,7 @@ import * as mathMLTree from "../mathMLTree";
|
|
|
7
7
|
import utils from "../utils";
|
|
8
8
|
import Style from "../Style";
|
|
9
9
|
import {assembleSupSub} from "./utils/assembleSupSub";
|
|
10
|
-
import {assertNodeType
|
|
10
|
+
import {assertNodeType} from "../parseNode";
|
|
11
11
|
|
|
12
12
|
import * as html from "../buildHTML";
|
|
13
13
|
import * as mml from "../buildMathML";
|
|
@@ -28,14 +28,13 @@ export const htmlBuilder: HtmlBuilderSupSub<"op"> = (grp, options) => {
|
|
|
28
28
|
let subGroup;
|
|
29
29
|
let hasLimits = false;
|
|
30
30
|
let group: ParseNode<"op">;
|
|
31
|
-
|
|
32
|
-
if (supSub) {
|
|
31
|
+
if (grp.type === "supsub") {
|
|
33
32
|
// If we have limits, supsub will pass us its group to handle. Pull
|
|
34
33
|
// out the superscript and subscript and set the group to the op in
|
|
35
34
|
// its base.
|
|
36
|
-
supGroup =
|
|
37
|
-
subGroup =
|
|
38
|
-
group = assertNodeType(
|
|
35
|
+
supGroup = grp.sup;
|
|
36
|
+
subGroup = grp.sub;
|
|
37
|
+
group = assertNodeType(grp.base, "op");
|
|
39
38
|
hasLimits = true;
|
|
40
39
|
} else {
|
|
41
40
|
group = assertNodeType(grp, "op");
|
|
@@ -4,7 +4,7 @@ import buildCommon from "../buildCommon";
|
|
|
4
4
|
import mathMLTree from "../mathMLTree";
|
|
5
5
|
import {SymbolNode} from "../domTree";
|
|
6
6
|
import {assembleSupSub} from "./utils/assembleSupSub";
|
|
7
|
-
import {assertNodeType
|
|
7
|
+
import {assertNodeType} from "../parseNode";
|
|
8
8
|
|
|
9
9
|
import * as html from "../buildHTML";
|
|
10
10
|
import * as mml from "../buildMathML";
|
|
@@ -21,14 +21,13 @@ export const htmlBuilder: HtmlBuilderSupSub<"operatorname"> = (grp, options) =>
|
|
|
21
21
|
let subGroup;
|
|
22
22
|
let hasLimits = false;
|
|
23
23
|
let group: ParseNode<"operatorname">;
|
|
24
|
-
|
|
25
|
-
if (supSub) {
|
|
24
|
+
if (grp.type === "supsub") {
|
|
26
25
|
// If we have limits, supsub will pass us its group to handle. Pull
|
|
27
26
|
// out the superscript and subscript and set the group to the op in
|
|
28
27
|
// its base.
|
|
29
|
-
supGroup =
|
|
30
|
-
subGroup =
|
|
31
|
-
group = assertNodeType(
|
|
28
|
+
supGroup = grp.sup;
|
|
29
|
+
subGroup = grp.sub;
|
|
30
|
+
group = assertNodeType(grp.base, "operatorname");
|
|
32
31
|
hasLimits = true;
|
|
33
32
|
} else {
|
|
34
33
|
group = assertNodeType(grp, "operatorname");
|
package/src/functions/supsub.js
CHANGED
|
@@ -5,7 +5,6 @@ import {SymbolNode} from "../domTree";
|
|
|
5
5
|
import mathMLTree from "../mathMLTree";
|
|
6
6
|
import utils from "../utils";
|
|
7
7
|
import Style from "../Style";
|
|
8
|
-
import {checkNodeType} from "../parseNode";
|
|
9
8
|
|
|
10
9
|
import * as html from "../buildHTML";
|
|
11
10
|
import * as mml from "../buildMathML";
|
|
@@ -197,12 +196,11 @@ defineFunctionBuilders({
|
|
|
197
196
|
let isOver;
|
|
198
197
|
let isSup;
|
|
199
198
|
|
|
200
|
-
|
|
201
|
-
if (horizBrace) {
|
|
199
|
+
if (group.base && group.base.type === "horizBrace") {
|
|
202
200
|
isSup = !!group.sup;
|
|
203
|
-
if (isSup ===
|
|
201
|
+
if (isSup === group.base.isOver) {
|
|
204
202
|
isBrace = true;
|
|
205
|
-
isOver =
|
|
203
|
+
isOver = group.base.isOver;
|
|
206
204
|
}
|
|
207
205
|
}
|
|
208
206
|
|
|
@@ -17,8 +17,6 @@ export const assembleSupSub = (
|
|
|
17
17
|
slant: number,
|
|
18
18
|
baseShift: number,
|
|
19
19
|
): DomSpan => {
|
|
20
|
-
// IE 8 clips \int if it is in a display: inline-block. We wrap it
|
|
21
|
-
// in a new span so it is an inline, and works.
|
|
22
20
|
base = buildCommon.makeSpan([], [base]);
|
|
23
21
|
let sub;
|
|
24
22
|
let sup;
|