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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "katex",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Fast math typesetting for the web.",
|
|
5
5
|
"main": "dist/katex.js",
|
|
6
6
|
"homepage": "https://katex.org",
|
|
@@ -28,10 +28,11 @@
|
|
|
28
28
|
"babel-jest": "^24.1.0",
|
|
29
29
|
"babel-loader": "^8.0.5",
|
|
30
30
|
"babel-plugin-istanbul": "^5.1.1",
|
|
31
|
+
"babel-plugin-preval": "^3.0.1",
|
|
31
32
|
"babel-plugin-version-inline": "^1.0.0",
|
|
32
33
|
"benchmark": "^2.1.4",
|
|
33
|
-
"browserslist": "^4.
|
|
34
|
-
"caniuse-lite": "^1.0.
|
|
34
|
+
"browserslist": "^4.7.1",
|
|
35
|
+
"caniuse-lite": "^1.0.30001002",
|
|
35
36
|
"codecov": "^3.2.0",
|
|
36
37
|
"css-loader": "^3.0.0",
|
|
37
38
|
"cssnano": "^4.1.10",
|
|
@@ -75,7 +76,7 @@
|
|
|
75
76
|
},
|
|
76
77
|
"bin": "cli.js",
|
|
77
78
|
"scripts": {
|
|
78
|
-
"test": "yarn
|
|
79
|
+
"test": "yarn test:lint && yarn test:flow && yarn test:jest",
|
|
79
80
|
"test:lint": "yarn test:lint:js && yarn test:lint:css",
|
|
80
81
|
"test:lint:js": "eslint *.js src static test contrib dockers website",
|
|
81
82
|
"test:lint:css": "stylelint src/katex.less static/main.css contrib/**/*.css website/static/**/*.css",
|
|
@@ -85,14 +86,13 @@
|
|
|
85
86
|
"test:jest:update": "jest --updateSnapshot",
|
|
86
87
|
"test:jest:coverage": "jest --coverage",
|
|
87
88
|
"test:screenshots": "yarn test:screenshots:update --verify",
|
|
88
|
-
"test:screenshots:update": "
|
|
89
|
-
"test:perf": "
|
|
89
|
+
"test:screenshots:update": "dockers/screenshotter/screenshotter.sh",
|
|
90
|
+
"test:perf": "NODE_ENV=test node test/perf-test.js",
|
|
90
91
|
"clean": "rm -rf dist/ node_modules/",
|
|
91
92
|
"clean-install": "yarn clean && yarn",
|
|
92
|
-
"prestart": "node src/unicodeMake.js",
|
|
93
93
|
"start": "webpack-dev-server --hot --config webpack.dev.js",
|
|
94
94
|
"analyze": "webpack --config webpack.analyze.js",
|
|
95
|
-
"build": "
|
|
95
|
+
"build": "rimraf dist/ && mkdirp dist && cp README.md dist && rollup -c && webpack",
|
|
96
96
|
"watch": "yarn build --watch",
|
|
97
97
|
"dist": "yarn test && yarn build && yarn dist:zip",
|
|
98
98
|
"dist:zip": "rimraf katex/ katex.tar.gz katex.zip && cp -R dist katex && tar czf katex.tar.gz katex && zip -rq katex.zip katex && rimraf katex/"
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"collectCoverageFrom": [
|
|
112
112
|
"src/**/*.js",
|
|
113
113
|
"contrib/**/*.js",
|
|
114
|
-
"!src/
|
|
114
|
+
"!src/unicodeSymbols.js",
|
|
115
115
|
"!contrib/mhchem/**"
|
|
116
116
|
],
|
|
117
117
|
"setupFilesAfterEnv": [
|
package/src/MacroExpander.js
CHANGED
|
@@ -180,13 +180,19 @@ export default class MacroExpander implements MacroContextInterface {
|
|
|
180
180
|
* At the moment, macro expansion doesn't handle delimited macros,
|
|
181
181
|
* i.e. things like those defined by \def\foo#1\end{…}.
|
|
182
182
|
* See the TeX book page 202ff. for details on how those should behave.
|
|
183
|
+
*
|
|
184
|
+
* If expandableOnly, only expandable tokens are expanded and
|
|
185
|
+
* an undefined control sequence results in an error.
|
|
183
186
|
*/
|
|
184
|
-
expandOnce(): Token | Token[] {
|
|
187
|
+
expandOnce(expandableOnly?: boolean): Token | Token[] {
|
|
185
188
|
const topToken = this.popToken();
|
|
186
189
|
const name = topToken.text;
|
|
187
|
-
const expansion = this._getExpansion(name);
|
|
188
|
-
if (expansion == null
|
|
189
|
-
|
|
190
|
+
const expansion = !topToken.noexpand ? this._getExpansion(name) : null;
|
|
191
|
+
if (expansion == null || (expandableOnly && expansion.unexpandable)) {
|
|
192
|
+
if (expandableOnly && expansion == null &&
|
|
193
|
+
name[0] === "\\" && !this.isDefined(name)) {
|
|
194
|
+
throw new ParseError("Undefined control sequence: " + name);
|
|
195
|
+
}
|
|
190
196
|
this.pushToken(topToken);
|
|
191
197
|
return topToken;
|
|
192
198
|
}
|
|
@@ -248,7 +254,9 @@ export default class MacroExpander implements MacroContextInterface {
|
|
|
248
254
|
if (expanded instanceof Token) {
|
|
249
255
|
// \relax stops the expansion, but shouldn't get returned (a
|
|
250
256
|
// null return value couldn't get implemented as a function).
|
|
251
|
-
|
|
257
|
+
// the token after \noexpand is interpreted as if its meaning
|
|
258
|
+
// were ‘\relax’
|
|
259
|
+
if (expanded.text === "\\relax" || expanded.treatAsRelax) {
|
|
252
260
|
this.stack.pop();
|
|
253
261
|
} else {
|
|
254
262
|
return this.stack.pop(); // === expanded
|
|
@@ -266,16 +274,26 @@ export default class MacroExpander implements MacroContextInterface {
|
|
|
266
274
|
* tokens, or return `undefined` if no such macro is defined.
|
|
267
275
|
*/
|
|
268
276
|
expandMacro(name: string): Token[] | void {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
277
|
+
return this.macros.has(name)
|
|
278
|
+
? this.expandTokens([new Token(name)]) : undefined;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Fully expand the given token stream and return the resulting list of tokens
|
|
283
|
+
*/
|
|
284
|
+
expandTokens(tokens: Token[]): Token[] {
|
|
272
285
|
const output = [];
|
|
273
286
|
const oldStackLength = this.stack.length;
|
|
274
|
-
this.
|
|
287
|
+
this.pushTokens(tokens);
|
|
275
288
|
while (this.stack.length > oldStackLength) {
|
|
276
|
-
const expanded = this.expandOnce();
|
|
289
|
+
const expanded = this.expandOnce(true); // expand only expandable tokens
|
|
277
290
|
// expandOnce returns Token if and only if it's fully expanded.
|
|
278
291
|
if (expanded instanceof Token) {
|
|
292
|
+
if (expanded.treatAsRelax) {
|
|
293
|
+
// the expansion of \noexpand is the token itself
|
|
294
|
+
expanded.noexpand = false;
|
|
295
|
+
expanded.treatAsRelax = false;
|
|
296
|
+
}
|
|
279
297
|
output.push(this.stack.pop());
|
|
280
298
|
}
|
|
281
299
|
}
|
|
@@ -342,4 +360,15 @@ export default class MacroExpander implements MacroContextInterface {
|
|
|
342
360
|
symbols.text.hasOwnProperty(name) ||
|
|
343
361
|
implicitCommands.hasOwnProperty(name);
|
|
344
362
|
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Determine whether a command is expandable.
|
|
366
|
+
*/
|
|
367
|
+
isExpandable(name: string): boolean {
|
|
368
|
+
const macro = this.macros.get(name);
|
|
369
|
+
return macro != null ? typeof macro === "string"
|
|
370
|
+
|| typeof macro === "function" || !macro.unexpandable
|
|
371
|
+
// TODO(ylem): #2085
|
|
372
|
+
: functions.hasOwnProperty(name)/* && !functions[name].primitive*/;
|
|
373
|
+
}
|
|
345
374
|
}
|
package/src/Parser.js
CHANGED
|
@@ -5,14 +5,16 @@ import MacroExpander, {implicitCommands} from "./MacroExpander";
|
|
|
5
5
|
import symbols, {ATOMS, extraLatin} from "./symbols";
|
|
6
6
|
import {validUnit} from "./units";
|
|
7
7
|
import {supportedCodepoint} from "./unicodeScripts";
|
|
8
|
-
import unicodeAccents from "./unicodeAccents";
|
|
9
|
-
import unicodeSymbols from "./unicodeSymbols";
|
|
10
|
-
import {checkNodeType} from "./parseNode";
|
|
11
8
|
import ParseError from "./ParseError";
|
|
12
9
|
import {combiningDiacriticalMarksEndRegex} from "./Lexer";
|
|
13
10
|
import Settings from "./Settings";
|
|
14
11
|
import SourceLocation from "./SourceLocation";
|
|
15
12
|
import {Token} from "./Token";
|
|
13
|
+
|
|
14
|
+
// Pre-evaluate both modules as unicodeSymbols require String.normalize()
|
|
15
|
+
import unicodeAccents from /*preval*/ "./unicodeAccents";
|
|
16
|
+
import unicodeSymbols from /*preval*/ "./unicodeSymbols";
|
|
17
|
+
|
|
16
18
|
import type {ParseNode, AnyParseNode, SymbolParseNode, UnsupportedCmdParseNode}
|
|
17
19
|
from "./parseNode";
|
|
18
20
|
import type {Atom, Group} from "./symbols";
|
|
@@ -115,9 +117,11 @@ export default class Parser {
|
|
|
115
117
|
* Main parsing function, which parses an entire input.
|
|
116
118
|
*/
|
|
117
119
|
parse(): AnyParseNode[] {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
120
|
+
if (!this.settings.globalGroup) {
|
|
121
|
+
// Create a group namespace for the math expression.
|
|
122
|
+
// (LaTeX creates a new group for every $...$, $$...$$, \[...\].)
|
|
123
|
+
this.gullet.beginGroup();
|
|
124
|
+
}
|
|
121
125
|
|
|
122
126
|
// Use old \color behavior (same as LaTeX's \textcolor) if requested.
|
|
123
127
|
// We do this within the group for the math expression, so it doesn't
|
|
@@ -133,7 +137,9 @@ export default class Parser {
|
|
|
133
137
|
this.expect("EOF");
|
|
134
138
|
|
|
135
139
|
// End the group namespace for the expression
|
|
136
|
-
this.
|
|
140
|
+
if (!this.settings.globalGroup) {
|
|
141
|
+
this.gullet.endGroup();
|
|
142
|
+
}
|
|
137
143
|
return parse;
|
|
138
144
|
}
|
|
139
145
|
|
|
@@ -181,6 +187,8 @@ export default class Parser {
|
|
|
181
187
|
const atom = this.parseAtom(breakOnTokenText);
|
|
182
188
|
if (!atom) {
|
|
183
189
|
break;
|
|
190
|
+
} else if (atom.type === "internal") {
|
|
191
|
+
continue;
|
|
184
192
|
}
|
|
185
193
|
body.push(atom);
|
|
186
194
|
}
|
|
@@ -202,15 +210,14 @@ export default class Parser {
|
|
|
202
210
|
let funcName;
|
|
203
211
|
|
|
204
212
|
for (let i = 0; i < body.length; i++) {
|
|
205
|
-
|
|
206
|
-
if (node) {
|
|
213
|
+
if (body[i].type === "infix") {
|
|
207
214
|
if (overIndex !== -1) {
|
|
208
215
|
throw new ParseError(
|
|
209
216
|
"only one infix operator per group",
|
|
210
|
-
|
|
217
|
+
body[i].token);
|
|
211
218
|
}
|
|
212
219
|
overIndex = i;
|
|
213
|
-
funcName =
|
|
220
|
+
funcName = body[i].replaceWith;
|
|
214
221
|
}
|
|
215
222
|
}
|
|
216
223
|
|
|
@@ -325,21 +332,18 @@ export default class Parser {
|
|
|
325
332
|
|
|
326
333
|
if (lex.text === "\\limits" || lex.text === "\\nolimits") {
|
|
327
334
|
// We got a limit control
|
|
328
|
-
|
|
329
|
-
if (opNode) {
|
|
335
|
+
if (base && base.type === "op") {
|
|
330
336
|
const limits = lex.text === "\\limits";
|
|
331
|
-
|
|
332
|
-
|
|
337
|
+
base.limits = limits;
|
|
338
|
+
base.alwaysHandleSupSub = true;
|
|
339
|
+
} else if (base && base.type === "operatorname"
|
|
340
|
+
&& base.alwaysHandleSupSub) {
|
|
341
|
+
const limits = lex.text === "\\limits";
|
|
342
|
+
base.limits = limits;
|
|
333
343
|
} else {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
opNode.limits = limits;
|
|
338
|
-
} else {
|
|
339
|
-
throw new ParseError(
|
|
340
|
-
"Limit controls must follow a math operator",
|
|
341
|
-
lex);
|
|
342
|
-
}
|
|
344
|
+
throw new ParseError(
|
|
345
|
+
"Limit controls must follow a math operator",
|
|
346
|
+
lex);
|
|
343
347
|
}
|
|
344
348
|
this.consume();
|
|
345
349
|
} else if (lex.text === "^") {
|
package/src/Settings.js
CHANGED
|
@@ -32,6 +32,22 @@ export type TrustContextTypes = {
|
|
|
32
32
|
url: string,
|
|
33
33
|
protocol?: string,
|
|
34
34
|
|},
|
|
35
|
+
"\\htmlClass": {|
|
|
36
|
+
command: "\\htmlClass",
|
|
37
|
+
class: string,
|
|
38
|
+
|},
|
|
39
|
+
"\\htmlId": {|
|
|
40
|
+
command: "\\htmlId",
|
|
41
|
+
id: string,
|
|
42
|
+
|},
|
|
43
|
+
"\\htmlStyle": {|
|
|
44
|
+
command: "\\htmlStyle",
|
|
45
|
+
style: string,
|
|
46
|
+
|},
|
|
47
|
+
"\\htmlData": {|
|
|
48
|
+
command: "\\htmlData",
|
|
49
|
+
attributes: {[string]: string},
|
|
50
|
+
|},
|
|
35
51
|
};
|
|
36
52
|
export type AnyTrustContext = $Values<TrustContextTypes>;
|
|
37
53
|
export type TrustFunction = (context: AnyTrustContext) => ?boolean;
|
|
@@ -50,6 +66,7 @@ export type SettingsOptions = {
|
|
|
50
66
|
trust?: boolean | TrustFunction;
|
|
51
67
|
maxSize?: number;
|
|
52
68
|
maxExpand?: number;
|
|
69
|
+
globalGroup?: boolean;
|
|
53
70
|
};
|
|
54
71
|
|
|
55
72
|
/**
|
|
@@ -76,6 +93,7 @@ export default class Settings {
|
|
|
76
93
|
trust: boolean | TrustFunction;
|
|
77
94
|
maxSize: number;
|
|
78
95
|
maxExpand: number;
|
|
96
|
+
globalGroup: boolean;
|
|
79
97
|
|
|
80
98
|
constructor(options: SettingsOptions) {
|
|
81
99
|
// allow null options
|
|
@@ -96,6 +114,7 @@ export default class Settings {
|
|
|
96
114
|
this.trust = utils.deflt(options.trust, false);
|
|
97
115
|
this.maxSize = Math.max(0, utils.deflt(options.maxSize, Infinity));
|
|
98
116
|
this.maxExpand = Math.max(0, utils.deflt(options.maxExpand, 1000));
|
|
117
|
+
this.globalGroup = utils.deflt(options.globalGroup, false);
|
|
99
118
|
}
|
|
100
119
|
|
|
101
120
|
/**
|
package/src/Token.js
CHANGED
|
@@ -23,6 +23,8 @@ export interface LexerInterface {input: string, tokenRegex: RegExp}
|
|
|
23
23
|
export class Token {
|
|
24
24
|
text: string;
|
|
25
25
|
loc: ?SourceLocation;
|
|
26
|
+
noexpand: ?boolean; // don't expand the token
|
|
27
|
+
treatAsRelax: ?boolean; // used in \noexpand
|
|
26
28
|
|
|
27
29
|
constructor(
|
|
28
30
|
text: string, // the text of this token
|
package/src/buildCommon.js
CHANGED
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
import {SymbolNode, Anchor, Span, PathNode, SvgNode, createClass} from "./domTree";
|
|
9
9
|
import {getCharacterMetrics} from "./fontMetrics";
|
|
10
10
|
import symbols, {ligatures} from "./symbols";
|
|
11
|
-
import utils from "./utils";
|
|
12
11
|
import {wideCharacterFont} from "./wide-character";
|
|
13
12
|
import {calculateSize} from "./units";
|
|
14
13
|
import {DocumentFragment} from "./tree";
|
|
@@ -21,13 +20,6 @@ import type {documentFragment as HtmlDocumentFragment} from "./domTree";
|
|
|
21
20
|
import type {HtmlDomNode, DomSpan, SvgSpan, CssStyle} from "./domTree";
|
|
22
21
|
import type {Measurement} from "./units";
|
|
23
22
|
|
|
24
|
-
// The following have to be loaded from Main-Italic font, using class mathit
|
|
25
|
-
const mathitLetters = [
|
|
26
|
-
"\\imath", "ı", // dotless i
|
|
27
|
-
"\\jmath", "ȷ", // dotless j
|
|
28
|
-
"\\pounds", "\\mathsterling", "\\textsterling", "£", // pounds symbol
|
|
29
|
-
];
|
|
30
|
-
|
|
31
23
|
/**
|
|
32
24
|
* Looks up the given symbol in fontMetrics, after applying any symbol
|
|
33
25
|
* replacements defined in symbol.js
|
|
@@ -128,63 +120,6 @@ const mathsym = function(
|
|
|
128
120
|
}
|
|
129
121
|
};
|
|
130
122
|
|
|
131
|
-
/**
|
|
132
|
-
* Determines which of the two font names (Main-Italic and Math-Italic) and
|
|
133
|
-
* corresponding style tags (maindefault or mathit) to use for default math font,
|
|
134
|
-
* depending on the symbol.
|
|
135
|
-
*/
|
|
136
|
-
const mathdefault = function(
|
|
137
|
-
value: string,
|
|
138
|
-
mode: Mode,
|
|
139
|
-
options: Options,
|
|
140
|
-
classes: string[],
|
|
141
|
-
): {| fontName: string, fontClass: string |} {
|
|
142
|
-
if (/[0-9]/.test(value.charAt(0)) ||
|
|
143
|
-
// glyphs for \imath and \jmath do not exist in Math-Italic so we
|
|
144
|
-
// need to use Main-Italic instead
|
|
145
|
-
utils.contains(mathitLetters, value)) {
|
|
146
|
-
return {
|
|
147
|
-
fontName: "Main-Italic",
|
|
148
|
-
fontClass: "mathit",
|
|
149
|
-
};
|
|
150
|
-
} else {
|
|
151
|
-
return {
|
|
152
|
-
fontName: "Math-Italic",
|
|
153
|
-
fontClass: "mathdefault",
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Determines which of the font names (Main-Italic, Math-Italic, and Caligraphic)
|
|
160
|
-
* and corresponding style tags (mathit, mathdefault, or mathcal) to use for font
|
|
161
|
-
* "mathnormal", depending on the symbol. Use this function instead of fontMap for
|
|
162
|
-
* font "mathnormal".
|
|
163
|
-
*/
|
|
164
|
-
const mathnormal = function(
|
|
165
|
-
value: string,
|
|
166
|
-
mode: Mode,
|
|
167
|
-
options: Options,
|
|
168
|
-
classes: string[],
|
|
169
|
-
): {| fontName: string, fontClass: string |} {
|
|
170
|
-
if (utils.contains(mathitLetters, value)) {
|
|
171
|
-
return {
|
|
172
|
-
fontName: "Main-Italic",
|
|
173
|
-
fontClass: "mathit",
|
|
174
|
-
};
|
|
175
|
-
} else if (/[0-9]/.test(value.charAt(0))) {
|
|
176
|
-
return {
|
|
177
|
-
fontName: "Caligraphic-Regular",
|
|
178
|
-
fontClass: "mathcal",
|
|
179
|
-
};
|
|
180
|
-
} else {
|
|
181
|
-
return {
|
|
182
|
-
fontName: "Math-Italic",
|
|
183
|
-
fontClass: "mathdefault",
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
|
|
188
123
|
/**
|
|
189
124
|
* Determines which of the two font names (Main-Bold and Math-BoldItalic) and
|
|
190
125
|
* corresponding style tags (mathbf or boldsymbol) to use for font "boldsymbol",
|
|
@@ -196,8 +131,10 @@ const boldsymbol = function(
|
|
|
196
131
|
mode: Mode,
|
|
197
132
|
options: Options,
|
|
198
133
|
classes: string[],
|
|
134
|
+
type: "mathord" | "textord",
|
|
199
135
|
): {| fontName: string, fontClass: string |} {
|
|
200
|
-
if (
|
|
136
|
+
if (type !== "textord" &&
|
|
137
|
+
lookupSymbol(value, "Math-BoldItalic", mode).metrics) {
|
|
201
138
|
return {
|
|
202
139
|
fontName: "Math-BoldItalic",
|
|
203
140
|
fontClass: "boldsymbol",
|
|
@@ -236,15 +173,10 @@ const makeOrd = function<NODETYPE: "spacing" | "mathord" | "textord">(
|
|
|
236
173
|
} else if (fontOrFamily) {
|
|
237
174
|
let fontName;
|
|
238
175
|
let fontClasses;
|
|
239
|
-
if (fontOrFamily === "boldsymbol"
|
|
240
|
-
const fontData =
|
|
241
|
-
? boldsymbol(text, mode, options, classes)
|
|
242
|
-
: mathnormal(text, mode, options, classes);
|
|
176
|
+
if (fontOrFamily === "boldsymbol") {
|
|
177
|
+
const fontData = boldsymbol(text, mode, options, classes, type);
|
|
243
178
|
fontName = fontData.fontName;
|
|
244
179
|
fontClasses = [fontData.fontClass];
|
|
245
|
-
} else if (utils.contains(mathitLetters, text)) {
|
|
246
|
-
fontName = "Main-Italic";
|
|
247
|
-
fontClasses = ["mathit"];
|
|
248
180
|
} else if (isFont) {
|
|
249
181
|
fontName = fontMap[fontOrFamily].fontName;
|
|
250
182
|
fontClasses = [fontOrFamily];
|
|
@@ -271,9 +203,8 @@ const makeOrd = function<NODETYPE: "spacing" | "mathord" | "textord">(
|
|
|
271
203
|
|
|
272
204
|
// Makes a symbol in the default font for mathords and textords.
|
|
273
205
|
if (type === "mathord") {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
classes.concat([fontLookup.fontClass]));
|
|
206
|
+
return makeSymbol(text, "Math-Italic", mode, options,
|
|
207
|
+
classes.concat(["mathnormal"]));
|
|
277
208
|
} else if (type === "textord") {
|
|
278
209
|
const font = symbols[mode][text] && symbols[mode][text].font;
|
|
279
210
|
if (font === "ams") {
|
|
@@ -752,13 +683,14 @@ const fontMap: {[string]: {| variant: FontVariant, fontName: string |}} = {
|
|
|
752
683
|
variant: "italic",
|
|
753
684
|
fontName: "Main-Italic",
|
|
754
685
|
},
|
|
686
|
+
"mathnormal": {
|
|
687
|
+
variant: "italic",
|
|
688
|
+
fontName: "Math-Italic",
|
|
689
|
+
},
|
|
755
690
|
|
|
756
|
-
//
|
|
757
|
-
//
|
|
758
|
-
//
|
|
759
|
-
// Math-BoldItalic and Main-Bold for "boldsymbol". This is handled by a
|
|
760
|
-
// special case in makeOrd which ends up calling mathdefault, mathnormal,
|
|
761
|
-
// and boldsymbol.
|
|
691
|
+
// "boldsymbol" is missing because they require the use of multiple fonts:
|
|
692
|
+
// Math-BoldItalic and Main-Bold. This is handled by a special case in
|
|
693
|
+
// makeOrd which ends up calling boldsymbol.
|
|
762
694
|
|
|
763
695
|
// families
|
|
764
696
|
"mathbb": {
|
|
@@ -796,6 +728,8 @@ const svgData: {
|
|
|
796
728
|
oiintSize2: ["oiintSize2", 1.472, 0.659],
|
|
797
729
|
oiiintSize1: ["oiiintSize1", 1.304, 0.499],
|
|
798
730
|
oiiintSize2: ["oiiintSize2", 1.98, 0.659],
|
|
731
|
+
leftParenInner: ["leftParenInner", 0.875, 0.3],
|
|
732
|
+
rightParenInner: ["rightParenInner", 0.875, 0.3],
|
|
799
733
|
};
|
|
800
734
|
|
|
801
735
|
const staticSvg = function(value: string, options: Options): SvgSpan {
|
package/src/buildHTML.js
CHANGED
|
@@ -9,9 +9,8 @@
|
|
|
9
9
|
import ParseError from "./ParseError";
|
|
10
10
|
import Style from "./Style";
|
|
11
11
|
import buildCommon from "./buildCommon";
|
|
12
|
-
import {Anchor} from "./domTree";
|
|
12
|
+
import {Span, Anchor} from "./domTree";
|
|
13
13
|
import utils from "./utils";
|
|
14
|
-
import {checkNodeType} from "./parseNode";
|
|
15
14
|
import {spacings, tightSpacings} from "./spacingData";
|
|
16
15
|
import {_htmlGroupBuilders as groupBuilders} from "./defineFunction";
|
|
17
16
|
import {DocumentFragment} from "./tree";
|
|
@@ -60,7 +59,7 @@ type DomType = $Keys<typeof DomEnum>;
|
|
|
60
59
|
export const buildExpression = function(
|
|
61
60
|
expression: AnyParseNode[],
|
|
62
61
|
options: Options,
|
|
63
|
-
isRealGroup: boolean,
|
|
62
|
+
isRealGroup: boolean | "root",
|
|
64
63
|
surrounding: [?DomType, ?DomType] = [null, null],
|
|
65
64
|
): HtmlDomNode[] {
|
|
66
65
|
// Parse expressions into `groups`.
|
|
@@ -83,11 +82,8 @@ export const buildExpression = function(
|
|
|
83
82
|
|
|
84
83
|
let glueOptions = options;
|
|
85
84
|
if (expression.length === 1) {
|
|
86
|
-
const node =
|
|
87
|
-
|
|
88
|
-
if (!node) {
|
|
89
|
-
// No match.
|
|
90
|
-
} else if (node.type === "sizing") {
|
|
85
|
+
const node = expression[0];
|
|
86
|
+
if (node.type === "sizing") {
|
|
91
87
|
glueOptions = options.havingSize(node.size);
|
|
92
88
|
} else if (node.type === "styling") {
|
|
93
89
|
glueOptions = options.havingStyle(styleMap[node.style]);
|
|
@@ -106,6 +102,7 @@ export const buildExpression = function(
|
|
|
106
102
|
|
|
107
103
|
// Before determining what spaces to insert, perform bin cancellation.
|
|
108
104
|
// Binary operators change to ordinary symbols in some contexts.
|
|
105
|
+
const isRoot = (isRealGroup === "root");
|
|
109
106
|
traverseNonSpaceNodes(groups, (node, prev) => {
|
|
110
107
|
const prevType = prev.classes[0];
|
|
111
108
|
const type = node.classes[0];
|
|
@@ -114,7 +111,7 @@ export const buildExpression = function(
|
|
|
114
111
|
} else if (type === "mbin" && utils.contains(binLeftCanceller, prevType)) {
|
|
115
112
|
node.classes[0] = "mord";
|
|
116
113
|
}
|
|
117
|
-
}, {node: dummyPrev}, dummyNext);
|
|
114
|
+
}, {node: dummyPrev}, dummyNext, isRoot);
|
|
118
115
|
|
|
119
116
|
traverseNonSpaceNodes(groups, (node, prev) => {
|
|
120
117
|
const prevType = getTypeOfDomTree(prev);
|
|
@@ -127,7 +124,7 @@ export const buildExpression = function(
|
|
|
127
124
|
if (space) { // Insert glue (spacing) after the `prev`.
|
|
128
125
|
return buildCommon.makeGlue(space, glueOptions);
|
|
129
126
|
}
|
|
130
|
-
}, {node: dummyPrev}, dummyNext);
|
|
127
|
+
}, {node: dummyPrev}, dummyNext, isRoot);
|
|
131
128
|
|
|
132
129
|
return groups;
|
|
133
130
|
};
|
|
@@ -145,6 +142,7 @@ const traverseNonSpaceNodes = function(
|
|
|
145
142
|
insertAfter?: HtmlDomNode => void,
|
|
146
143
|
|},
|
|
147
144
|
next: ?HtmlDomNode,
|
|
145
|
+
isRoot: boolean,
|
|
148
146
|
) {
|
|
149
147
|
if (next) { // temporarily append the right node, if exists
|
|
150
148
|
nodes.push(next);
|
|
@@ -155,27 +153,31 @@ const traverseNonSpaceNodes = function(
|
|
|
155
153
|
const partialGroup = checkPartialGroup(node);
|
|
156
154
|
if (partialGroup) { // Recursive DFS
|
|
157
155
|
// $FlowFixMe: make nodes a $ReadOnlyArray by returning a new array
|
|
158
|
-
traverseNonSpaceNodes(partialGroup.children,
|
|
156
|
+
traverseNonSpaceNodes(partialGroup.children,
|
|
157
|
+
callback, prev, null, isRoot);
|
|
159
158
|
continue;
|
|
160
159
|
}
|
|
161
160
|
|
|
162
161
|
// Ignore explicit spaces (e.g., \;, \,) when determining what implicit
|
|
163
162
|
// spacing should go between atoms of different classes
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
i++;
|
|
163
|
+
const nonspace = !node.hasClass("mspace");
|
|
164
|
+
if (nonspace) {
|
|
165
|
+
const result = callback(node, prev.node);
|
|
166
|
+
if (result) {
|
|
167
|
+
if (prev.insertAfter) {
|
|
168
|
+
prev.insertAfter(result);
|
|
169
|
+
} else { // insert at front
|
|
170
|
+
nodes.unshift(result);
|
|
171
|
+
i++;
|
|
172
|
+
}
|
|
175
173
|
}
|
|
176
174
|
}
|
|
177
175
|
|
|
178
|
-
|
|
176
|
+
if (nonspace) {
|
|
177
|
+
prev.node = node;
|
|
178
|
+
} else if (isRoot && node.hasClass("newline")) {
|
|
179
|
+
prev.node = makeSpan(["leftmost"]); // treat like beginning of line
|
|
180
|
+
}
|
|
179
181
|
prev.insertAfter = (index => n => {
|
|
180
182
|
nodes.splice(index + 1, 0, n);
|
|
181
183
|
i++;
|
|
@@ -189,8 +191,9 @@ const traverseNonSpaceNodes = function(
|
|
|
189
191
|
// Check if given node is a partial group, i.e., does not affect spacing around.
|
|
190
192
|
const checkPartialGroup = function(
|
|
191
193
|
node: HtmlDomNode,
|
|
192
|
-
): ?(DocumentFragment<HtmlDomNode> | Anchor) {
|
|
193
|
-
if (node instanceof DocumentFragment || node instanceof Anchor
|
|
194
|
+
): ?(DocumentFragment<HtmlDomNode> | Anchor | DomSpan) {
|
|
195
|
+
if (node instanceof DocumentFragment || node instanceof Anchor
|
|
196
|
+
|| (node instanceof Span && node.hasClass("enclosing"))) {
|
|
194
197
|
return node;
|
|
195
198
|
}
|
|
196
199
|
return null;
|
|
@@ -292,10 +295,6 @@ function buildHTMLUnbreakable(children, options) {
|
|
|
292
295
|
// Add strut, which ensures that the top of the HTML element falls at
|
|
293
296
|
// the height of the expression, and the bottom of the HTML element
|
|
294
297
|
// falls at the depth of the expression.
|
|
295
|
-
// We used to have separate top and bottom struts, where the bottom strut
|
|
296
|
-
// would like to use `vertical-align: top`, but in IE 9 this lowers the
|
|
297
|
-
// baseline of the box to the bottom of this strut (instead of staying in
|
|
298
|
-
// the normal place) so we use an absolute value for vertical-align instead.
|
|
299
298
|
const strut = makeSpan(["strut"]);
|
|
300
299
|
strut.style.height = (body.height + body.depth) + "em";
|
|
301
300
|
strut.style.verticalAlign = -body.depth + "em";
|
|
@@ -317,7 +316,7 @@ export default function buildHTML(tree: AnyParseNode[], options: Options): DomSp
|
|
|
317
316
|
}
|
|
318
317
|
|
|
319
318
|
// Build the expression contained in the tree
|
|
320
|
-
const expression = buildExpression(tree, options,
|
|
319
|
+
const expression = buildExpression(tree, options, "root");
|
|
321
320
|
|
|
322
321
|
const children = [];
|
|
323
322
|
|
package/src/buildMathML.js
CHANGED
|
@@ -93,7 +93,7 @@ export const getVariant = function(
|
|
|
93
93
|
if (font === "mathit") {
|
|
94
94
|
return "italic";
|
|
95
95
|
} else if (font === "boldsymbol") {
|
|
96
|
-
return "bold-italic";
|
|
96
|
+
return group.type === "textord" ? "bold" : "bold-italic";
|
|
97
97
|
} else if (font === "mathbf") {
|
|
98
98
|
return "bold";
|
|
99
99
|
} else if (font === "mathbb") {
|
|
@@ -238,6 +238,7 @@ export default function buildMathML(
|
|
|
238
238
|
tree: AnyParseNode[],
|
|
239
239
|
texExpression: string,
|
|
240
240
|
options: Options,
|
|
241
|
+
isDisplayMode: boolean,
|
|
241
242
|
forMathmlOnly: boolean,
|
|
242
243
|
): DomSpan {
|
|
243
244
|
const expression = buildExpression(tree, options);
|
|
@@ -263,6 +264,9 @@ export default function buildMathML(
|
|
|
263
264
|
|
|
264
265
|
const math = new mathMLTree.MathNode("math", [semantics]);
|
|
265
266
|
math.setAttribute("xmlns", "http://www.w3.org/1998/Math/MathML");
|
|
267
|
+
if (isDisplayMode) {
|
|
268
|
+
math.setAttribute("display", "block");
|
|
269
|
+
}
|
|
266
270
|
|
|
267
271
|
// You can't style <math> nodes, so we wrap the node in a span.
|
|
268
272
|
// NOTE: The span class is not typed to have <math> nodes as children, and
|
package/src/buildTree.js
CHANGED
|
@@ -39,12 +39,13 @@ export const buildTree = function(
|
|
|
39
39
|
const options = optionsFromSettings(settings);
|
|
40
40
|
let katexNode;
|
|
41
41
|
if (settings.output === "mathml") {
|
|
42
|
-
return buildMathML(tree, expression, options, true);
|
|
42
|
+
return buildMathML(tree, expression, options, settings.displayMode, true);
|
|
43
43
|
} else if (settings.output === "html") {
|
|
44
44
|
const htmlNode = buildHTML(tree, options);
|
|
45
45
|
katexNode = buildCommon.makeSpan(["katex"], [htmlNode]);
|
|
46
46
|
} else {
|
|
47
|
-
const mathMLNode = buildMathML(tree, expression, options,
|
|
47
|
+
const mathMLNode = buildMathML(tree, expression, options,
|
|
48
|
+
settings.displayMode, false);
|
|
48
49
|
const htmlNode = buildHTML(tree, options);
|
|
49
50
|
katexNode = buildCommon.makeSpan(["katex"], [mathMLNode, htmlNode]);
|
|
50
51
|
}
|
package/src/defineFunction.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
// @flow
|
|
2
|
-
import {checkNodeType} from "./parseNode";
|
|
3
|
-
|
|
4
2
|
import type Parser from "./Parser";
|
|
5
3
|
import type {ParseNode, AnyParseNode, NodeType, UnsupportedCmdParseNode}
|
|
6
4
|
from "./parseNode";
|
|
@@ -228,6 +226,5 @@ export function defineFunctionBuilders<NODETYPE: NodeType>({
|
|
|
228
226
|
// Since the corresponding buildHTML/buildMathML function expects a
|
|
229
227
|
// list of elements, we normalize for different kinds of arguments
|
|
230
228
|
export const ordargument = function(arg: AnyParseNode): AnyParseNode[] {
|
|
231
|
-
|
|
232
|
-
return node ? node.body : [arg];
|
|
229
|
+
return arg.type === "ordgroup" ? arg.body : [arg];
|
|
233
230
|
};
|