temml 0.9.1
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/LICENSE +21 -0
- package/README.md +44 -0
- package/contrib/auto-render/README.md +89 -0
- package/contrib/auto-render/auto-render.js +128 -0
- package/contrib/auto-render/dist/auto-render.js +217 -0
- package/contrib/auto-render/dist/auto-render.min.js +1 -0
- package/contrib/auto-render/splitAtDelimiters.js +84 -0
- package/contrib/auto-render/test/auto-render-spec.js +234 -0
- package/contrib/auto-render/test/auto-render.js +217 -0
- package/contrib/auto-render/test/test_page.html +59 -0
- package/contrib/mhchem/README.md +26 -0
- package/contrib/mhchem/mhchem.js +1705 -0
- package/contrib/mhchem/mhchem.min.js +1 -0
- package/contrib/physics/README.md +20 -0
- package/contrib/physics/physics.js +131 -0
- package/contrib/texvc/README.md +23 -0
- package/contrib/texvc/texvc.js +61 -0
- package/dist/Temml-Asana.css +201 -0
- package/dist/Temml-Latin-Modern.css +216 -0
- package/dist/Temml-Libertinus.css +214 -0
- package/dist/Temml-Local.css +194 -0
- package/dist/Temml-STIX2.css +203 -0
- package/dist/Temml.woff2 +0 -0
- package/dist/temml.cjs +13122 -0
- package/dist/temml.js +11225 -0
- package/dist/temml.min.js +1 -0
- package/dist/temml.mjs +13120 -0
- package/dist/temmlPostProcess.js +70 -0
- package/package.json +34 -0
- package/src/Lexer.js +121 -0
- package/src/MacroExpander.js +437 -0
- package/src/Namespace.js +107 -0
- package/src/ParseError.js +64 -0
- package/src/Parser.js +977 -0
- package/src/Settings.js +49 -0
- package/src/SourceLocation.js +29 -0
- package/src/Style.js +144 -0
- package/src/Token.js +40 -0
- package/src/buildMathML.js +235 -0
- package/src/constants.js +25 -0
- package/src/defineEnvironment.js +25 -0
- package/src/defineFunction.js +69 -0
- package/src/defineMacro.js +11 -0
- package/src/domTree.js +185 -0
- package/src/environments/array.js +791 -0
- package/src/environments/cd.js +252 -0
- package/src/environments.js +8 -0
- package/src/functions/accent.js +127 -0
- package/src/functions/accentunder.js +38 -0
- package/src/functions/arrow.js +204 -0
- package/src/functions/cancelto.js +36 -0
- package/src/functions/char.js +33 -0
- package/src/functions/color.js +253 -0
- package/src/functions/cr.js +46 -0
- package/src/functions/def.js +259 -0
- package/src/functions/delimsizing.js +304 -0
- package/src/functions/enclose.js +193 -0
- package/src/functions/envTag.js +38 -0
- package/src/functions/environment.js +59 -0
- package/src/functions/font.js +123 -0
- package/src/functions/genfrac.js +333 -0
- package/src/functions/hbox.js +29 -0
- package/src/functions/horizBrace.js +32 -0
- package/src/functions/href.js +90 -0
- package/src/functions/html.js +95 -0
- package/src/functions/includegraphics.js +131 -0
- package/src/functions/kern.js +75 -0
- package/src/functions/label.js +29 -0
- package/src/functions/lap.js +75 -0
- package/src/functions/math.js +40 -0
- package/src/functions/mathchoice.js +41 -0
- package/src/functions/mclass.js +201 -0
- package/src/functions/multiscript.js +91 -0
- package/src/functions/not.js +46 -0
- package/src/functions/op.js +338 -0
- package/src/functions/operatorname.js +139 -0
- package/src/functions/ordgroup.js +9 -0
- package/src/functions/phantom.js +73 -0
- package/src/functions/pmb.js +31 -0
- package/src/functions/raise.js +68 -0
- package/src/functions/ref.js +28 -0
- package/src/functions/relax.js +16 -0
- package/src/functions/rule.js +52 -0
- package/src/functions/sizing.js +64 -0
- package/src/functions/smash.js +66 -0
- package/src/functions/sqrt.js +31 -0
- package/src/functions/styling.js +58 -0
- package/src/functions/supsub.js +135 -0
- package/src/functions/symbolsOp.js +53 -0
- package/src/functions/symbolsOrd.js +102 -0
- package/src/functions/symbolsSpacing.js +53 -0
- package/src/functions/tag.js +8 -0
- package/src/functions/text.js +75 -0
- package/src/functions/tip.js +63 -0
- package/src/functions/toggle.js +13 -0
- package/src/functions/verb.js +33 -0
- package/src/functions.js +57 -0
- package/src/linebreaking.js +159 -0
- package/src/macros.js +708 -0
- package/src/mathMLTree.js +175 -0
- package/src/parseNode.js +42 -0
- package/src/parseTree.js +40 -0
- package/src/postProcess.js +57 -0
- package/src/replace.js +225 -0
- package/src/stretchy.js +66 -0
- package/src/svg.js +110 -0
- package/src/symbols.js +972 -0
- package/src/tree.js +50 -0
- package/src/unicodeAccents.js +16 -0
- package/src/unicodeScripts.js +119 -0
- package/src/unicodeSupOrSub.js +108 -0
- package/src/unicodeSymbolBuilder.js +31 -0
- package/src/unicodeSymbols.js +320 -0
- package/src/units.js +109 -0
- package/src/utils.js +109 -0
- package/src/variant.js +103 -0
- package/temml.js +181 -0
package/src/units.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file does conversion between units. In particular, it provides
|
|
3
|
+
* calculateSize to convert other units into CSS units.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import ParseError from "./ParseError"
|
|
7
|
+
import utils from "./utils"
|
|
8
|
+
|
|
9
|
+
const ptPerUnit = {
|
|
10
|
+
// Convert to CSS (Postscipt) points, not TeX points
|
|
11
|
+
// https://en.wikibooks.org/wiki/LaTeX/Lengths and
|
|
12
|
+
// https://tex.stackexchange.com/a/8263
|
|
13
|
+
pt: 800 / 803, // convert TeX point to CSS (Postscript) point
|
|
14
|
+
pc: (12 * 800) / 803, // pica
|
|
15
|
+
dd: ((1238 / 1157) * 800) / 803, // didot
|
|
16
|
+
cc: ((14856 / 1157) * 800) / 803, // cicero (12 didot)
|
|
17
|
+
nd: ((685 / 642) * 800) / 803, // new didot
|
|
18
|
+
nc: ((1370 / 107) * 800) / 803, // new cicero (12 new didot)
|
|
19
|
+
sp: ((1 / 65536) * 800) / 803, // scaled point (TeX's internal smallest unit)
|
|
20
|
+
mm: (25.4 / 72),
|
|
21
|
+
cm: (2.54 / 72),
|
|
22
|
+
in: (1 / 72),
|
|
23
|
+
px: (96 / 72)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Determine whether the specified unit (either a string defining the unit
|
|
28
|
+
* or a "size" parse node containing a unit field) is valid.
|
|
29
|
+
*/
|
|
30
|
+
const validUnits = [
|
|
31
|
+
"em",
|
|
32
|
+
"ex",
|
|
33
|
+
"mu",
|
|
34
|
+
"pt",
|
|
35
|
+
"mm",
|
|
36
|
+
"cm",
|
|
37
|
+
"in",
|
|
38
|
+
"px",
|
|
39
|
+
"bp",
|
|
40
|
+
"pc",
|
|
41
|
+
"dd",
|
|
42
|
+
"cc",
|
|
43
|
+
"nd",
|
|
44
|
+
"nc",
|
|
45
|
+
"sp"
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
export const validUnit = function(unit) {
|
|
49
|
+
if (typeof unit !== "string") {
|
|
50
|
+
unit = unit.unit
|
|
51
|
+
}
|
|
52
|
+
return validUnits.indexOf(unit) > -1
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const emScale = styleLevel => {
|
|
56
|
+
const scriptLevel = Math.max(styleLevel - 1, 0)
|
|
57
|
+
return [1, 0.7, 0.5][scriptLevel]
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/*
|
|
61
|
+
* Convert a "size" parse node (with numeric "number" and string "unit" fields,
|
|
62
|
+
* as parsed by functions.js argType "size") into a CSS value.
|
|
63
|
+
*/
|
|
64
|
+
export const calculateSize = function(sizeValue, style) {
|
|
65
|
+
let number = sizeValue.number
|
|
66
|
+
if (style.maxSize[0] < 0 && number > 0) {
|
|
67
|
+
return { number: 0, unit: "em" }
|
|
68
|
+
}
|
|
69
|
+
const unit = sizeValue.unit
|
|
70
|
+
switch (unit) {
|
|
71
|
+
case "mm":
|
|
72
|
+
case "cm":
|
|
73
|
+
case "in":
|
|
74
|
+
case "px": {
|
|
75
|
+
const numInCssPts = number * ptPerUnit[unit];
|
|
76
|
+
if (numInCssPts > style.maxSize[1]) {
|
|
77
|
+
return { number: style.maxSize[1], unit: "pt" }
|
|
78
|
+
}
|
|
79
|
+
return { number, unit }; // absolute CSS units.
|
|
80
|
+
}
|
|
81
|
+
case "em":
|
|
82
|
+
case "ex": {
|
|
83
|
+
// In TeX, em and ex do not change size in \scriptstyle.
|
|
84
|
+
if (unit === "ex") { number *= 0.431 }
|
|
85
|
+
number = Math.min(number / emScale(style.level), style.maxSize[0])
|
|
86
|
+
return { number: utils.round(number), unit: "em" };
|
|
87
|
+
}
|
|
88
|
+
case "bp": {
|
|
89
|
+
if (number > style.maxSize[1]) { number = style.maxSize[1] }
|
|
90
|
+
return { number, unit: "pt" }; // TeX bp is a CSS pt. (1/72 inch).
|
|
91
|
+
}
|
|
92
|
+
case "pt":
|
|
93
|
+
case "pc":
|
|
94
|
+
case "dd":
|
|
95
|
+
case "cc":
|
|
96
|
+
case "nd":
|
|
97
|
+
case "nc":
|
|
98
|
+
case "sp": {
|
|
99
|
+
number = Math.min(number * ptPerUnit[unit], style.maxSize[1])
|
|
100
|
+
return { number: utils.round(number), unit: "pt" }
|
|
101
|
+
}
|
|
102
|
+
case "mu": {
|
|
103
|
+
number = Math.min(number / 18, style.maxSize[0])
|
|
104
|
+
return { number: utils.round(number), unit: "em" }
|
|
105
|
+
}
|
|
106
|
+
default:
|
|
107
|
+
throw new ParseError("Invalid unit: '" + unit + "'")
|
|
108
|
+
}
|
|
109
|
+
}
|
package/src/utils.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
//
|
|
2
|
+
/**
|
|
3
|
+
* This file contains a list of utility functions which are useful in other
|
|
4
|
+
* files.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Provide a default value if a setting is undefined
|
|
9
|
+
*/
|
|
10
|
+
const deflt = function(setting, defaultIfUndefined) {
|
|
11
|
+
return setting === undefined ? defaultIfUndefined : setting;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// hyphenate and escape adapted from Facebook's React under Apache 2 license
|
|
15
|
+
|
|
16
|
+
const uppercase = /([A-Z])/g;
|
|
17
|
+
const hyphenate = function(str) {
|
|
18
|
+
return str.replace(uppercase, "-$1").toLowerCase();
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const ESCAPE_LOOKUP = {
|
|
22
|
+
"&": "&",
|
|
23
|
+
">": ">",
|
|
24
|
+
"<": "<",
|
|
25
|
+
'"': """,
|
|
26
|
+
"'": "'"
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const ESCAPE_REGEX = /[&><"']/g;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Escapes text to prevent scripting attacks.
|
|
33
|
+
*/
|
|
34
|
+
function escape(text) {
|
|
35
|
+
return String(text).replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Sometimes we want to pull out the innermost element of a group. In most
|
|
40
|
+
* cases, this will just be the group itself, but when ordgroups and colors have
|
|
41
|
+
* a single element, we want to pull that out.
|
|
42
|
+
*/
|
|
43
|
+
const getBaseElem = function(group) {
|
|
44
|
+
if (group.type === "ordgroup") {
|
|
45
|
+
if (group.body.length === 1) {
|
|
46
|
+
return getBaseElem(group.body[0]);
|
|
47
|
+
} else {
|
|
48
|
+
return group;
|
|
49
|
+
}
|
|
50
|
+
} else if (group.type === "color") {
|
|
51
|
+
if (group.body.length === 1) {
|
|
52
|
+
return getBaseElem(group.body[0]);
|
|
53
|
+
} else {
|
|
54
|
+
return group;
|
|
55
|
+
}
|
|
56
|
+
} else if (group.type === "font") {
|
|
57
|
+
return getBaseElem(group.body);
|
|
58
|
+
} else {
|
|
59
|
+
return group;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* TeXbook algorithms often reference "character boxes", which are simply groups
|
|
65
|
+
* with a single character in them. To decide if something is a character box,
|
|
66
|
+
* we find its innermost group, and see if it is a single character.
|
|
67
|
+
*/
|
|
68
|
+
const isCharacterBox = function(group) {
|
|
69
|
+
const baseElem = getBaseElem(group);
|
|
70
|
+
|
|
71
|
+
// These are all the types of groups which hold single characters
|
|
72
|
+
return baseElem.type === "mathord" || baseElem.type === "textord" || baseElem.type === "atom"
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const assert = function(value) {
|
|
76
|
+
if (!value) {
|
|
77
|
+
throw new Error("Expected non-null, but got " + String(value));
|
|
78
|
+
}
|
|
79
|
+
return value;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Return the protocol of a URL, or "_relative" if the URL does not specify a
|
|
84
|
+
* protocol (and thus is relative).
|
|
85
|
+
*/
|
|
86
|
+
export const protocolFromUrl = function(url) {
|
|
87
|
+
const protocol = /^\s*([^\\/#]*?)(?::|�*58|�*3a)/i.exec(url);
|
|
88
|
+
return protocol != null ? protocol[1] : "_relative";
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Round `n` to 4 decimal places, or to the nearest 1/10,000th em. The TeXbook
|
|
93
|
+
* gives an acceptable rounding error of 100sp (which would be the nearest
|
|
94
|
+
* 1/6551.6em with our ptPerEm = 10):
|
|
95
|
+
* http://www.ctex.org/documents/shredder/src/texbook.pdf#page=69
|
|
96
|
+
*/
|
|
97
|
+
const round = function(n) {
|
|
98
|
+
return +n.toFixed(4);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export default {
|
|
102
|
+
deflt,
|
|
103
|
+
escape,
|
|
104
|
+
hyphenate,
|
|
105
|
+
getBaseElem,
|
|
106
|
+
isCharacterBox,
|
|
107
|
+
protocolFromUrl,
|
|
108
|
+
round
|
|
109
|
+
};
|
package/src/variant.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import symbols from "./symbols";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Maps TeX font commands to "mathvariant" attribute in buildMathML.js
|
|
5
|
+
*/
|
|
6
|
+
const fontMap = {
|
|
7
|
+
// styles
|
|
8
|
+
mathbf: "bold",
|
|
9
|
+
mathrm: "normal",
|
|
10
|
+
textit: "italic",
|
|
11
|
+
mathit: "italic",
|
|
12
|
+
mathnormal: "italic",
|
|
13
|
+
|
|
14
|
+
// families
|
|
15
|
+
mathbb: "double-struck",
|
|
16
|
+
mathcal: "script",
|
|
17
|
+
mathfrak: "fraktur",
|
|
18
|
+
mathscr: "script",
|
|
19
|
+
mathsf: "sans-serif",
|
|
20
|
+
mathtt: "monospace",
|
|
21
|
+
oldstylenums: "oldstylenums"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns the math variant as a string or null if none is required.
|
|
26
|
+
*/
|
|
27
|
+
export const getVariant = function(group, style) {
|
|
28
|
+
// Handle font specifiers as best we can.
|
|
29
|
+
// Chromium does not support the MathML mathvariant attribute.
|
|
30
|
+
// So we'll use Unicode replacement characters instead.
|
|
31
|
+
// But first, determine the math variant.
|
|
32
|
+
|
|
33
|
+
// Deal with the \textit, \textbf, etc., functions.
|
|
34
|
+
if (style.fontFamily === "texttt") {
|
|
35
|
+
return "monospace"
|
|
36
|
+
} else if (style.fontFamily === "textsc") {
|
|
37
|
+
return "normal"; // handled via character substitution in symbolsOrd.js.
|
|
38
|
+
} else if (style.fontFamily === "textsf") {
|
|
39
|
+
if (style.fontShape === "textit" && style.fontWeight === "textbf") {
|
|
40
|
+
return "sans-serif-bold-italic"
|
|
41
|
+
} else if (style.fontShape === "textit") {
|
|
42
|
+
return "sans-serif-italic"
|
|
43
|
+
} else if (style.fontWeight === "textbf") {
|
|
44
|
+
return "sans-serif-bold"
|
|
45
|
+
} else {
|
|
46
|
+
return "sans-serif"
|
|
47
|
+
}
|
|
48
|
+
} else if (style.fontShape === "textit" && style.fontWeight === "textbf") {
|
|
49
|
+
return "bold-italic"
|
|
50
|
+
} else if (style.fontShape === "textit") {
|
|
51
|
+
return "italic"
|
|
52
|
+
} else if (style.fontWeight === "textbf") {
|
|
53
|
+
return "bold"
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Deal with the \mathit, mathbf, etc, functions.
|
|
57
|
+
const font = style.font
|
|
58
|
+
if (!font || font === "mathnormal") {
|
|
59
|
+
return null
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const mode = group.mode;
|
|
63
|
+
switch (font) {
|
|
64
|
+
case "mathit":
|
|
65
|
+
return "italic"
|
|
66
|
+
case "mathrm": {
|
|
67
|
+
const codePoint = group.text.codePointAt(0)
|
|
68
|
+
// LaTeX \mathrm returns italic for Greek characters.
|
|
69
|
+
return (0x03ab < codePoint && codePoint < 0x03cf) ? "italic" : "normal"
|
|
70
|
+
}
|
|
71
|
+
case "greekItalic":
|
|
72
|
+
return "italic"
|
|
73
|
+
case "up@greek":
|
|
74
|
+
return "normal"
|
|
75
|
+
case "boldsymbol":
|
|
76
|
+
case "mathboldsymbol":
|
|
77
|
+
return "bold-italic"
|
|
78
|
+
case "mathbf":
|
|
79
|
+
return "bold"
|
|
80
|
+
case "mathbb":
|
|
81
|
+
return "double-struck"
|
|
82
|
+
case "mathfrak":
|
|
83
|
+
return "fraktur"
|
|
84
|
+
case "mathscr":
|
|
85
|
+
case "mathcal":
|
|
86
|
+
return "script"
|
|
87
|
+
case "mathsf":
|
|
88
|
+
return "sans-serif"
|
|
89
|
+
case "mathtt":
|
|
90
|
+
return "monospace"
|
|
91
|
+
case "oldstylenums":
|
|
92
|
+
return "oldstylenums"
|
|
93
|
+
default:
|
|
94
|
+
break
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let text = group.text;
|
|
98
|
+
if (symbols[mode][text] && symbols[mode][text].replace) {
|
|
99
|
+
text = symbols[mode][text].replace
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return Object.prototype.hasOwnProperty.call(fontMap, font) ? fontMap[font] : null
|
|
103
|
+
};
|
package/temml.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/* eslint no-console:0 */
|
|
2
|
+
/**
|
|
3
|
+
* This is the main entry point for Temml. Here, we expose functions for
|
|
4
|
+
* rendering expressions either to DOM nodes or to markup strings.
|
|
5
|
+
*
|
|
6
|
+
* We also expose the ParseError class to check if errors thrown from Temml are
|
|
7
|
+
* errors in the expression, or errors in javascript handling.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import ParseError from "./src/ParseError";
|
|
11
|
+
import Settings from "./src/Settings";
|
|
12
|
+
|
|
13
|
+
import Parser from "./src/Parser";
|
|
14
|
+
import parseTree from "./src/parseTree";
|
|
15
|
+
import buildMathML from "./src/buildMathML";
|
|
16
|
+
import { StyleLevel } from "./src/constants";
|
|
17
|
+
import Style from "./src/Style";
|
|
18
|
+
import { Span, TextNode } from "./src/domTree";
|
|
19
|
+
import { defineSymbol } from "./src/symbols";
|
|
20
|
+
import defineMacro from "./src/defineMacro";
|
|
21
|
+
import { postProcess, version } from "./src/postProcess";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Parse and build an expression, and place that expression in the DOM node
|
|
25
|
+
* given.
|
|
26
|
+
*/
|
|
27
|
+
let render = function(expression, baseNode, options) {
|
|
28
|
+
baseNode.textContent = "";
|
|
29
|
+
const alreadyInMathElement = baseNode.tagName === "MATH"
|
|
30
|
+
if (alreadyInMathElement) { options.wrap = "none" }
|
|
31
|
+
const math = renderToMathMLTree(expression, options)
|
|
32
|
+
if (alreadyInMathElement) {
|
|
33
|
+
// The <math> element already exists. Populate it.
|
|
34
|
+
baseNode.textContent = ""
|
|
35
|
+
math.children.forEach(e => { baseNode.appendChild(e.toNode()) })
|
|
36
|
+
} else if (math.children.length > 1) {
|
|
37
|
+
baseNode.textContent = ""
|
|
38
|
+
math.children.forEach(e => { baseNode.appendChild(e.toNode()) })
|
|
39
|
+
} else {
|
|
40
|
+
baseNode.appendChild(math.toNode())
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Temml's styles don't work properly in quirks mode. Print out an error, and
|
|
45
|
+
// disable rendering.
|
|
46
|
+
if (typeof document !== "undefined") {
|
|
47
|
+
if (document.compatMode !== "CSS1Compat") {
|
|
48
|
+
typeof console !== "undefined" &&
|
|
49
|
+
console.warn(
|
|
50
|
+
"Warning: Temml doesn't work in quirks mode. Make sure your " +
|
|
51
|
+
"website has a suitable doctype."
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
render = function() {
|
|
55
|
+
throw new ParseError("Temml doesn't work in quirks mode.");
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Parse and build an expression, and return the markup for that.
|
|
62
|
+
*/
|
|
63
|
+
const renderToString = function(expression, options) {
|
|
64
|
+
const markup = renderToMathMLTree(expression, options).toMarkup();
|
|
65
|
+
return markup;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Parse an expression and return the parse tree.
|
|
70
|
+
*/
|
|
71
|
+
const generateParseTree = function(expression, options) {
|
|
72
|
+
const settings = new Settings(options);
|
|
73
|
+
return parseTree(expression, settings);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Take an expression which contains a preamble.
|
|
78
|
+
* Parse it and return the macros.
|
|
79
|
+
*/
|
|
80
|
+
const definePreamble = function(expression, options) {
|
|
81
|
+
const settings = new Settings(options);
|
|
82
|
+
settings.macros = {};
|
|
83
|
+
if (!(typeof expression === "string" || expression instanceof String)) {
|
|
84
|
+
throw new TypeError("Temml can only parse string typed expression")
|
|
85
|
+
}
|
|
86
|
+
const parser = new Parser(expression, settings, true)
|
|
87
|
+
// Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
|
|
88
|
+
delete parser.gullet.macros.current["\\df@tag"]
|
|
89
|
+
const macros = parser.parse()
|
|
90
|
+
return macros
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* If the given error is a Temml ParseError,
|
|
95
|
+
* renders the invalid LaTeX as a span with hover title giving the Temml
|
|
96
|
+
* error message. Otherwise, simply throws the error.
|
|
97
|
+
*/
|
|
98
|
+
const renderError = function(error, expression, options) {
|
|
99
|
+
if (options.throwOnError || !(error instanceof ParseError)) {
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
const node = new Span(["temml-error"], [new TextNode(expression + "\n" + error.toString())]);
|
|
103
|
+
node.style.color = options.errorColor
|
|
104
|
+
node.style.whiteSpace = "pre-line"
|
|
105
|
+
return node;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Generates and returns the Temml build tree. This is used for advanced
|
|
110
|
+
* use cases (like rendering to custom output).
|
|
111
|
+
*/
|
|
112
|
+
const renderToMathMLTree = function(expression, options) {
|
|
113
|
+
const settings = new Settings(options);
|
|
114
|
+
try {
|
|
115
|
+
const tree = parseTree(expression, settings);
|
|
116
|
+
const style = new Style({
|
|
117
|
+
level: settings.displayMode ? StyleLevel.DISPLAY : StyleLevel.TEXT,
|
|
118
|
+
maxSize: settings.maxSize
|
|
119
|
+
});
|
|
120
|
+
return buildMathML(tree, expression, style, settings);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
return renderError(error, expression, settings);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export default {
|
|
127
|
+
/**
|
|
128
|
+
* Current Temml version
|
|
129
|
+
*/
|
|
130
|
+
version: version,
|
|
131
|
+
/**
|
|
132
|
+
* Renders the given LaTeX into MathML, and adds
|
|
133
|
+
* it as a child to the specified DOM node.
|
|
134
|
+
*/
|
|
135
|
+
render,
|
|
136
|
+
/**
|
|
137
|
+
* Renders the given LaTeX into MathML string,
|
|
138
|
+
* for sending to the client.
|
|
139
|
+
*/
|
|
140
|
+
renderToString,
|
|
141
|
+
/**
|
|
142
|
+
* Post-process an entire HTML block.
|
|
143
|
+
* Writes AMS auto-numbers and implements \ref{}.
|
|
144
|
+
* Typcally called once, after a loop has rendered many individual spans.
|
|
145
|
+
*/
|
|
146
|
+
postProcess,
|
|
147
|
+
/**
|
|
148
|
+
* Temml error, usually during parsing.
|
|
149
|
+
*/
|
|
150
|
+
ParseError,
|
|
151
|
+
/**
|
|
152
|
+
* Creates a set of macros with document-wide scope.
|
|
153
|
+
*/
|
|
154
|
+
definePreamble,
|
|
155
|
+
/**
|
|
156
|
+
* Parses the given LaTeX into Temml's internal parse tree structure,
|
|
157
|
+
* without rendering to HTML or MathML.
|
|
158
|
+
*
|
|
159
|
+
* NOTE: This method is not currently recommended for public use.
|
|
160
|
+
* The internal tree representation is unstable and is very likely
|
|
161
|
+
* to change. Use at your own risk.
|
|
162
|
+
*/
|
|
163
|
+
__parse: generateParseTree,
|
|
164
|
+
/**
|
|
165
|
+
* Renders the given LaTeX into a MathML internal DOM tree
|
|
166
|
+
* representation, without flattening that representation to a string.
|
|
167
|
+
*
|
|
168
|
+
* NOTE: This method is not currently recommended for public use.
|
|
169
|
+
* The internal tree representation is unstable and is very likely
|
|
170
|
+
* to change. Use at your own risk.
|
|
171
|
+
*/
|
|
172
|
+
__renderToMathMLTree: renderToMathMLTree,
|
|
173
|
+
/**
|
|
174
|
+
* adds a new symbol to builtin symbols table
|
|
175
|
+
*/
|
|
176
|
+
__defineSymbol: defineSymbol,
|
|
177
|
+
/**
|
|
178
|
+
* adds a new macro to builtin macro list
|
|
179
|
+
*/
|
|
180
|
+
__defineMacro: defineMacro
|
|
181
|
+
}
|