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
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
import buildCommon from "../buildCommon";
|
|
3
|
+
import Style from "../Style";
|
|
3
4
|
import defineEnvironment from "../defineEnvironment";
|
|
4
5
|
import defineFunction from "../defineFunction";
|
|
5
6
|
import mathMLTree from "../mathMLTree";
|
|
6
7
|
import ParseError from "../ParseError";
|
|
7
8
|
import {assertNodeType, assertSymbolNodeType} from "../parseNode";
|
|
8
|
-
import {
|
|
9
|
+
import {checkSymbolNodeType} from "../parseNode";
|
|
9
10
|
import {calculateSize} from "../units";
|
|
10
11
|
import utils from "../utils";
|
|
11
12
|
|
|
@@ -25,17 +26,20 @@ export type AlignSpec = { type: "separator", separator: string } | {
|
|
|
25
26
|
postgap?: number,
|
|
26
27
|
};
|
|
27
28
|
|
|
29
|
+
// Type to indicate column separation in MathML
|
|
30
|
+
export type ColSeparationType = "align" | "alignat" | "small";
|
|
31
|
+
|
|
28
32
|
function getHLines(parser: Parser): boolean[] {
|
|
29
33
|
// Return an array. The array length = number of hlines.
|
|
30
34
|
// Each element in the array tells if the line is dashed.
|
|
31
35
|
const hlineInfo = [];
|
|
32
36
|
parser.consumeSpaces();
|
|
33
|
-
let nxt = parser.
|
|
37
|
+
let nxt = parser.fetch().text;
|
|
34
38
|
while (nxt === "\\hline" || nxt === "\\hdashline") {
|
|
35
39
|
parser.consume();
|
|
36
40
|
hlineInfo.push(nxt === "\\hdashline");
|
|
37
41
|
parser.consumeSpaces();
|
|
38
|
-
nxt = parser.
|
|
42
|
+
nxt = parser.fetch().text;
|
|
39
43
|
}
|
|
40
44
|
return hlineInfo;
|
|
41
45
|
}
|
|
@@ -48,11 +52,12 @@ function getHLines(parser: Parser): boolean[] {
|
|
|
48
52
|
*/
|
|
49
53
|
function parseArray(
|
|
50
54
|
parser: Parser,
|
|
51
|
-
{hskipBeforeAndAfter, addJot, cols, arraystretch}: {|
|
|
55
|
+
{hskipBeforeAndAfter, addJot, cols, arraystretch, colSeparationType}: {|
|
|
52
56
|
hskipBeforeAndAfter?: boolean,
|
|
53
57
|
addJot?: boolean,
|
|
54
58
|
cols?: AlignSpec[],
|
|
55
59
|
arraystretch?: number,
|
|
60
|
+
colSeparationType?: ColSeparationType,
|
|
56
61
|
|},
|
|
57
62
|
style: StyleStr,
|
|
58
63
|
): ParseNode<"array"> {
|
|
@@ -74,6 +79,9 @@ function parseArray(
|
|
|
74
79
|
}
|
|
75
80
|
}
|
|
76
81
|
|
|
82
|
+
// Start group for first cell
|
|
83
|
+
parser.gullet.beginGroup();
|
|
84
|
+
|
|
77
85
|
let row = [];
|
|
78
86
|
const body = [row];
|
|
79
87
|
const rowGaps = [];
|
|
@@ -83,7 +91,11 @@ function parseArray(
|
|
|
83
91
|
hLinesBeforeRow.push(getHLines(parser));
|
|
84
92
|
|
|
85
93
|
while (true) { // eslint-disable-line no-constant-condition
|
|
94
|
+
// Parse each cell in its own group (namespace)
|
|
86
95
|
let cell = parser.parseExpression(false, "\\cr");
|
|
96
|
+
parser.gullet.endGroup();
|
|
97
|
+
parser.gullet.beginGroup();
|
|
98
|
+
|
|
87
99
|
cell = {
|
|
88
100
|
type: "ordgroup",
|
|
89
101
|
mode: parser.mode,
|
|
@@ -98,7 +110,7 @@ function parseArray(
|
|
|
98
110
|
};
|
|
99
111
|
}
|
|
100
112
|
row.push(cell);
|
|
101
|
-
const next = parser.
|
|
113
|
+
const next = parser.fetch().text;
|
|
102
114
|
if (next === "&") {
|
|
103
115
|
parser.consume();
|
|
104
116
|
} else if (next === "\\end") {
|
|
@@ -127,7 +139,12 @@ function parseArray(
|
|
|
127
139
|
parser.nextToken);
|
|
128
140
|
}
|
|
129
141
|
}
|
|
142
|
+
|
|
143
|
+
// End cell group
|
|
144
|
+
parser.gullet.endGroup();
|
|
145
|
+
// End array group defining \\
|
|
130
146
|
parser.gullet.endGroup();
|
|
147
|
+
|
|
131
148
|
return {
|
|
132
149
|
type: "array",
|
|
133
150
|
mode: parser.mode,
|
|
@@ -138,6 +155,7 @@ function parseArray(
|
|
|
138
155
|
rowGaps,
|
|
139
156
|
hskipBeforeAndAfter,
|
|
140
157
|
hLinesBeforeRow,
|
|
158
|
+
colSeparationType,
|
|
141
159
|
};
|
|
142
160
|
}
|
|
143
161
|
|
|
@@ -168,9 +186,24 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
|
|
168
186
|
let body = new Array(nr);
|
|
169
187
|
const hlines = [];
|
|
170
188
|
|
|
189
|
+
const ruleThickness = Math.max(
|
|
190
|
+
// From LaTeX \showthe\arrayrulewidth. Equals 0.04 em.
|
|
191
|
+
(options.fontMetrics().arrayRuleWidth),
|
|
192
|
+
options.minRuleThickness, // User override.
|
|
193
|
+
);
|
|
194
|
+
|
|
171
195
|
// Horizontal spacing
|
|
172
196
|
const pt = 1 / options.fontMetrics().ptPerEm;
|
|
173
|
-
|
|
197
|
+
let arraycolsep = 5 * pt; // default value, i.e. \arraycolsep in article.cls
|
|
198
|
+
if (group.colSeparationType && group.colSeparationType === "small") {
|
|
199
|
+
// We're in a {smallmatrix}. Default column space is \thickspace,
|
|
200
|
+
// i.e. 5/18em = 0.2778em, per amsmath.dtx for {smallmatrix}.
|
|
201
|
+
// But that needs adjustment because LaTeX applies \scriptstyle to the
|
|
202
|
+
// entire array, including the colspace, but this function applies
|
|
203
|
+
// \scriptstyle only inside each element.
|
|
204
|
+
const localMultiplier = options.havingStyle(Style.SCRIPT).sizeMultiplier;
|
|
205
|
+
arraycolsep = 0.2778 * (localMultiplier / options.sizeMultiplier);
|
|
206
|
+
}
|
|
174
207
|
|
|
175
208
|
// Vertical spacing
|
|
176
209
|
const baselineskip = 12 * pt; // see size10.clo
|
|
@@ -269,20 +302,15 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
|
|
269
302
|
cols.push(colSep);
|
|
270
303
|
}
|
|
271
304
|
|
|
272
|
-
if (colDescr.separator === "|") {
|
|
305
|
+
if (colDescr.separator === "|" || colDescr.separator === ":") {
|
|
306
|
+
const lineType = (colDescr.separator === "|") ? "solid" : "dashed";
|
|
273
307
|
const separator = buildCommon.makeSpan(
|
|
274
308
|
["vertical-separator"], [], options
|
|
275
309
|
);
|
|
276
310
|
separator.style.height = totalHeight + "em";
|
|
277
|
-
separator.style.
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
cols.push(separator);
|
|
281
|
-
} else if (colDescr.separator === ":") {
|
|
282
|
-
const separator = buildCommon.makeSpan(
|
|
283
|
-
["vertical-separator", "vs-dashed"], [], options
|
|
284
|
-
);
|
|
285
|
-
separator.style.height = totalHeight + "em";
|
|
311
|
+
separator.style.borderRightWidth = `${ruleThickness}em`;
|
|
312
|
+
separator.style.borderRightStyle = lineType;
|
|
313
|
+
separator.style.margin = `0 -${ruleThickness / 2}em`;
|
|
286
314
|
separator.style.verticalAlign =
|
|
287
315
|
-(totalHeight - offset) + "em";
|
|
288
316
|
|
|
@@ -346,8 +374,9 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
|
|
346
374
|
|
|
347
375
|
// Add \hline(s), if any.
|
|
348
376
|
if (hlines.length > 0) {
|
|
349
|
-
const line = buildCommon.makeLineSpan("hline", options,
|
|
350
|
-
const dashes = buildCommon.makeLineSpan("hdashline", options,
|
|
377
|
+
const line = buildCommon.makeLineSpan("hline", options, ruleThickness);
|
|
378
|
+
const dashes = buildCommon.makeLineSpan("hdashline", options,
|
|
379
|
+
ruleThickness);
|
|
351
380
|
const vListElems = [{type: "elem", elem: body, shift: 0}];
|
|
352
381
|
while (hlines.length > 0) {
|
|
353
382
|
const hline = hlines.pop();
|
|
@@ -367,8 +396,14 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
|
|
367
396
|
return buildCommon.makeSpan(["mord"], [body], options);
|
|
368
397
|
};
|
|
369
398
|
|
|
399
|
+
const alignMap = {
|
|
400
|
+
c: "center ",
|
|
401
|
+
l: "left ",
|
|
402
|
+
r: "right ",
|
|
403
|
+
};
|
|
404
|
+
|
|
370
405
|
const mathmlBuilder: MathMLBuilder<"array"> = function(group, options) {
|
|
371
|
-
|
|
406
|
+
let table = new mathMLTree.MathNode(
|
|
372
407
|
"mtable", group.body.map(function(row) {
|
|
373
408
|
return new mathMLTree.MathNode(
|
|
374
409
|
"mtr", row.map(function(cell) {
|
|
@@ -376,6 +411,119 @@ const mathmlBuilder: MathMLBuilder<"array"> = function(group, options) {
|
|
|
376
411
|
"mtd", [mml.buildGroup(cell, options)]);
|
|
377
412
|
}));
|
|
378
413
|
}));
|
|
414
|
+
|
|
415
|
+
// Set column alignment, row spacing, column spacing, and
|
|
416
|
+
// array lines by setting attributes on the table element.
|
|
417
|
+
|
|
418
|
+
// Set the row spacing. In MathML, we specify a gap distance.
|
|
419
|
+
// We do not use rowGap[] because MathML automatically increases
|
|
420
|
+
// cell height with the height/depth of the element content.
|
|
421
|
+
|
|
422
|
+
// LaTeX \arraystretch multiplies the row baseline-to-baseline distance.
|
|
423
|
+
// We simulate this by adding (arraystretch - 1)em to the gap. This
|
|
424
|
+
// does a reasonable job of adjusting arrays containing 1 em tall content.
|
|
425
|
+
|
|
426
|
+
// The 0.16 and 0.09 values are found emprically. They produce an array
|
|
427
|
+
// similar to LaTeX and in which content does not interfere with \hines.
|
|
428
|
+
const gap = (group.arraystretch === 0.5)
|
|
429
|
+
? 0.1 // {smallmatrix}, {subarray}
|
|
430
|
+
: 0.16 + group.arraystretch - 1 + (group.addJot ? 0.09 : 0);
|
|
431
|
+
table.setAttribute("rowspacing", gap + "em");
|
|
432
|
+
|
|
433
|
+
// MathML table lines go only between cells.
|
|
434
|
+
// To place a line on an edge we'll use <menclose>, if necessary.
|
|
435
|
+
let menclose = "";
|
|
436
|
+
let align = "";
|
|
437
|
+
|
|
438
|
+
if (group.cols && group.cols.length > 0) {
|
|
439
|
+
// Find column alignment, column spacing, and vertical lines.
|
|
440
|
+
const cols = group.cols;
|
|
441
|
+
let columnLines = "";
|
|
442
|
+
let prevTypeWasAlign = false;
|
|
443
|
+
let iStart = 0;
|
|
444
|
+
let iEnd = cols.length;
|
|
445
|
+
|
|
446
|
+
if (cols[0].type === "separator") {
|
|
447
|
+
menclose += "top ";
|
|
448
|
+
iStart = 1;
|
|
449
|
+
}
|
|
450
|
+
if (cols[cols.length - 1].type === "separator") {
|
|
451
|
+
menclose += "bottom ";
|
|
452
|
+
iEnd -= 1;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
for (let i = iStart; i < iEnd; i++) {
|
|
456
|
+
if (cols[i].type === "align") {
|
|
457
|
+
align += alignMap[cols[i].align];
|
|
458
|
+
|
|
459
|
+
if (prevTypeWasAlign) {
|
|
460
|
+
columnLines += "none ";
|
|
461
|
+
}
|
|
462
|
+
prevTypeWasAlign = true;
|
|
463
|
+
} else if (cols[i].type === "separator") {
|
|
464
|
+
// MathML accepts only single lines between cells.
|
|
465
|
+
// So we read only the first of consecutive separators.
|
|
466
|
+
if (prevTypeWasAlign) {
|
|
467
|
+
columnLines += cols[i].separator === "|"
|
|
468
|
+
? "solid "
|
|
469
|
+
: "dashed ";
|
|
470
|
+
prevTypeWasAlign = false;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
table.setAttribute("columnalign", align.trim());
|
|
476
|
+
|
|
477
|
+
if (/[sd]/.test(columnLines)) {
|
|
478
|
+
table.setAttribute("columnlines", columnLines.trim());
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Set column spacing.
|
|
483
|
+
if (group.colSeparationType === "align") {
|
|
484
|
+
const cols = group.cols || [];
|
|
485
|
+
let spacing = "";
|
|
486
|
+
for (let i = 1; i < cols.length; i++) {
|
|
487
|
+
spacing += i % 2 ? "0em " : "1em ";
|
|
488
|
+
}
|
|
489
|
+
table.setAttribute("columnspacing", spacing.trim());
|
|
490
|
+
} else if (group.colSeparationType === "alignat") {
|
|
491
|
+
table.setAttribute("columnspacing", "0em");
|
|
492
|
+
} else if (group.colSeparationType === "small") {
|
|
493
|
+
table.setAttribute("columnspacing", "0.2778em");
|
|
494
|
+
} else {
|
|
495
|
+
table.setAttribute("columnspacing", "1em");
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Address \hline and \hdashline
|
|
499
|
+
let rowLines = "";
|
|
500
|
+
const hlines = group.hLinesBeforeRow;
|
|
501
|
+
|
|
502
|
+
menclose += hlines[0].length > 0 ? "left " : "";
|
|
503
|
+
menclose += hlines[hlines.length - 1].length > 0 ? "right " : "";
|
|
504
|
+
|
|
505
|
+
for (let i = 1; i < hlines.length - 1; i++) {
|
|
506
|
+
rowLines += (hlines[i].length === 0)
|
|
507
|
+
? "none "
|
|
508
|
+
// MathML accepts only a single line between rows. Read one element.
|
|
509
|
+
: hlines[i][0] ? "dashed " : "solid ";
|
|
510
|
+
}
|
|
511
|
+
if (/[sd]/.test(rowLines)) {
|
|
512
|
+
table.setAttribute("rowlines", rowLines.trim());
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (menclose !== "") {
|
|
516
|
+
table = new mathMLTree.MathNode("menclose", [table]);
|
|
517
|
+
table.setAttribute("notation", menclose.trim());
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (group.arraystretch && group.arraystretch < 1) {
|
|
521
|
+
// A small array. Wrap in scriptstyle so row gap is not too large.
|
|
522
|
+
table = new mathMLTree.MathNode("mstyle", [table]);
|
|
523
|
+
table.setAttribute("scriptlevel", "1");
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
return table;
|
|
379
527
|
};
|
|
380
528
|
|
|
381
529
|
// Convenience function for aligned and alignedat environments.
|
|
@@ -399,11 +547,10 @@ const alignedHandler = function(context, args) {
|
|
|
399
547
|
mode: context.mode,
|
|
400
548
|
body: [],
|
|
401
549
|
};
|
|
402
|
-
|
|
403
|
-
if (ordgroup) {
|
|
550
|
+
if (args[0] && args[0].type === "ordgroup") {
|
|
404
551
|
let arg0 = "";
|
|
405
|
-
for (let i = 0; i <
|
|
406
|
-
const textord = assertNodeType(
|
|
552
|
+
for (let i = 0; i < args[0].body.length; i++) {
|
|
553
|
+
const textord = assertNodeType(args[0].body[i], "textord");
|
|
407
554
|
arg0 += textord.text;
|
|
408
555
|
}
|
|
409
556
|
numMaths = Number(arg0);
|
|
@@ -448,6 +595,7 @@ const alignedHandler = function(context, args) {
|
|
|
448
595
|
postgap: 0,
|
|
449
596
|
};
|
|
450
597
|
}
|
|
598
|
+
res.colSeparationType = isAligned ? "align" : "alignat";
|
|
451
599
|
return res;
|
|
452
600
|
};
|
|
453
601
|
|
|
@@ -534,22 +682,83 @@ defineEnvironment({
|
|
|
534
682
|
body: [res],
|
|
535
683
|
left: delimiters[0],
|
|
536
684
|
right: delimiters[1],
|
|
685
|
+
rightColor: undefined, // \right uninfluenced by \color in array
|
|
537
686
|
} : res;
|
|
538
687
|
},
|
|
539
688
|
htmlBuilder,
|
|
540
689
|
mathmlBuilder,
|
|
541
690
|
});
|
|
542
691
|
|
|
692
|
+
defineEnvironment({
|
|
693
|
+
type: "array",
|
|
694
|
+
names: ["smallmatrix"],
|
|
695
|
+
props: {
|
|
696
|
+
numArgs: 0,
|
|
697
|
+
},
|
|
698
|
+
handler(context) {
|
|
699
|
+
const payload = {arraystretch: 0.5};
|
|
700
|
+
const res = parseArray(context.parser, payload, "script");
|
|
701
|
+
res.colSeparationType = "small";
|
|
702
|
+
return res;
|
|
703
|
+
},
|
|
704
|
+
htmlBuilder,
|
|
705
|
+
mathmlBuilder,
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
defineEnvironment({
|
|
709
|
+
type: "array",
|
|
710
|
+
names: ["subarray"],
|
|
711
|
+
props: {
|
|
712
|
+
numArgs: 1,
|
|
713
|
+
},
|
|
714
|
+
handler(context, args) {
|
|
715
|
+
// Parsing of {subarray} is similar to {array}
|
|
716
|
+
const symNode = checkSymbolNodeType(args[0]);
|
|
717
|
+
const colalign: AnyParseNode[] =
|
|
718
|
+
symNode ? [args[0]] : assertNodeType(args[0], "ordgroup").body;
|
|
719
|
+
const cols = colalign.map(function(nde) {
|
|
720
|
+
const node = assertSymbolNodeType(nde);
|
|
721
|
+
const ca = node.text;
|
|
722
|
+
// {subarray} only recognizes "l" & "c"
|
|
723
|
+
if ("lc".indexOf(ca) !== -1) {
|
|
724
|
+
return {
|
|
725
|
+
type: "align",
|
|
726
|
+
align: ca,
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
throw new ParseError("Unknown column alignment: " + ca, nde);
|
|
730
|
+
});
|
|
731
|
+
if (cols.length > 1) {
|
|
732
|
+
throw new ParseError("{subarray} can contain only one column");
|
|
733
|
+
}
|
|
734
|
+
let res = {
|
|
735
|
+
cols,
|
|
736
|
+
hskipBeforeAndAfter: false,
|
|
737
|
+
arraystretch: 0.5,
|
|
738
|
+
};
|
|
739
|
+
res = parseArray(context.parser, res, "script");
|
|
740
|
+
if (res.body.length > 0 && res.body[0].length > 1) {
|
|
741
|
+
throw new ParseError("{subarray} can contain only one column");
|
|
742
|
+
}
|
|
743
|
+
return res;
|
|
744
|
+
},
|
|
745
|
+
htmlBuilder,
|
|
746
|
+
mathmlBuilder,
|
|
747
|
+
});
|
|
748
|
+
|
|
543
749
|
// A cases environment (in amsmath.sty) is almost equivalent to
|
|
544
750
|
// \def\arraystretch{1.2}%
|
|
545
751
|
// \left\{\begin{array}{@{}l@{\quad}l@{}} … \end{array}\right.
|
|
546
752
|
// {dcases} is a {cases} environment where cells are set in \displaystyle,
|
|
547
753
|
// as defined in mathtools.sty.
|
|
754
|
+
// {rcases} is another mathtools environment. It's brace is on the right side.
|
|
548
755
|
defineEnvironment({
|
|
549
756
|
type: "array",
|
|
550
757
|
names: [
|
|
551
758
|
"cases",
|
|
552
759
|
"dcases",
|
|
760
|
+
"rcases",
|
|
761
|
+
"drcases",
|
|
553
762
|
],
|
|
554
763
|
props: {
|
|
555
764
|
numArgs: 0,
|
|
@@ -579,8 +788,9 @@ defineEnvironment({
|
|
|
579
788
|
type: "leftright",
|
|
580
789
|
mode: context.mode,
|
|
581
790
|
body: [res],
|
|
582
|
-
left: "\\{",
|
|
583
|
-
right: ".",
|
|
791
|
+
left: context.envName.indexOf("r") > -1 ? "." : "\\{",
|
|
792
|
+
right: context.envName.indexOf("r") > -1 ? "\\}" : ".",
|
|
793
|
+
rightColor: undefined,
|
|
584
794
|
};
|
|
585
795
|
},
|
|
586
796
|
htmlBuilder,
|
package/src/fontMetrics.js
CHANGED
|
@@ -82,6 +82,14 @@ const sigmasAndXis = {
|
|
|
82
82
|
// The space between adjacent `|` columns in an array definition. From
|
|
83
83
|
// `\showthe\doublerulesep` in LaTeX. Equals 2.0 / ptPerEm.
|
|
84
84
|
doubleRuleSep: [0.2, 0.2, 0.2],
|
|
85
|
+
|
|
86
|
+
// The width of separator lines in {array} environments. From
|
|
87
|
+
// `\showthe\arrayrulewidth` in LaTeX. Equals 0.4 / ptPerEm.
|
|
88
|
+
arrayRuleWidth: [0.04, 0.04, 0.04],
|
|
89
|
+
|
|
90
|
+
// Two values from LaTeX source2e:
|
|
91
|
+
fboxsep: [0.3, 0.3, 0.3], // 3 pt / ptPerEm
|
|
92
|
+
fboxrule: [0.04, 0.04, 0.04], // 0.4 pt / ptPerEm
|
|
85
93
|
};
|
|
86
94
|
|
|
87
95
|
// This map contains a mapping from font name and character code to character
|
|
@@ -211,10 +219,11 @@ export function getCharacterMetrics(
|
|
|
211
219
|
throw new Error(`Font metrics not found for font: ${font}.`);
|
|
212
220
|
}
|
|
213
221
|
let ch = character.charCodeAt(0);
|
|
214
|
-
|
|
222
|
+
let metrics = metricMap[font][ch];
|
|
223
|
+
if (!metrics && character[0] in extraCharacterMap) {
|
|
215
224
|
ch = extraCharacterMap[character[0]].charCodeAt(0);
|
|
225
|
+
metrics = metricMap[font][ch];
|
|
216
226
|
}
|
|
217
|
-
let metrics = metricMap[font][ch];
|
|
218
227
|
|
|
219
228
|
if (!metrics && mode === 'text') {
|
|
220
229
|
// We don't typically have font metrics for Asian scripts.
|
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;
|
|
@@ -94,8 +93,9 @@ export const htmlBuilder: HtmlBuilderSupSub<"accent"> = (grp, options) => {
|
|
|
94
93
|
accent = buildCommon.staticSvg("vec", options);
|
|
95
94
|
width = buildCommon.svgData.vec[1];
|
|
96
95
|
} else {
|
|
97
|
-
accent = buildCommon.
|
|
98
|
-
|
|
96
|
+
accent = buildCommon.makeOrd({mode: group.mode, text: group.label},
|
|
97
|
+
options, "textord");
|
|
98
|
+
accent = assertSymbolDomNode(accent);
|
|
99
99
|
// Remove the italic correction of the accent, because it only serves to
|
|
100
100
|
// shift the accent over to a place we don't want.
|
|
101
101
|
accent.italic = 0;
|
|
@@ -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},
|
package/src/functions/arrow.js
CHANGED
|
@@ -9,6 +9,14 @@ import * as mml from "../buildMathML";
|
|
|
9
9
|
|
|
10
10
|
import type {ParseNode} from "../parseNode";
|
|
11
11
|
|
|
12
|
+
// Helper function
|
|
13
|
+
const paddedNode = group => {
|
|
14
|
+
const node = new mathMLTree.MathNode("mpadded", group ? [group] : []);
|
|
15
|
+
node.setAttribute("width", "+0.6em");
|
|
16
|
+
node.setAttribute("lspace", "0.3em");
|
|
17
|
+
return node;
|
|
18
|
+
};
|
|
19
|
+
|
|
12
20
|
// Stretchy arrows with an optional argument
|
|
13
21
|
defineFunction({
|
|
14
22
|
type: "xArrow",
|
|
@@ -105,12 +113,11 @@ defineFunction({
|
|
|
105
113
|
mathmlBuilder(group, options) {
|
|
106
114
|
const arrowNode = stretchy.mathMLnode(group.label);
|
|
107
115
|
let node;
|
|
108
|
-
let lowerNode;
|
|
109
116
|
|
|
110
117
|
if (group.body) {
|
|
111
|
-
const upperNode = mml.buildGroup(group.body, options);
|
|
118
|
+
const upperNode = paddedNode(mml.buildGroup(group.body, options));
|
|
112
119
|
if (group.below) {
|
|
113
|
-
lowerNode = mml.buildGroup(group.below, options);
|
|
120
|
+
const lowerNode = paddedNode(mml.buildGroup(group.below, options));
|
|
114
121
|
node = new mathMLTree.MathNode(
|
|
115
122
|
"munderover", [arrowNode, lowerNode, upperNode]
|
|
116
123
|
);
|
|
@@ -118,10 +125,13 @@ defineFunction({
|
|
|
118
125
|
node = new mathMLTree.MathNode("mover", [arrowNode, upperNode]);
|
|
119
126
|
}
|
|
120
127
|
} else if (group.below) {
|
|
121
|
-
lowerNode = mml.buildGroup(group.below, options);
|
|
128
|
+
const lowerNode = paddedNode(mml.buildGroup(group.below, options));
|
|
122
129
|
node = new mathMLTree.MathNode("munder", [arrowNode, lowerNode]);
|
|
123
130
|
} else {
|
|
124
|
-
|
|
131
|
+
// This should never happen.
|
|
132
|
+
// Parser.js throws an error if there is no argument.
|
|
133
|
+
node = paddedNode();
|
|
134
|
+
node = new mathMLTree.MathNode("mover", [arrowNode, node]);
|
|
125
135
|
}
|
|
126
136
|
return node;
|
|
127
137
|
},
|
package/src/functions/color.js
CHANGED
|
@@ -22,7 +22,8 @@ const htmlBuilder = (group, options) => {
|
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
const mathmlBuilder = (group, options) => {
|
|
25
|
-
const inner = mml.buildExpression(group.body,
|
|
25
|
+
const inner = mml.buildExpression(group.body,
|
|
26
|
+
options.withColor(group.color));
|
|
26
27
|
|
|
27
28
|
const node = new mathMLTree.MathNode("mstyle", inner);
|
|
28
29
|
|
|
@@ -54,42 +55,6 @@ defineFunction({
|
|
|
54
55
|
mathmlBuilder,
|
|
55
56
|
});
|
|
56
57
|
|
|
57
|
-
// TODO(kevinb): define these using macros
|
|
58
|
-
defineFunction({
|
|
59
|
-
type: "color",
|
|
60
|
-
names: [
|
|
61
|
-
"\\blue", "\\orange", "\\pink", "\\red",
|
|
62
|
-
"\\green", "\\gray", "\\purple",
|
|
63
|
-
"\\blueA", "\\blueB", "\\blueC", "\\blueD", "\\blueE",
|
|
64
|
-
"\\tealA", "\\tealB", "\\tealC", "\\tealD", "\\tealE",
|
|
65
|
-
"\\greenA", "\\greenB", "\\greenC", "\\greenD", "\\greenE",
|
|
66
|
-
"\\goldA", "\\goldB", "\\goldC", "\\goldD", "\\goldE",
|
|
67
|
-
"\\redA", "\\redB", "\\redC", "\\redD", "\\redE",
|
|
68
|
-
"\\maroonA", "\\maroonB", "\\maroonC", "\\maroonD", "\\maroonE",
|
|
69
|
-
"\\purpleA", "\\purpleB", "\\purpleC", "\\purpleD", "\\purpleE",
|
|
70
|
-
"\\mintA", "\\mintB", "\\mintC",
|
|
71
|
-
"\\grayA", "\\grayB", "\\grayC", "\\grayD", "\\grayE",
|
|
72
|
-
"\\grayF", "\\grayG", "\\grayH", "\\grayI",
|
|
73
|
-
"\\kaBlue", "\\kaGreen",
|
|
74
|
-
],
|
|
75
|
-
props: {
|
|
76
|
-
numArgs: 1,
|
|
77
|
-
allowedInText: true,
|
|
78
|
-
greediness: 3,
|
|
79
|
-
},
|
|
80
|
-
handler({parser, funcName}, args) {
|
|
81
|
-
const body = args[0];
|
|
82
|
-
return {
|
|
83
|
-
type: "color",
|
|
84
|
-
mode: parser.mode,
|
|
85
|
-
color: "katex-" + funcName.slice(1),
|
|
86
|
-
body: ordargument(body),
|
|
87
|
-
};
|
|
88
|
-
},
|
|
89
|
-
htmlBuilder,
|
|
90
|
-
mathmlBuilder,
|
|
91
|
-
});
|
|
92
|
-
|
|
93
58
|
defineFunction({
|
|
94
59
|
type: "color",
|
|
95
60
|
names: ["\\color"],
|
|
@@ -102,7 +67,13 @@ defineFunction({
|
|
|
102
67
|
handler({parser, breakOnTokenText}, args) {
|
|
103
68
|
const color = assertNodeType(args[0], "color-token").color;
|
|
104
69
|
|
|
105
|
-
//
|
|
70
|
+
// Set macro \current@color in current namespace to store the current
|
|
71
|
+
// color, mimicking the behavior of color.sty.
|
|
72
|
+
// This is currently used just to correctly color a \right
|
|
73
|
+
// that follows a \color command.
|
|
74
|
+
parser.gullet.macros.set("\\current@color", color);
|
|
75
|
+
|
|
76
|
+
// Parse out the implicit body that should be colored.
|
|
106
77
|
const body = parser.parseExpression(true, breakOnTokenText);
|
|
107
78
|
|
|
108
79
|
return {
|