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,153 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import defineFunction from "../defineFunction";
|
|
3
|
+
import type {Measurement} from "../units";
|
|
4
|
+
import {calculateSize, validUnit} from "../units";
|
|
5
|
+
import ParseError from "../ParseError";
|
|
6
|
+
import {Img} from "../domTree";
|
|
7
|
+
import mathMLTree from "../mathMLTree";
|
|
8
|
+
import {assertNodeType} from "../parseNode";
|
|
9
|
+
import type {CssStyle} from "../domTree";
|
|
10
|
+
|
|
11
|
+
const sizeData = function(str: string): Measurement {
|
|
12
|
+
if (/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(str)) {
|
|
13
|
+
// str is a number with no unit specified.
|
|
14
|
+
// default unit is bp, per graphix package.
|
|
15
|
+
return {number: +str, unit: "bp"};
|
|
16
|
+
} else {
|
|
17
|
+
const match = (/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/).exec(str);
|
|
18
|
+
if (!match) {
|
|
19
|
+
throw new ParseError("Invalid size: '" + str
|
|
20
|
+
+ "' in \\includegraphics");
|
|
21
|
+
}
|
|
22
|
+
const data = {
|
|
23
|
+
number: +(match[1] + match[2]), // sign + magnitude, cast to number
|
|
24
|
+
unit: match[3],
|
|
25
|
+
};
|
|
26
|
+
if (!validUnit(data)) {
|
|
27
|
+
throw new ParseError("Invalid unit: '" + data.unit
|
|
28
|
+
+ "' in \\includegraphics.");
|
|
29
|
+
}
|
|
30
|
+
return data;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
defineFunction({
|
|
35
|
+
type: "includegraphics",
|
|
36
|
+
names: ["\\includegraphics"],
|
|
37
|
+
props: {
|
|
38
|
+
numArgs: 1,
|
|
39
|
+
numOptionalArgs: 1,
|
|
40
|
+
argTypes: ["raw", "url"],
|
|
41
|
+
allowedInText: false,
|
|
42
|
+
},
|
|
43
|
+
handler: ({parser}, args, optArgs) => {
|
|
44
|
+
let width = {number: 0, unit: "em"};
|
|
45
|
+
let height = {number: 0.9, unit: "em"}; // sorta character sized.
|
|
46
|
+
let totalheight = {number: 0, unit: "em"};
|
|
47
|
+
let alt = "";
|
|
48
|
+
|
|
49
|
+
if (optArgs[0]) {
|
|
50
|
+
const attributeStr = assertNodeType(optArgs[0], "raw").string;
|
|
51
|
+
|
|
52
|
+
// Parser.js does not parse key/value pairs. We get a string.
|
|
53
|
+
const attributes = attributeStr.split(",");
|
|
54
|
+
for (let i = 0; i < attributes.length; i++) {
|
|
55
|
+
const keyVal = attributes[i].split("=");
|
|
56
|
+
if (keyVal.length === 2) {
|
|
57
|
+
const str = keyVal[1].trim();
|
|
58
|
+
switch (keyVal[0].trim()) {
|
|
59
|
+
case "alt":
|
|
60
|
+
alt = str;
|
|
61
|
+
break;
|
|
62
|
+
case "width":
|
|
63
|
+
width = sizeData(str);
|
|
64
|
+
break;
|
|
65
|
+
case "height":
|
|
66
|
+
height = sizeData(str);
|
|
67
|
+
break;
|
|
68
|
+
case "totalheight":
|
|
69
|
+
totalheight = sizeData(str);
|
|
70
|
+
break;
|
|
71
|
+
default:
|
|
72
|
+
throw new ParseError("Invalid key: '" + keyVal[0] +
|
|
73
|
+
"' in \\includegraphics.");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const src = assertNodeType(args[0], "url").url;
|
|
80
|
+
|
|
81
|
+
if (alt === "") {
|
|
82
|
+
// No alt given. Use the file name. Strip away the path.
|
|
83
|
+
alt = src;
|
|
84
|
+
alt = alt.replace(/^.*[\\/]/, '');
|
|
85
|
+
alt = alt.substring(0, alt.lastIndexOf('.'));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!parser.settings.isTrusted({
|
|
89
|
+
command: "\\includegraphics",
|
|
90
|
+
url: src,
|
|
91
|
+
})) {
|
|
92
|
+
return parser.formatUnsupportedCmd("\\includegraphics");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
type: "includegraphics",
|
|
97
|
+
mode: parser.mode,
|
|
98
|
+
alt: alt,
|
|
99
|
+
width: width,
|
|
100
|
+
height: height,
|
|
101
|
+
totalheight: totalheight,
|
|
102
|
+
src: src,
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
htmlBuilder: (group, options) => {
|
|
106
|
+
const height = calculateSize(group.height, options);
|
|
107
|
+
let depth = 0;
|
|
108
|
+
|
|
109
|
+
if (group.totalheight.number > 0) {
|
|
110
|
+
depth = calculateSize(group.totalheight, options) - height;
|
|
111
|
+
depth = Number(depth.toFixed(2));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let width = 0;
|
|
115
|
+
if (group.width.number > 0) {
|
|
116
|
+
width = calculateSize(group.width, options);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const style: CssStyle = {height: height + depth + "em"};
|
|
120
|
+
if (width > 0) {
|
|
121
|
+
style.width = width + "em";
|
|
122
|
+
}
|
|
123
|
+
if (depth > 0) {
|
|
124
|
+
style.verticalAlign = -depth + "em";
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const node = new Img(group.src, group.alt, style);
|
|
128
|
+
node.height = height;
|
|
129
|
+
node.depth = depth;
|
|
130
|
+
|
|
131
|
+
return node;
|
|
132
|
+
},
|
|
133
|
+
mathmlBuilder: (group, options) => {
|
|
134
|
+
const node = new mathMLTree.MathNode("mglyph", []);
|
|
135
|
+
node.setAttribute("alt", group.alt);
|
|
136
|
+
|
|
137
|
+
const height = calculateSize(group.height, options);
|
|
138
|
+
let depth = 0;
|
|
139
|
+
if (group.totalheight.number > 0) {
|
|
140
|
+
depth = calculateSize(group.totalheight, options) - height;
|
|
141
|
+
depth = depth.toFixed(2);
|
|
142
|
+
node.setAttribute("valign", "-" + depth + "em");
|
|
143
|
+
}
|
|
144
|
+
node.setAttribute("height", height + depth + "em");
|
|
145
|
+
|
|
146
|
+
if (group.width.number > 0) {
|
|
147
|
+
const width = calculateSize(group.width, options);
|
|
148
|
+
node.setAttribute("width", width + "em");
|
|
149
|
+
}
|
|
150
|
+
node.setAttribute("src", group.src);
|
|
151
|
+
return node;
|
|
152
|
+
},
|
|
153
|
+
});
|
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/math.js
CHANGED
|
@@ -10,18 +10,14 @@ defineFunction({
|
|
|
10
10
|
numArgs: 0,
|
|
11
11
|
allowedInText: true,
|
|
12
12
|
allowedInMath: false,
|
|
13
|
-
consumeMode: "math",
|
|
14
13
|
},
|
|
15
14
|
handler({funcName, parser}, args) {
|
|
16
15
|
const outerMode = parser.mode;
|
|
17
16
|
parser.switchMode("math");
|
|
18
17
|
const close = (funcName === "\\(" ? "\\)" : "$");
|
|
19
18
|
const body = parser.parseExpression(false, close);
|
|
20
|
-
|
|
21
|
-
// switching modes back. So don't consume within expect.
|
|
22
|
-
parser.expect(close, false);
|
|
19
|
+
parser.expect(close);
|
|
23
20
|
parser.switchMode(outerMode);
|
|
24
|
-
parser.consume();
|
|
25
21
|
return {
|
|
26
22
|
type: "styling",
|
|
27
23
|
mode: parser.mode,
|
package/src/functions/mclass.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import defineFunction, {ordargument} from "../defineFunction";
|
|
3
3
|
import buildCommon from "../buildCommon";
|
|
4
4
|
import mathMLTree from "../mathMLTree";
|
|
5
|
+
import utils from "../utils";
|
|
5
6
|
import type {AnyParseNode} from "../parseNode";
|
|
6
7
|
|
|
7
8
|
import * as html from "../buildHTML";
|
|
@@ -17,8 +18,42 @@ function htmlBuilder(group: ParseNode<"mclass">, options) {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
function mathmlBuilder(group: ParseNode<"mclass">, options) {
|
|
21
|
+
let node: mathMLTree.MathNode;
|
|
20
22
|
const inner = mml.buildExpression(group.body, options);
|
|
21
|
-
|
|
23
|
+
|
|
24
|
+
if (group.mclass === "minner") {
|
|
25
|
+
return mathMLTree.newDocumentFragment(inner);
|
|
26
|
+
} else if (group.mclass === "mord") {
|
|
27
|
+
if (group.isCharacterBox) {
|
|
28
|
+
node = inner[0];
|
|
29
|
+
node.type = "mi";
|
|
30
|
+
} else {
|
|
31
|
+
node = new mathMLTree.MathNode("mi", inner);
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
if (group.isCharacterBox) {
|
|
35
|
+
node = inner[0];
|
|
36
|
+
node.type = "mo";
|
|
37
|
+
} else {
|
|
38
|
+
node = new mathMLTree.MathNode("mo", inner);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Set spacing based on what is the most likely adjacent atom type.
|
|
42
|
+
// See TeXbook p170.
|
|
43
|
+
if (group.mclass === "mbin") {
|
|
44
|
+
node.attributes.lspace = "0.22em"; // medium space
|
|
45
|
+
node.attributes.rspace = "0.22em";
|
|
46
|
+
} else if (group.mclass === "mpunct") {
|
|
47
|
+
node.attributes.lspace = "0em";
|
|
48
|
+
node.attributes.rspace = "0.17em"; // thinspace
|
|
49
|
+
} else if (group.mclass === "mopen" || group.mclass === "mclose") {
|
|
50
|
+
node.attributes.lspace = "0em";
|
|
51
|
+
node.attributes.rspace = "0em";
|
|
52
|
+
}
|
|
53
|
+
// MathML <mo> default space is 5/18 em, so <mrel> needs no action.
|
|
54
|
+
// Ref: https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mo
|
|
55
|
+
}
|
|
56
|
+
return node;
|
|
22
57
|
}
|
|
23
58
|
|
|
24
59
|
// Math class commands except \mathop
|
|
@@ -36,8 +71,9 @@ defineFunction({
|
|
|
36
71
|
return {
|
|
37
72
|
type: "mclass",
|
|
38
73
|
mode: parser.mode,
|
|
39
|
-
mclass: "m" + funcName.substr(5),
|
|
74
|
+
mclass: "m" + funcName.substr(5), // TODO(kevinb): don't prefix with 'm'
|
|
40
75
|
body: ordargument(body),
|
|
76
|
+
isCharacterBox: utils.isCharacterBox(body),
|
|
41
77
|
};
|
|
42
78
|
},
|
|
43
79
|
htmlBuilder,
|
|
@@ -71,6 +107,7 @@ defineFunction({
|
|
|
71
107
|
mode: parser.mode,
|
|
72
108
|
mclass: binrelClass(args[0]),
|
|
73
109
|
body: [args[1]],
|
|
110
|
+
isCharacterBox: utils.isCharacterBox(args[1]),
|
|
74
111
|
};
|
|
75
112
|
},
|
|
76
113
|
});
|
|
@@ -99,6 +136,7 @@ defineFunction({
|
|
|
99
136
|
mode: baseArg.mode,
|
|
100
137
|
limits: true,
|
|
101
138
|
alwaysHandleSupSub: true,
|
|
139
|
+
parentIsSupSub: false,
|
|
102
140
|
symbol: false,
|
|
103
141
|
suppressBaseShift: funcName !== "\\stackrel",
|
|
104
142
|
body: ordargument(baseArg),
|
|
@@ -117,6 +155,7 @@ defineFunction({
|
|
|
117
155
|
mode: parser.mode,
|
|
118
156
|
mclass,
|
|
119
157
|
body: [supsub],
|
|
158
|
+
isCharacterBox: utils.isCharacterBox(supsub),
|
|
120
159
|
};
|
|
121
160
|
},
|
|
122
161
|
htmlBuilder,
|
package/src/functions/op.js
CHANGED
|
@@ -6,7 +6,8 @@ import {SymbolNode} from "../domTree";
|
|
|
6
6
|
import * as mathMLTree from "../mathMLTree";
|
|
7
7
|
import utils from "../utils";
|
|
8
8
|
import Style from "../Style";
|
|
9
|
-
import {
|
|
9
|
+
import {assembleSupSub} from "./utils/assembleSupSub";
|
|
10
|
+
import {assertNodeType} from "../parseNode";
|
|
10
11
|
|
|
11
12
|
import * as html from "../buildHTML";
|
|
12
13
|
import * as mml from "../buildMathML";
|
|
@@ -14,6 +15,11 @@ import * as mml from "../buildMathML";
|
|
|
14
15
|
import type {HtmlBuilderSupSub, MathMLBuilder} from "../defineFunction";
|
|
15
16
|
import type {ParseNode} from "../parseNode";
|
|
16
17
|
|
|
18
|
+
// Most operators have a large successor symbol, but these don't.
|
|
19
|
+
const noSuccessor = [
|
|
20
|
+
"\\smallint",
|
|
21
|
+
];
|
|
22
|
+
|
|
17
23
|
// NOTE: Unlike most `htmlBuilder`s, this one handles not only "op", but also
|
|
18
24
|
// "supsub" since some of them (like \int) can affect super/subscripting.
|
|
19
25
|
export const htmlBuilder: HtmlBuilderSupSub<"op"> = (grp, options) => {
|
|
@@ -22,14 +28,13 @@ export const htmlBuilder: HtmlBuilderSupSub<"op"> = (grp, options) => {
|
|
|
22
28
|
let subGroup;
|
|
23
29
|
let hasLimits = false;
|
|
24
30
|
let group: ParseNode<"op">;
|
|
25
|
-
|
|
26
|
-
if (supSub) {
|
|
31
|
+
if (grp.type === "supsub") {
|
|
27
32
|
// If we have limits, supsub will pass us its group to handle. Pull
|
|
28
33
|
// out the superscript and subscript and set the group to the op in
|
|
29
34
|
// its base.
|
|
30
|
-
supGroup =
|
|
31
|
-
subGroup =
|
|
32
|
-
group = assertNodeType(
|
|
35
|
+
supGroup = grp.sup;
|
|
36
|
+
subGroup = grp.sub;
|
|
37
|
+
group = assertNodeType(grp.base, "op");
|
|
33
38
|
hasLimits = true;
|
|
34
39
|
} else {
|
|
35
40
|
group = assertNodeType(grp, "op");
|
|
@@ -37,11 +42,6 @@ export const htmlBuilder: HtmlBuilderSupSub<"op"> = (grp, options) => {
|
|
|
37
42
|
|
|
38
43
|
const style = options.style;
|
|
39
44
|
|
|
40
|
-
// Most operators have a large successor symbol, but these don't.
|
|
41
|
-
const noSuccessor = [
|
|
42
|
-
"\\smallint",
|
|
43
|
-
];
|
|
44
|
-
|
|
45
45
|
let large = false;
|
|
46
46
|
if (style.size === Style.DISPLAY.size &&
|
|
47
47
|
group.symbol &&
|
|
@@ -105,7 +105,7 @@ export const htmlBuilder: HtmlBuilderSupSub<"op"> = (grp, options) => {
|
|
|
105
105
|
// operators, like \limsup
|
|
106
106
|
const output = [];
|
|
107
107
|
for (let i = 1; i < group.name.length; i++) {
|
|
108
|
-
output.push(buildCommon.mathsym(group.name[i], group.mode));
|
|
108
|
+
output.push(buildCommon.mathsym(group.name[i], group.mode, options));
|
|
109
109
|
}
|
|
110
110
|
base = buildCommon.makeSpan(["mop"], output, options);
|
|
111
111
|
}
|
|
@@ -131,99 +131,9 @@ export const htmlBuilder: HtmlBuilderSupSub<"op"> = (grp, options) => {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
if (hasLimits) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
base = buildCommon.makeSpan([], [base]);
|
|
137
|
-
|
|
138
|
-
let sub;
|
|
139
|
-
let sup;
|
|
140
|
-
// We manually have to handle the superscripts and subscripts. This,
|
|
141
|
-
// aside from the kern calculations, is copied from supsub.
|
|
142
|
-
if (supGroup) {
|
|
143
|
-
const elem = html.buildGroup(
|
|
144
|
-
supGroup, options.havingStyle(style.sup()), options);
|
|
145
|
-
|
|
146
|
-
sup = {
|
|
147
|
-
elem,
|
|
148
|
-
kern: Math.max(
|
|
149
|
-
options.fontMetrics().bigOpSpacing1,
|
|
150
|
-
options.fontMetrics().bigOpSpacing3 - elem.depth),
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (subGroup) {
|
|
155
|
-
const elem = html.buildGroup(
|
|
156
|
-
subGroup, options.havingStyle(style.sub()), options);
|
|
157
|
-
|
|
158
|
-
sub = {
|
|
159
|
-
elem,
|
|
160
|
-
kern: Math.max(
|
|
161
|
-
options.fontMetrics().bigOpSpacing2,
|
|
162
|
-
options.fontMetrics().bigOpSpacing4 - elem.height),
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Build the final group as a vlist of the possible subscript, base,
|
|
167
|
-
// and possible superscript.
|
|
168
|
-
let finalGroup;
|
|
169
|
-
if (sup && sub) {
|
|
170
|
-
const bottom = options.fontMetrics().bigOpSpacing5 +
|
|
171
|
-
sub.elem.height + sub.elem.depth +
|
|
172
|
-
sub.kern +
|
|
173
|
-
base.depth + baseShift;
|
|
174
|
-
|
|
175
|
-
finalGroup = buildCommon.makeVList({
|
|
176
|
-
positionType: "bottom",
|
|
177
|
-
positionData: bottom,
|
|
178
|
-
children: [
|
|
179
|
-
{type: "kern", size: options.fontMetrics().bigOpSpacing5},
|
|
180
|
-
{type: "elem", elem: sub.elem, marginLeft: -slant + "em"},
|
|
181
|
-
{type: "kern", size: sub.kern},
|
|
182
|
-
{type: "elem", elem: base},
|
|
183
|
-
{type: "kern", size: sup.kern},
|
|
184
|
-
{type: "elem", elem: sup.elem, marginLeft: slant + "em"},
|
|
185
|
-
{type: "kern", size: options.fontMetrics().bigOpSpacing5},
|
|
186
|
-
],
|
|
187
|
-
}, options);
|
|
188
|
-
} else if (sub) {
|
|
189
|
-
const top = base.height - baseShift;
|
|
190
|
-
|
|
191
|
-
// Shift the limits by the slant of the symbol. Note
|
|
192
|
-
// that we are supposed to shift the limits by 1/2 of the slant,
|
|
193
|
-
// but since we are centering the limits adding a full slant of
|
|
194
|
-
// margin will shift by 1/2 that.
|
|
195
|
-
finalGroup = buildCommon.makeVList({
|
|
196
|
-
positionType: "top",
|
|
197
|
-
positionData: top,
|
|
198
|
-
children: [
|
|
199
|
-
{type: "kern", size: options.fontMetrics().bigOpSpacing5},
|
|
200
|
-
{type: "elem", elem: sub.elem, marginLeft: -slant + "em"},
|
|
201
|
-
{type: "kern", size: sub.kern},
|
|
202
|
-
{type: "elem", elem: base},
|
|
203
|
-
],
|
|
204
|
-
}, options);
|
|
205
|
-
} else if (sup) {
|
|
206
|
-
const bottom = base.depth + baseShift;
|
|
207
|
-
|
|
208
|
-
finalGroup = buildCommon.makeVList({
|
|
209
|
-
positionType: "bottom",
|
|
210
|
-
positionData: bottom,
|
|
211
|
-
children: [
|
|
212
|
-
{type: "elem", elem: base},
|
|
213
|
-
{type: "kern", size: sup.kern},
|
|
214
|
-
{type: "elem", elem: sup.elem, marginLeft: slant + "em"},
|
|
215
|
-
{type: "kern", size: options.fontMetrics().bigOpSpacing5},
|
|
216
|
-
],
|
|
217
|
-
}, options);
|
|
218
|
-
} else {
|
|
219
|
-
// This case probably shouldn't occur (this would mean the
|
|
220
|
-
// supsub was sending us a group with no superscript or
|
|
221
|
-
// subscript) but be safe.
|
|
222
|
-
return base;
|
|
223
|
-
}
|
|
134
|
+
return assembleSupSub(base, supGroup, subGroup, options,
|
|
135
|
+
style, slant, baseShift);
|
|
224
136
|
|
|
225
|
-
return buildCommon.makeSpan(
|
|
226
|
-
["mop", "op-limits"], [finalGroup], options);
|
|
227
137
|
} else {
|
|
228
138
|
if (baseShift) {
|
|
229
139
|
base.style.position = "relative";
|
|
@@ -237,12 +147,13 @@ export const htmlBuilder: HtmlBuilderSupSub<"op"> = (grp, options) => {
|
|
|
237
147
|
const mathmlBuilder: MathMLBuilder<"op"> = (group, options) => {
|
|
238
148
|
let node;
|
|
239
149
|
|
|
240
|
-
// TODO(emily): handle big operators using the `largeop` attribute
|
|
241
|
-
|
|
242
150
|
if (group.symbol) {
|
|
243
151
|
// This is a symbol. Just add the symbol.
|
|
244
152
|
node = new mathMLTree.MathNode(
|
|
245
153
|
"mo", [mml.makeText(group.name, group.mode)]);
|
|
154
|
+
if (utils.contains(noSuccessor, group.name)) {
|
|
155
|
+
node.setAttribute("largeop", "false");
|
|
156
|
+
}
|
|
246
157
|
} else if (group.body) {
|
|
247
158
|
// This is an operator with children. Add them.
|
|
248
159
|
node = new mathMLTree.MathNode(
|
|
@@ -250,17 +161,17 @@ const mathmlBuilder: MathMLBuilder<"op"> = (group, options) => {
|
|
|
250
161
|
} else {
|
|
251
162
|
// This is a text operator. Add all of the characters from the
|
|
252
163
|
// operator's name.
|
|
253
|
-
// TODO(emily): Add a space in the middle of some of these
|
|
254
|
-
// operators, like \limsup.
|
|
255
164
|
node = new mathMLTree.MathNode(
|
|
256
165
|
"mi", [new mathMLTree.TextNode(group.name.slice(1))]);
|
|
257
|
-
|
|
258
166
|
// Append an <mo>⁡</mo>.
|
|
259
167
|
// ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4
|
|
260
168
|
const operator = new mathMLTree.MathNode("mo",
|
|
261
169
|
[mml.makeText("\u2061", "text")]);
|
|
262
|
-
|
|
263
|
-
|
|
170
|
+
if (group.parentIsSupSub) {
|
|
171
|
+
node = new mathMLTree.MathNode("mo", [node, operator]);
|
|
172
|
+
} else {
|
|
173
|
+
node = mathMLTree.newDocumentFragment([node, operator]);
|
|
174
|
+
}
|
|
264
175
|
}
|
|
265
176
|
|
|
266
177
|
return node;
|
|
@@ -302,6 +213,7 @@ defineFunction({
|
|
|
302
213
|
type: "op",
|
|
303
214
|
mode: parser.mode,
|
|
304
215
|
limits: true,
|
|
216
|
+
parentIsSupSub: false,
|
|
305
217
|
symbol: true,
|
|
306
218
|
name: fName,
|
|
307
219
|
};
|
|
@@ -324,6 +236,7 @@ defineFunction({
|
|
|
324
236
|
type: "op",
|
|
325
237
|
mode: parser.mode,
|
|
326
238
|
limits: false,
|
|
239
|
+
parentIsSupSub: false,
|
|
327
240
|
symbol: false,
|
|
328
241
|
body: ordargument(body),
|
|
329
242
|
};
|
|
@@ -363,6 +276,7 @@ defineFunction({
|
|
|
363
276
|
type: "op",
|
|
364
277
|
mode: parser.mode,
|
|
365
278
|
limits: false,
|
|
279
|
+
parentIsSupSub: false,
|
|
366
280
|
symbol: false,
|
|
367
281
|
name: funcName,
|
|
368
282
|
};
|
|
@@ -385,6 +299,7 @@ defineFunction({
|
|
|
385
299
|
type: "op",
|
|
386
300
|
mode: parser.mode,
|
|
387
301
|
limits: true,
|
|
302
|
+
parentIsSupSub: false,
|
|
388
303
|
symbol: false,
|
|
389
304
|
name: funcName,
|
|
390
305
|
};
|
|
@@ -412,6 +327,7 @@ defineFunction({
|
|
|
412
327
|
type: "op",
|
|
413
328
|
mode: parser.mode,
|
|
414
329
|
limits: false,
|
|
330
|
+
parentIsSupSub: false,
|
|
415
331
|
symbol: true,
|
|
416
332
|
name: fName,
|
|
417
333
|
};
|