katex 0.10.1 → 0.10.2
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 +51 -0
- package/README.md +4 -4
- package/cli.js +0 -0
- package/contrib/copy-tex/README.md +3 -3
- package/contrib/mathtex-script-type/README.md +5 -5
- package/contrib/mhchem/README.md +1 -1
- package/dist/README.md +4 -4
- 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 +10 -0
- package/dist/katex.js +541 -249
- package/dist/katex.min.css +1 -1
- package/dist/katex.min.js +1 -1
- package/dist/katex.mjs +418 -198
- package/package.json +1 -1
- package/src/Options.js +11 -75
- package/src/buildMathML.js +13 -3
- package/src/domTree.js +63 -0
- package/src/environments/array.js +118 -2
- package/src/fontMetrics.js +3 -2
- package/src/functions/arrow.js +15 -5
- package/src/functions/color.js +2 -37
- package/src/functions/delimsizing.js +12 -2
- package/src/functions/enclose.js +15 -3
- package/src/functions/genfrac.js +31 -12
- package/src/functions/includegraphics.js +146 -0
- package/src/functions/mclass.js +1 -0
- package/src/functions/op.js +18 -10
- package/src/functions/phantom.js +5 -2
- package/src/functions/rule.js +20 -9
- package/src/functions/supsub.js +6 -2
- package/src/functions/symbolsOp.js +4 -0
- package/src/functions/tag.js +20 -4
- package/src/functions/text.js +4 -2
- package/src/functions.js +2 -0
- package/src/katex.less +15 -0
- package/src/macros.js +144 -27
- package/src/mathMLTree.js +1 -1
- package/src/parseNode.js +20 -1
- package/src/stretchy.js +3 -1
- package/src/symbols.js +15 -15
package/package.json
CHANGED
package/src/Options.js
CHANGED
|
@@ -36,6 +36,10 @@ const sizeAtStyle = function(size: number, style: StyleInterface): number {
|
|
|
36
36
|
return style.size < 2 ? size : sizeStyleMap[size - 1][style.size - 1];
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
+
// In these types, "" (empty string) means "no change".
|
|
40
|
+
export type FontWeight = "textbf" | "textmd" | "";
|
|
41
|
+
export type FontShape = "textit" | "textup" | "";
|
|
42
|
+
|
|
39
43
|
export type OptionsData = {
|
|
40
44
|
style: StyleInterface;
|
|
41
45
|
color?: string | void;
|
|
@@ -44,8 +48,8 @@ export type OptionsData = {
|
|
|
44
48
|
phantom?: boolean;
|
|
45
49
|
font?: string;
|
|
46
50
|
fontFamily?: string;
|
|
47
|
-
fontWeight?:
|
|
48
|
-
fontShape?:
|
|
51
|
+
fontWeight?: FontWeight;
|
|
52
|
+
fontShape?: FontShape;
|
|
49
53
|
sizeMultiplier?: number;
|
|
50
54
|
maxSize: number;
|
|
51
55
|
};
|
|
@@ -68,8 +72,8 @@ class Options {
|
|
|
68
72
|
// See: https://tex.stackexchange.com/questions/22350/difference-between-textrm-and-mathrm
|
|
69
73
|
font: string;
|
|
70
74
|
fontFamily: string;
|
|
71
|
-
fontWeight:
|
|
72
|
-
fontShape:
|
|
75
|
+
fontWeight: FontWeight;
|
|
76
|
+
fontShape: FontShape;
|
|
73
77
|
sizeMultiplier: number;
|
|
74
78
|
maxSize: number;
|
|
75
79
|
_fontMetrics: FontMetrics | void;
|
|
@@ -244,7 +248,7 @@ class Options {
|
|
|
244
248
|
/**
|
|
245
249
|
* Creates a new options object with the given font weight
|
|
246
250
|
*/
|
|
247
|
-
withTextFontWeight(fontWeight:
|
|
251
|
+
withTextFontWeight(fontWeight: FontWeight): Options {
|
|
248
252
|
return this.extend({
|
|
249
253
|
fontWeight,
|
|
250
254
|
font: "",
|
|
@@ -254,7 +258,7 @@ class Options {
|
|
|
254
258
|
/**
|
|
255
259
|
* Creates a new options object with the given font weight
|
|
256
260
|
*/
|
|
257
|
-
withTextFontShape(fontShape:
|
|
261
|
+
withTextFontShape(fontShape: FontShape): Options {
|
|
258
262
|
return this.extend({
|
|
259
263
|
fontShape,
|
|
260
264
|
font: "",
|
|
@@ -295,81 +299,13 @@ class Options {
|
|
|
295
299
|
return this._fontMetrics;
|
|
296
300
|
}
|
|
297
301
|
|
|
298
|
-
/**
|
|
299
|
-
* A map of color names to CSS colors.
|
|
300
|
-
* TODO(emily): Remove this when we have real macros
|
|
301
|
-
*/
|
|
302
|
-
static colorMap = {
|
|
303
|
-
"katex-blue": "#6495ed",
|
|
304
|
-
"katex-orange": "#ffa500",
|
|
305
|
-
"katex-pink": "#ff00af",
|
|
306
|
-
"katex-red": "#df0030",
|
|
307
|
-
"katex-green": "#28ae7b",
|
|
308
|
-
"katex-gray": "gray",
|
|
309
|
-
"katex-purple": "#9d38bd",
|
|
310
|
-
"katex-blueA": "#ccfaff",
|
|
311
|
-
"katex-blueB": "#80f6ff",
|
|
312
|
-
"katex-blueC": "#63d9ea",
|
|
313
|
-
"katex-blueD": "#11accd",
|
|
314
|
-
"katex-blueE": "#0c7f99",
|
|
315
|
-
"katex-tealA": "#94fff5",
|
|
316
|
-
"katex-tealB": "#26edd5",
|
|
317
|
-
"katex-tealC": "#01d1c1",
|
|
318
|
-
"katex-tealD": "#01a995",
|
|
319
|
-
"katex-tealE": "#208170",
|
|
320
|
-
"katex-greenA": "#b6ffb0",
|
|
321
|
-
"katex-greenB": "#8af281",
|
|
322
|
-
"katex-greenC": "#74cf70",
|
|
323
|
-
"katex-greenD": "#1fab54",
|
|
324
|
-
"katex-greenE": "#0d923f",
|
|
325
|
-
"katex-goldA": "#ffd0a9",
|
|
326
|
-
"katex-goldB": "#ffbb71",
|
|
327
|
-
"katex-goldC": "#ff9c39",
|
|
328
|
-
"katex-goldD": "#e07d10",
|
|
329
|
-
"katex-goldE": "#a75a05",
|
|
330
|
-
"katex-redA": "#fca9a9",
|
|
331
|
-
"katex-redB": "#ff8482",
|
|
332
|
-
"katex-redC": "#f9685d",
|
|
333
|
-
"katex-redD": "#e84d39",
|
|
334
|
-
"katex-redE": "#bc2612",
|
|
335
|
-
"katex-maroonA": "#ffbde0",
|
|
336
|
-
"katex-maroonB": "#ff92c6",
|
|
337
|
-
"katex-maroonC": "#ed5fa6",
|
|
338
|
-
"katex-maroonD": "#ca337c",
|
|
339
|
-
"katex-maroonE": "#9e034e",
|
|
340
|
-
"katex-purpleA": "#ddd7ff",
|
|
341
|
-
"katex-purpleB": "#c6b9fc",
|
|
342
|
-
"katex-purpleC": "#aa87ff",
|
|
343
|
-
"katex-purpleD": "#7854ab",
|
|
344
|
-
"katex-purpleE": "#543b78",
|
|
345
|
-
"katex-mintA": "#f5f9e8",
|
|
346
|
-
"katex-mintB": "#edf2df",
|
|
347
|
-
"katex-mintC": "#e0e5cc",
|
|
348
|
-
"katex-grayA": "#f6f7f7",
|
|
349
|
-
"katex-grayB": "#f0f1f2",
|
|
350
|
-
"katex-grayC": "#e3e5e6",
|
|
351
|
-
"katex-grayD": "#d6d8da",
|
|
352
|
-
"katex-grayE": "#babec2",
|
|
353
|
-
"katex-grayF": "#888d93",
|
|
354
|
-
"katex-grayG": "#626569",
|
|
355
|
-
"katex-grayH": "#3b3e40",
|
|
356
|
-
"katex-grayI": "#21242c",
|
|
357
|
-
"katex-kaBlue": "#314453",
|
|
358
|
-
"katex-kaGreen": "#71B307",
|
|
359
|
-
};
|
|
360
302
|
|
|
361
303
|
/**
|
|
362
|
-
* Gets the CSS color of the current options object
|
|
363
|
-
* `colorMap`.
|
|
304
|
+
* Gets the CSS color of the current options object
|
|
364
305
|
*/
|
|
365
306
|
getColor(): string | void {
|
|
366
307
|
if (this.phantom) {
|
|
367
308
|
return "transparent";
|
|
368
|
-
} else if (
|
|
369
|
-
this.color != null &&
|
|
370
|
-
Options.colorMap.hasOwnProperty(this.color)
|
|
371
|
-
) {
|
|
372
|
-
return Options.colorMap[this.color];
|
|
373
309
|
} else {
|
|
374
310
|
return this.color;
|
|
375
311
|
}
|
package/src/buildMathML.js
CHANGED
|
@@ -145,14 +145,24 @@ export const buildExpression = function(
|
|
|
145
145
|
lastGroup.children.push(...group.children);
|
|
146
146
|
continue;
|
|
147
147
|
}
|
|
148
|
+
} else if (lastGroup.type === 'mi' && lastGroup.children.length === 1) {
|
|
149
|
+
const lastChild = lastGroup.children[0];
|
|
150
|
+
if (lastChild instanceof TextNode && lastChild.text === '\u0338' &&
|
|
151
|
+
(group.type === 'mo' || group.type === 'mi' ||
|
|
152
|
+
group.type === 'mn')) {
|
|
153
|
+
const child = group.children[0];
|
|
154
|
+
if (child instanceof TextNode && child.text.length > 0) {
|
|
155
|
+
// Overlay with combining character long solidus
|
|
156
|
+
child.text = child.text.slice(0, 1) + "\u0338" +
|
|
157
|
+
child.text.slice(1);
|
|
158
|
+
groups.pop();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
148
161
|
}
|
|
149
162
|
}
|
|
150
163
|
groups.push(group);
|
|
151
164
|
lastGroup = group;
|
|
152
165
|
}
|
|
153
|
-
|
|
154
|
-
// TODO(kevinb): combine \\not with mrels and mords
|
|
155
|
-
|
|
156
166
|
return groups;
|
|
157
167
|
};
|
|
158
168
|
|
package/src/domTree.js
CHANGED
|
@@ -264,6 +264,69 @@ export class Anchor implements HtmlDomNode {
|
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
+
/**
|
|
268
|
+
* This node represents an image embed (<img>) element.
|
|
269
|
+
*/
|
|
270
|
+
export class Img implements VirtualNode {
|
|
271
|
+
src: string;
|
|
272
|
+
alt: string;
|
|
273
|
+
classes: string[];
|
|
274
|
+
height: number;
|
|
275
|
+
depth: number;
|
|
276
|
+
maxFontSize: number;
|
|
277
|
+
style: CssStyle;
|
|
278
|
+
|
|
279
|
+
constructor(
|
|
280
|
+
src: string,
|
|
281
|
+
alt: string,
|
|
282
|
+
style: CssStyle,
|
|
283
|
+
) {
|
|
284
|
+
this.alt = alt;
|
|
285
|
+
this.src = src;
|
|
286
|
+
this.classes = ["mord"];
|
|
287
|
+
this.style = style;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
hasClass(className: string): boolean {
|
|
291
|
+
return utils.contains(this.classes, className);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
toNode(): Node {
|
|
295
|
+
const node = document.createElement("img");
|
|
296
|
+
node.src = this.src;
|
|
297
|
+
node.alt = this.alt;
|
|
298
|
+
node.className = "mord";
|
|
299
|
+
|
|
300
|
+
// Apply inline styles
|
|
301
|
+
for (const style in this.style) {
|
|
302
|
+
if (this.style.hasOwnProperty(style)) {
|
|
303
|
+
// $FlowFixMe
|
|
304
|
+
node.style[style] = this.style[style];
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return node;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
toMarkup(): string {
|
|
312
|
+
let markup = `<img src='${this.src} 'alt='${this.alt}' `;
|
|
313
|
+
|
|
314
|
+
// Add the styles, after hyphenation
|
|
315
|
+
let styles = "";
|
|
316
|
+
for (const style in this.style) {
|
|
317
|
+
if (this.style.hasOwnProperty(style)) {
|
|
318
|
+
styles += `${utils.hyphenate(style)}:${this.style[style]};`;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (styles) {
|
|
322
|
+
markup += ` style="${utils.escape(styles)}"`;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
markup += "'/>";
|
|
326
|
+
return markup;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
267
330
|
const iCombinations = {
|
|
268
331
|
'î': '\u0131\u0302',
|
|
269
332
|
'ï': '\u0131\u0308',
|
|
@@ -25,6 +25,9 @@ export type AlignSpec = { type: "separator", separator: string } | {
|
|
|
25
25
|
postgap?: number,
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
+
// Type to indicate column separation in MathML
|
|
29
|
+
export type ColSeparationType = "align" | "alignat";
|
|
30
|
+
|
|
28
31
|
function getHLines(parser: Parser): boolean[] {
|
|
29
32
|
// Return an array. The array length = number of hlines.
|
|
30
33
|
// Each element in the array tells if the line is dashed.
|
|
@@ -48,11 +51,12 @@ function getHLines(parser: Parser): boolean[] {
|
|
|
48
51
|
*/
|
|
49
52
|
function parseArray(
|
|
50
53
|
parser: Parser,
|
|
51
|
-
{hskipBeforeAndAfter, addJot, cols, arraystretch}: {|
|
|
54
|
+
{hskipBeforeAndAfter, addJot, cols, arraystretch, colSeparationType}: {|
|
|
52
55
|
hskipBeforeAndAfter?: boolean,
|
|
53
56
|
addJot?: boolean,
|
|
54
57
|
cols?: AlignSpec[],
|
|
55
58
|
arraystretch?: number,
|
|
59
|
+
colSeparationType?: ColSeparationType,
|
|
56
60
|
|},
|
|
57
61
|
style: StyleStr,
|
|
58
62
|
): ParseNode<"array"> {
|
|
@@ -138,6 +142,7 @@ function parseArray(
|
|
|
138
142
|
rowGaps,
|
|
139
143
|
hskipBeforeAndAfter,
|
|
140
144
|
hLinesBeforeRow,
|
|
145
|
+
colSeparationType,
|
|
141
146
|
};
|
|
142
147
|
}
|
|
143
148
|
|
|
@@ -367,8 +372,14 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
|
|
367
372
|
return buildCommon.makeSpan(["mord"], [body], options);
|
|
368
373
|
};
|
|
369
374
|
|
|
375
|
+
const alignMap = {
|
|
376
|
+
c: "center ",
|
|
377
|
+
l: "left ",
|
|
378
|
+
r: "right ",
|
|
379
|
+
};
|
|
380
|
+
|
|
370
381
|
const mathmlBuilder: MathMLBuilder<"array"> = function(group, options) {
|
|
371
|
-
|
|
382
|
+
const table = new mathMLTree.MathNode(
|
|
372
383
|
"mtable", group.body.map(function(row) {
|
|
373
384
|
return new mathMLTree.MathNode(
|
|
374
385
|
"mtr", row.map(function(cell) {
|
|
@@ -376,6 +387,110 @@ const mathmlBuilder: MathMLBuilder<"array"> = function(group, options) {
|
|
|
376
387
|
"mtd", [mml.buildGroup(cell, options)]);
|
|
377
388
|
}));
|
|
378
389
|
}));
|
|
390
|
+
|
|
391
|
+
// Set column alignment, row spacing, column spacing, and
|
|
392
|
+
// array lines by setting attributes on the table element.
|
|
393
|
+
|
|
394
|
+
// Set the row spacing. In MathML, we specify a gap distance.
|
|
395
|
+
// We do not use rowGap[] because MathML automatically increases
|
|
396
|
+
// cell height with the height/depth of the element content.
|
|
397
|
+
|
|
398
|
+
// LaTeX \arraystretch multiplies the row baseline-to-baseline distance.
|
|
399
|
+
// We simulate this by adding (arraystretch - 1)em to the gap. This
|
|
400
|
+
// does a reasonable job of adjusting arrays containing 1 em tall content.
|
|
401
|
+
|
|
402
|
+
// The 0.16 and 0.09 values are found emprically. They produce an array
|
|
403
|
+
// similar to LaTeX and in which content does not interfere with \hines.
|
|
404
|
+
const gap = 0.16 + group.arraystretch - 1 + (group.addJot ? 0.09 : 0);
|
|
405
|
+
table.setAttribute("rowspacing", gap + "em");
|
|
406
|
+
|
|
407
|
+
// MathML table lines go only between cells.
|
|
408
|
+
// To place a line on an edge we'll use <menclose>, if necessary.
|
|
409
|
+
let menclose = "";
|
|
410
|
+
let align = "";
|
|
411
|
+
|
|
412
|
+
if (group.cols) {
|
|
413
|
+
// Find column alignment, column spacing, and vertical lines.
|
|
414
|
+
const cols = group.cols;
|
|
415
|
+
let columnLines = "";
|
|
416
|
+
let prevTypeWasAlign = false;
|
|
417
|
+
let iStart = 0;
|
|
418
|
+
let iEnd = cols.length;
|
|
419
|
+
|
|
420
|
+
if (cols[0].type === "separator") {
|
|
421
|
+
menclose += "top ";
|
|
422
|
+
iStart = 1;
|
|
423
|
+
}
|
|
424
|
+
if (cols[cols.length - 1].type === "separator") {
|
|
425
|
+
menclose += "bottom ";
|
|
426
|
+
iEnd -= 1;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
for (let i = iStart; i < iEnd; i++) {
|
|
430
|
+
if (cols[i].type === "align") {
|
|
431
|
+
align += alignMap[cols[i].align];
|
|
432
|
+
|
|
433
|
+
if (prevTypeWasAlign) {
|
|
434
|
+
columnLines += "none ";
|
|
435
|
+
}
|
|
436
|
+
prevTypeWasAlign = true;
|
|
437
|
+
} else if (cols[i].type === "separator") {
|
|
438
|
+
// MathML accepts only single lines between cells.
|
|
439
|
+
// So we read only the first of consecutive separators.
|
|
440
|
+
if (prevTypeWasAlign) {
|
|
441
|
+
columnLines += cols[i].separator === "|"
|
|
442
|
+
? "solid "
|
|
443
|
+
: "dashed ";
|
|
444
|
+
prevTypeWasAlign = false;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
table.setAttribute("columnalign", align.trim());
|
|
450
|
+
|
|
451
|
+
if (/[sd]/.test(columnLines)) {
|
|
452
|
+
table.setAttribute("columnlines", columnLines.trim());
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Set column spacing.
|
|
457
|
+
if (group.colSeparationType === "align") {
|
|
458
|
+
const cols = group.cols || [];
|
|
459
|
+
let spacing = "";
|
|
460
|
+
for (let i = 1; i < cols.length; i++) {
|
|
461
|
+
spacing += i % 2 ? "0em " : "1em ";
|
|
462
|
+
}
|
|
463
|
+
table.setAttribute("columnspacing", spacing.trim());
|
|
464
|
+
} else if (group.colSeparationType === "alignat") {
|
|
465
|
+
table.setAttribute("columnspacing", "0em");
|
|
466
|
+
} else {
|
|
467
|
+
table.setAttribute("columnspacing", "1em");
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// Address \hline and \hdashline
|
|
471
|
+
let rowLines = "";
|
|
472
|
+
const hlines = group.hLinesBeforeRow;
|
|
473
|
+
|
|
474
|
+
menclose += hlines[0].length > 0 ? "left " : "";
|
|
475
|
+
menclose += hlines[hlines.length - 1].length > 0 ? "right " : "";
|
|
476
|
+
|
|
477
|
+
for (let i = 1; i < hlines.length - 1; i++) {
|
|
478
|
+
rowLines += (hlines[i].length === 0)
|
|
479
|
+
? "none "
|
|
480
|
+
// MathML accepts only a single line between rows. Read one element.
|
|
481
|
+
: hlines[i][0] ? "dashed " : "solid ";
|
|
482
|
+
}
|
|
483
|
+
if (/[sd]/.test(rowLines)) {
|
|
484
|
+
table.setAttribute("rowlines", rowLines.trim());
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (menclose === "") {
|
|
488
|
+
return table;
|
|
489
|
+
} else {
|
|
490
|
+
const wrapper = new mathMLTree.MathNode("menclose", [table]);
|
|
491
|
+
wrapper.setAttribute("notation", menclose.trim());
|
|
492
|
+
return wrapper;
|
|
493
|
+
}
|
|
379
494
|
};
|
|
380
495
|
|
|
381
496
|
// Convenience function for aligned and alignedat environments.
|
|
@@ -448,6 +563,7 @@ const alignedHandler = function(context, args) {
|
|
|
448
563
|
postgap: 0,
|
|
449
564
|
};
|
|
450
565
|
}
|
|
566
|
+
res.colSeparationType = isAligned ? "align" : "alignat";
|
|
451
567
|
return res;
|
|
452
568
|
};
|
|
453
569
|
|
package/src/fontMetrics.js
CHANGED
|
@@ -211,10 +211,11 @@ export function getCharacterMetrics(
|
|
|
211
211
|
throw new Error(`Font metrics not found for font: ${font}.`);
|
|
212
212
|
}
|
|
213
213
|
let ch = character.charCodeAt(0);
|
|
214
|
-
|
|
214
|
+
let metrics = metricMap[font][ch];
|
|
215
|
+
if (!metrics && character[0] in extraCharacterMap) {
|
|
215
216
|
ch = extraCharacterMap[character[0]].charCodeAt(0);
|
|
217
|
+
metrics = metricMap[font][ch];
|
|
216
218
|
}
|
|
217
|
-
let metrics = metricMap[font][ch];
|
|
218
219
|
|
|
219
220
|
if (!metrics && mode === 'text') {
|
|
220
221
|
// We don't typically have font metrics for Asian scripts.
|
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"],
|
|
@@ -318,9 +318,19 @@ defineFunction({
|
|
|
318
318
|
return middleDelim;
|
|
319
319
|
},
|
|
320
320
|
mathmlBuilder: (group, options) => {
|
|
321
|
-
|
|
322
|
-
|
|
321
|
+
// A Firefox \middle will strech a character vertically only if it
|
|
322
|
+
// is in the fence part of the operator dictionary at:
|
|
323
|
+
// https://www.w3.org/TR/MathML3/appendixc.html.
|
|
324
|
+
// So we need to avoid U+2223 and use plain "|" instead.
|
|
325
|
+
const textNode = (group.delim === "\\vert" || group.delim === "|")
|
|
326
|
+
? mml.makeText("|", "text")
|
|
327
|
+
: mml.makeText(group.delim, group.mode);
|
|
328
|
+
const middleNode = new mathMLTree.MathNode("mo", [textNode]);
|
|
323
329
|
middleNode.setAttribute("fence", "true");
|
|
330
|
+
// MathML gives 5/18em spacing to each <mo> element.
|
|
331
|
+
// \middle should get delimiter spacing instead.
|
|
332
|
+
middleNode.setAttribute("lspace", "0.05em");
|
|
333
|
+
middleNode.setAttribute("rspace", "0.05em");
|
|
324
334
|
return middleNode;
|
|
325
335
|
},
|
|
326
336
|
});
|
package/src/functions/enclose.js
CHANGED
|
@@ -112,7 +112,9 @@ const htmlBuilder = (group, options) => {
|
|
|
112
112
|
|
|
113
113
|
const mathmlBuilder = (group, options) => {
|
|
114
114
|
const node = new mathMLTree.MathNode(
|
|
115
|
-
|
|
115
|
+
(group.label.indexOf("colorbox") > -1) ? "mpadded" : "menclose",
|
|
116
|
+
[mml.buildGroup(group.body, options)]
|
|
117
|
+
);
|
|
116
118
|
switch (group.label) {
|
|
117
119
|
case "\\cancel":
|
|
118
120
|
node.setAttribute("notation", "updiagonalstrike");
|
|
@@ -127,8 +129,18 @@ const mathmlBuilder = (group, options) => {
|
|
|
127
129
|
node.setAttribute("notation", "box");
|
|
128
130
|
break;
|
|
129
131
|
case "\\fcolorbox":
|
|
130
|
-
|
|
131
|
-
|
|
132
|
+
case "\\colorbox":
|
|
133
|
+
// <menclose> doesn't have a good notation option. So use <mpadded>
|
|
134
|
+
// instead. Set some attributes that come included with <menclose>.
|
|
135
|
+
node.setAttribute("width", "+6pt");
|
|
136
|
+
node.setAttribute("height", "+6pt");
|
|
137
|
+
node.setAttribute("lspace", "3pt"); // LaTeX source2e: \fboxsep = 3pt
|
|
138
|
+
node.setAttribute("voffset", "3pt");
|
|
139
|
+
if (group.label === "\\fcolorbox") {
|
|
140
|
+
const thk = options.fontMetrics().defaultRuleThickness;
|
|
141
|
+
node.setAttribute("style", "border: " + thk + "em solid " +
|
|
142
|
+
String(group.borderColor));
|
|
143
|
+
}
|
|
132
144
|
break;
|
|
133
145
|
case "\\xcancel":
|
|
134
146
|
node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
|
package/src/functions/genfrac.js
CHANGED
|
@@ -11,22 +11,29 @@ 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
|
|