temml 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +44 -0
  3. package/contrib/auto-render/README.md +89 -0
  4. package/contrib/auto-render/auto-render.js +128 -0
  5. package/contrib/auto-render/dist/auto-render.js +217 -0
  6. package/contrib/auto-render/dist/auto-render.min.js +1 -0
  7. package/contrib/auto-render/splitAtDelimiters.js +84 -0
  8. package/contrib/auto-render/test/auto-render-spec.js +234 -0
  9. package/contrib/auto-render/test/auto-render.js +217 -0
  10. package/contrib/auto-render/test/test_page.html +59 -0
  11. package/contrib/mhchem/README.md +26 -0
  12. package/contrib/mhchem/mhchem.js +1705 -0
  13. package/contrib/mhchem/mhchem.min.js +1 -0
  14. package/contrib/physics/README.md +20 -0
  15. package/contrib/physics/physics.js +131 -0
  16. package/contrib/texvc/README.md +23 -0
  17. package/contrib/texvc/texvc.js +61 -0
  18. package/dist/Temml-Asana.css +201 -0
  19. package/dist/Temml-Latin-Modern.css +216 -0
  20. package/dist/Temml-Libertinus.css +214 -0
  21. package/dist/Temml-Local.css +194 -0
  22. package/dist/Temml-STIX2.css +203 -0
  23. package/dist/Temml.woff2 +0 -0
  24. package/dist/temml.cjs +13122 -0
  25. package/dist/temml.js +11225 -0
  26. package/dist/temml.min.js +1 -0
  27. package/dist/temml.mjs +13120 -0
  28. package/dist/temmlPostProcess.js +70 -0
  29. package/package.json +34 -0
  30. package/src/Lexer.js +121 -0
  31. package/src/MacroExpander.js +437 -0
  32. package/src/Namespace.js +107 -0
  33. package/src/ParseError.js +64 -0
  34. package/src/Parser.js +977 -0
  35. package/src/Settings.js +49 -0
  36. package/src/SourceLocation.js +29 -0
  37. package/src/Style.js +144 -0
  38. package/src/Token.js +40 -0
  39. package/src/buildMathML.js +235 -0
  40. package/src/constants.js +25 -0
  41. package/src/defineEnvironment.js +25 -0
  42. package/src/defineFunction.js +69 -0
  43. package/src/defineMacro.js +11 -0
  44. package/src/domTree.js +185 -0
  45. package/src/environments/array.js +791 -0
  46. package/src/environments/cd.js +252 -0
  47. package/src/environments.js +8 -0
  48. package/src/functions/accent.js +127 -0
  49. package/src/functions/accentunder.js +38 -0
  50. package/src/functions/arrow.js +204 -0
  51. package/src/functions/cancelto.js +36 -0
  52. package/src/functions/char.js +33 -0
  53. package/src/functions/color.js +253 -0
  54. package/src/functions/cr.js +46 -0
  55. package/src/functions/def.js +259 -0
  56. package/src/functions/delimsizing.js +304 -0
  57. package/src/functions/enclose.js +193 -0
  58. package/src/functions/envTag.js +38 -0
  59. package/src/functions/environment.js +59 -0
  60. package/src/functions/font.js +123 -0
  61. package/src/functions/genfrac.js +333 -0
  62. package/src/functions/hbox.js +29 -0
  63. package/src/functions/horizBrace.js +32 -0
  64. package/src/functions/href.js +90 -0
  65. package/src/functions/html.js +95 -0
  66. package/src/functions/includegraphics.js +131 -0
  67. package/src/functions/kern.js +75 -0
  68. package/src/functions/label.js +29 -0
  69. package/src/functions/lap.js +75 -0
  70. package/src/functions/math.js +40 -0
  71. package/src/functions/mathchoice.js +41 -0
  72. package/src/functions/mclass.js +201 -0
  73. package/src/functions/multiscript.js +91 -0
  74. package/src/functions/not.js +46 -0
  75. package/src/functions/op.js +338 -0
  76. package/src/functions/operatorname.js +139 -0
  77. package/src/functions/ordgroup.js +9 -0
  78. package/src/functions/phantom.js +73 -0
  79. package/src/functions/pmb.js +31 -0
  80. package/src/functions/raise.js +68 -0
  81. package/src/functions/ref.js +28 -0
  82. package/src/functions/relax.js +16 -0
  83. package/src/functions/rule.js +52 -0
  84. package/src/functions/sizing.js +64 -0
  85. package/src/functions/smash.js +66 -0
  86. package/src/functions/sqrt.js +31 -0
  87. package/src/functions/styling.js +58 -0
  88. package/src/functions/supsub.js +135 -0
  89. package/src/functions/symbolsOp.js +53 -0
  90. package/src/functions/symbolsOrd.js +102 -0
  91. package/src/functions/symbolsSpacing.js +53 -0
  92. package/src/functions/tag.js +8 -0
  93. package/src/functions/text.js +75 -0
  94. package/src/functions/tip.js +63 -0
  95. package/src/functions/toggle.js +13 -0
  96. package/src/functions/verb.js +33 -0
  97. package/src/functions.js +57 -0
  98. package/src/linebreaking.js +159 -0
  99. package/src/macros.js +708 -0
  100. package/src/mathMLTree.js +175 -0
  101. package/src/parseNode.js +42 -0
  102. package/src/parseTree.js +40 -0
  103. package/src/postProcess.js +57 -0
  104. package/src/replace.js +225 -0
  105. package/src/stretchy.js +66 -0
  106. package/src/svg.js +110 -0
  107. package/src/symbols.js +972 -0
  108. package/src/tree.js +50 -0
  109. package/src/unicodeAccents.js +16 -0
  110. package/src/unicodeScripts.js +119 -0
  111. package/src/unicodeSupOrSub.js +108 -0
  112. package/src/unicodeSymbolBuilder.js +31 -0
  113. package/src/unicodeSymbols.js +320 -0
  114. package/src/units.js +109 -0
  115. package/src/utils.js +109 -0
  116. package/src/variant.js +103 -0
  117. package/temml.js +181 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Ron Kok
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ *Temml* is a LaTeX-to-MathML JavaScript conversion utility. It is built to be lightweight.
2
+
3
+ | Library | Minified JavaScript + CSS |
4
+ |:--------------|:-------------------------:|
5
+ | Temml | 147 KB |
6
+ | MathJax 2.7.5 | 338 KB |
7
+ | KaTeX | 280 KB |
8
+ | TeXZilla | 168 KB |
9
+
10
+ As a futher advantage, Temml can use local system fonts. The minimum Temml installation serves a font file that is only 12kb.
11
+
12
+ Chromium will support MathML in release 109 [early in 2023](https://chromiumdash.appspot.com/schedule), At that point, all the major browsers will support MathML and Temml will become the most lightweight way to render math in a browser.
13
+
14
+ Temml’s coverage of LaTeX functions is as good as MathJax, slightly better than KaTeX 0.13.0 and substantially better than TeXZilla. See a [detailed coverage comparison](https://temml.org/docs/en/comparison.html).
15
+
16
+ Temml's test suite includes many rendered examples, including the Temml [supported functions page](https://temml.org/docs/en/supported.html) and tests from [Mozilla](https://temml.org/tests/mozilla-tests.html), [Wikipedia](https://temml.org/tests/wiki-tests.html), [mhchem](https://temml.org/tests/mhchem-tests.html), and [LaTeXML](https://temml.org/tests/LaTeXML-tests.html).
17
+
18
+ Temml's demonstration page is at https://temml.org/
19
+
20
+ Documentation can be found at:
21
+
22
+ * [Installation](https://temml.org/docs/en/administration.html)
23
+
24
+ * LaTeX function support, [sorted into logical groups](https://temml.org/docs/en/supported.html).
25
+
26
+ * LaTeX function support, [sorted alphabetically](https://temml.org/docs/en/support_table.html).
27
+
28
+ ### Acknowledgements
29
+
30
+ I built Temml by:
31
+
32
+ 1. Forking [KaTeX](https://katex.org/).
33
+
34
+ 2. Deleting half the code, removing the HTML parts and keeping the parser, the macro expander, and the MathML parts.
35
+
36
+ 3. Doing some code refactoring and many MathML bug fixes.
37
+
38
+ 4. Adding new functionality: upright lower-case Greek letters, `\euro`, `\label{…}`, `\ref{…}`, `\prescript`, `\definecolor`, `xcolor` color names, etc.
39
+
40
+ I wish to thank Khan Academy and the many volunteer KaTeX contributors. This library would not exist if KaTeX had not existed first.
41
+
42
+ ---
43
+
44
+ Temml is released under terms of the [MIT license](https://mit-license.org/)
@@ -0,0 +1,89 @@
1
+ # Auto-render extension
2
+
3
+ This is a client-side extension to automatically render all of the math inside of the
4
+ text of a running HTML document. It searches all of the text nodes in a given element
5
+ for the given delimiters, and renders the math in place.
6
+
7
+
8
+ This extension isn't part of Temml proper, so the script needs to be included
9
+ (via a `<script>` tag) in the page along with Temml itself. For example:
10
+
11
+ ```html
12
+ <head>
13
+ ...
14
+ <link rel="stylesheet" href="./Temml-Local.css">
15
+ <script src="./temml.min.js"></script>
16
+ <script src="./auto-render.min.js"></script>
17
+ ...
18
+ </head>
19
+ <body>
20
+ ...
21
+ <script>renderMathInElement(document.body);</script>
22
+ </body>
23
+ ```
24
+
25
+ The auto-render extension exposes a single function, `window.renderMathInElement`, with
26
+ the following API:
27
+
28
+ ```js
29
+ function renderMathInElement(elem, options)
30
+ ```
31
+
32
+ `elem` is an HTML DOM element, typically `document.main`. The function will
33
+ recursively search for text nodes inside this element and render the math in them.
34
+
35
+ `options` is an optional object argument that can have the same keys as [the
36
+ options](https://temml.org/docs/en/administration.html#options) passed to
37
+ `temml.render`. In addition, there are five auto-render-specific keys:
38
+
39
+ - `delimiters`: This is a list of delimiters to look for math, processed in
40
+ the same order as the list. Each delimiter has three properties:
41
+
42
+ - `left`: A string which starts the math expression (i.e. the left delimiter).
43
+ - `right`: A string which ends the math expression (i.e. the right delimiter).
44
+ - `display`: A boolean of whether the math in the expression should be
45
+ rendered in display mode or not.
46
+
47
+ The default `delimiters` value is:
48
+
49
+ ```js
50
+ [
51
+ { left: "$$", right: "$$", display: true },
52
+ { left: "\\(", right: "\\)", display: false },
53
+ { left: "\\begin{equation}", right: "\\end{equation}", display: true },
54
+ { left: "\\begin{align}", right: "\\end{align}", display: true },
55
+ { left: "\\begin{alignat}", right: "\\end{alignat}", display: true },
56
+ { left: "\\begin{gather}", right: "\\end{gather}", display: true },
57
+ { left: "\\begin{CD}", right: "\\end{CD}", display: true },
58
+ { left: "\\begin{multline}", right: "\\end{multline}", display: true },
59
+ { left: "\\[", right: "\\]", display: true }
60
+ ]
61
+ ```
62
+
63
+ If you want to add support for inline math via `$…$`, be sure to list it
64
+ **after** `$$…$$`. Because rules are processed in order, putting a `$` rule first would
65
+ match `$$` and treat as an empty math expression. Here is an example that includes `$…$`:
66
+
67
+ ```js
68
+ [
69
+ {left: "$$", right: "$$", display: true},
70
+ // Put $ after $$.
71
+ {left: "$", right: "$", display: false},
72
+ {left: "\\(", right: "\\)", display: false},
73
+ // Put \[ last to avoid conflict with possible future \\[1em] row separator.
74
+ {left: "\\[", right: "\\]", display: true}
75
+ ]
76
+ ```
77
+
78
+ - `ignoredTags`: This is a list of DOM node types to ignore when recursing
79
+ through. The default value is
80
+ `["script", "noscript", "style", "textarea", "pre", "code", "option"]`.
81
+
82
+ - `ignoredClasses`: This is a list of DOM node class names to ignore when
83
+ recursing through. By default, this value is not set.
84
+
85
+ - `errorCallback`: A callback method returning a message and an error stack
86
+ in case of an critical error during rendering. The default uses `console.error`.
87
+
88
+ - `preProcess`: A callback function, `(math: string) => string`, used to process
89
+ math expressions before rendering.
@@ -0,0 +1,128 @@
1
+ /* eslint no-console:0 */
2
+
3
+ import temml from "temml";
4
+ import splitAtDelimiters from "./splitAtDelimiters";
5
+
6
+ /* Note: optionsCopy is mutated by this method. If it is ever exposed in the
7
+ * API, we should copy it before mutating.
8
+ */
9
+ const renderMathInText = function(text, optionsCopy) {
10
+ const data = splitAtDelimiters(text, optionsCopy.delimiters);
11
+ if (data.length === 1 && data[0].type === "text") {
12
+ // There is no formula in the text.
13
+ // Let's return null which means there is no need to replace
14
+ // the current text node with a new one.
15
+ return null;
16
+ }
17
+
18
+ const fragment = document.createDocumentFragment();
19
+
20
+ for (let i = 0; i < data.length; i++) {
21
+ if (data[i].type === "text") {
22
+ fragment.appendChild(document.createTextNode(data[i].data));
23
+ } else {
24
+ const span = document.createElement("span");
25
+ let math = data[i].data;
26
+ // Override any display mode defined in the settings with that
27
+ // defined by the text itself
28
+ optionsCopy.displayMode = data[i].display;
29
+ try {
30
+ if (optionsCopy.preProcess) {
31
+ math = optionsCopy.preProcess(math);
32
+ }
33
+ temml.render(math, span, optionsCopy);
34
+ } catch (e) {
35
+ if (!(e instanceof temml.ParseError)) {
36
+ throw e;
37
+ }
38
+ optionsCopy.errorCallback(
39
+ "Temml auto-render: Failed to parse `" + data[i].data + "` with ",
40
+ e
41
+ );
42
+ fragment.appendChild(document.createTextNode(data[i].rawData));
43
+ continue;
44
+ }
45
+ fragment.appendChild(span);
46
+ }
47
+ }
48
+
49
+ return fragment;
50
+ };
51
+
52
+ const renderElem = function(elem, optionsCopy) {
53
+ for (let i = 0; i < elem.childNodes.length; i++) {
54
+ const childNode = elem.childNodes[i];
55
+ if (childNode.nodeType === 3) {
56
+ // Text node
57
+ const frag = renderMathInText(childNode.textContent, optionsCopy);
58
+ if (frag) {
59
+ i += frag.childNodes.length - 1;
60
+ elem.replaceChild(frag, childNode);
61
+ }
62
+ } else if (childNode.nodeType === 1) {
63
+ // Element node
64
+ const className = " " + childNode.className + " ";
65
+ const shouldRender =
66
+ optionsCopy.ignoredTags.indexOf(childNode.nodeName.toLowerCase()) === -1 &&
67
+ optionsCopy.ignoredClasses.every((x) => className.indexOf(" " + x + " ") === -1);
68
+
69
+ if (shouldRender) {
70
+ renderElem(childNode, optionsCopy);
71
+ }
72
+ }
73
+ // Otherwise, it's something else, and ignore it.
74
+ }
75
+ };
76
+
77
+ const renderMathInElement = function(elem, options) {
78
+ if (!elem) {
79
+ throw new Error("No element provided to render");
80
+ }
81
+
82
+ const optionsCopy = {};
83
+
84
+ // Object.assign(optionsCopy, option)
85
+ for (const option in options) {
86
+ if (Object.prototype.hasOwnProperty.call(options, option)) {
87
+ optionsCopy[option] = options[option];
88
+ }
89
+ }
90
+
91
+ // default options
92
+ optionsCopy.delimiters = optionsCopy.delimiters || [
93
+ { left: "$$", right: "$$", display: true },
94
+ { left: "\\(", right: "\\)", display: false },
95
+ // LaTeX uses $…$, but it ruins the display of normal `$` in text:
96
+ // {left: "$", right: "$", display: false},
97
+ // $ must come after $$
98
+
99
+ // Render AMS environments even if outside $$…$$ delimiters.
100
+ { left: "\\begin{equation}", right: "\\end{equation}", display: true },
101
+ { left: "\\begin{align}", right: "\\end{align}", display: true },
102
+ { left: "\\begin{alignat}", right: "\\end{alignat}", display: true },
103
+ { left: "\\begin{gather}", right: "\\end{gather}", display: true },
104
+ { left: "\\begin{CD}", right: "\\end{CD}", display: true },
105
+
106
+ { left: "\\[", right: "\\]", display: true }
107
+ ];
108
+ optionsCopy.ignoredTags = optionsCopy.ignoredTags || [
109
+ "script",
110
+ "noscript",
111
+ "style",
112
+ "textarea",
113
+ "pre",
114
+ "code",
115
+ "option"
116
+ ];
117
+ optionsCopy.ignoredClasses = optionsCopy.ignoredClasses || [];
118
+ optionsCopy.errorCallback = optionsCopy.errorCallback || console.error;
119
+
120
+ // Enable sharing of global macros defined via `\gdef` between different
121
+ // math elements within a single call to `renderMathInElement`.
122
+ optionsCopy.macros = optionsCopy.macros || {};
123
+
124
+ renderElem(elem, optionsCopy);
125
+ temml.postProcess(elem);
126
+ };
127
+
128
+ export default renderMathInElement;
@@ -0,0 +1,217 @@
1
+ var renderMathInElement = (function (temml) {
2
+ 'use strict';
3
+
4
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
5
+
6
+ var temml__default = /*#__PURE__*/_interopDefaultLegacy(temml);
7
+
8
+ /* eslint no-constant-condition:0 */
9
+ const findEndOfMath = function(delimiter, text, startIndex) {
10
+ // Adapted from
11
+ // https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx
12
+ let index = startIndex;
13
+ let braceLevel = 0;
14
+
15
+ const delimLength = delimiter.length;
16
+
17
+ while (index < text.length) {
18
+ const character = text[index];
19
+
20
+ if (braceLevel <= 0 && text.slice(index, index + delimLength) === delimiter) {
21
+ return index;
22
+ } else if (character === "\\") {
23
+ index++;
24
+ } else if (character === "{") {
25
+ braceLevel++;
26
+ } else if (character === "}") {
27
+ braceLevel--;
28
+ }
29
+
30
+ index++;
31
+ }
32
+
33
+ return -1;
34
+ };
35
+
36
+ const escapeRegex = function(string) {
37
+ return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
38
+ };
39
+
40
+ const amsRegex = /^\\begin{/;
41
+
42
+ const splitAtDelimiters = function(text, delimiters) {
43
+ let index;
44
+ const data = [];
45
+
46
+ const regexLeft = new RegExp(
47
+ "(" + delimiters.map((x) => escapeRegex(x.left)).join("|") + ")"
48
+ );
49
+
50
+ while (true) {
51
+ index = text.search(regexLeft);
52
+ if (index === -1) {
53
+ break;
54
+ }
55
+ if (index > 0) {
56
+ data.push({
57
+ type: "text",
58
+ data: text.slice(0, index)
59
+ });
60
+ text = text.slice(index); // now text starts with delimiter
61
+ }
62
+ // ... so this always succeeds:
63
+ const i = delimiters.findIndex((delim) => text.startsWith(delim.left));
64
+ index = findEndOfMath(delimiters[i].right, text, delimiters[i].left.length);
65
+ if (index === -1) {
66
+ break;
67
+ }
68
+ const rawData = text.slice(0, index + delimiters[i].right.length);
69
+ const math = amsRegex.test(rawData)
70
+ ? rawData
71
+ : text.slice(delimiters[i].left.length, index);
72
+ data.push({
73
+ type: "math",
74
+ data: math,
75
+ rawData,
76
+ display: delimiters[i].display
77
+ });
78
+ text = text.slice(index + delimiters[i].right.length);
79
+ }
80
+
81
+ if (text !== "") {
82
+ data.push({
83
+ type: "text",
84
+ data: text
85
+ });
86
+ }
87
+
88
+ return data;
89
+ };
90
+
91
+ /* eslint no-console:0 */
92
+
93
+ /* Note: optionsCopy is mutated by this method. If it is ever exposed in the
94
+ * API, we should copy it before mutating.
95
+ */
96
+ const renderMathInText = function(text, optionsCopy) {
97
+ const data = splitAtDelimiters(text, optionsCopy.delimiters);
98
+ if (data.length === 1 && data[0].type === "text") {
99
+ // There is no formula in the text.
100
+ // Let's return null which means there is no need to replace
101
+ // the current text node with a new one.
102
+ return null;
103
+ }
104
+
105
+ const fragment = document.createDocumentFragment();
106
+
107
+ for (let i = 0; i < data.length; i++) {
108
+ if (data[i].type === "text") {
109
+ fragment.appendChild(document.createTextNode(data[i].data));
110
+ } else {
111
+ const span = document.createElement("span");
112
+ let math = data[i].data;
113
+ // Override any display mode defined in the settings with that
114
+ // defined by the text itself
115
+ optionsCopy.displayMode = data[i].display;
116
+ try {
117
+ if (optionsCopy.preProcess) {
118
+ math = optionsCopy.preProcess(math);
119
+ }
120
+ temml__default["default"].render(math, span, optionsCopy);
121
+ } catch (e) {
122
+ if (!(e instanceof temml__default["default"].ParseError)) {
123
+ throw e;
124
+ }
125
+ optionsCopy.errorCallback(
126
+ "Temml auto-render: Failed to parse `" + data[i].data + "` with ",
127
+ e
128
+ );
129
+ fragment.appendChild(document.createTextNode(data[i].rawData));
130
+ continue;
131
+ }
132
+ fragment.appendChild(span);
133
+ }
134
+ }
135
+
136
+ return fragment;
137
+ };
138
+
139
+ const renderElem = function(elem, optionsCopy) {
140
+ for (let i = 0; i < elem.childNodes.length; i++) {
141
+ const childNode = elem.childNodes[i];
142
+ if (childNode.nodeType === 3) {
143
+ // Text node
144
+ const frag = renderMathInText(childNode.textContent, optionsCopy);
145
+ if (frag) {
146
+ i += frag.childNodes.length - 1;
147
+ elem.replaceChild(frag, childNode);
148
+ }
149
+ } else if (childNode.nodeType === 1) {
150
+ // Element node
151
+ const className = " " + childNode.className + " ";
152
+ const shouldRender =
153
+ optionsCopy.ignoredTags.indexOf(childNode.nodeName.toLowerCase()) === -1 &&
154
+ optionsCopy.ignoredClasses.every((x) => className.indexOf(" " + x + " ") === -1);
155
+
156
+ if (shouldRender) {
157
+ renderElem(childNode, optionsCopy);
158
+ }
159
+ }
160
+ // Otherwise, it's something else, and ignore it.
161
+ }
162
+ };
163
+
164
+ const renderMathInElement = function(elem, options) {
165
+ if (!elem) {
166
+ throw new Error("No element provided to render");
167
+ }
168
+
169
+ const optionsCopy = {};
170
+
171
+ // Object.assign(optionsCopy, option)
172
+ for (const option in options) {
173
+ if (Object.prototype.hasOwnProperty.call(options, option)) {
174
+ optionsCopy[option] = options[option];
175
+ }
176
+ }
177
+
178
+ // default options
179
+ optionsCopy.delimiters = optionsCopy.delimiters || [
180
+ { left: "$$", right: "$$", display: true },
181
+ { left: "\\(", right: "\\)", display: false },
182
+ // LaTeX uses $…$, but it ruins the display of normal `$` in text:
183
+ // {left: "$", right: "$", display: false},
184
+ // $ must come after $$
185
+
186
+ // Render AMS environments even if outside $$…$$ delimiters.
187
+ { left: "\\begin{equation}", right: "\\end{equation}", display: true },
188
+ { left: "\\begin{align}", right: "\\end{align}", display: true },
189
+ { left: "\\begin{alignat}", right: "\\end{alignat}", display: true },
190
+ { left: "\\begin{gather}", right: "\\end{gather}", display: true },
191
+ { left: "\\begin{CD}", right: "\\end{CD}", display: true },
192
+
193
+ { left: "\\[", right: "\\]", display: true }
194
+ ];
195
+ optionsCopy.ignoredTags = optionsCopy.ignoredTags || [
196
+ "script",
197
+ "noscript",
198
+ "style",
199
+ "textarea",
200
+ "pre",
201
+ "code",
202
+ "option"
203
+ ];
204
+ optionsCopy.ignoredClasses = optionsCopy.ignoredClasses || [];
205
+ optionsCopy.errorCallback = optionsCopy.errorCallback || console.error;
206
+
207
+ // Enable sharing of global macros defined via `\gdef` between different
208
+ // math elements within a single call to `renderMathInElement`.
209
+ optionsCopy.macros = optionsCopy.macros || {};
210
+
211
+ renderElem(elem, optionsCopy);
212
+ temml__default["default"].postProcess(elem);
213
+ };
214
+
215
+ return renderMathInElement;
216
+
217
+ })(temml);
@@ -0,0 +1 @@
1
+ var renderMathInElement=function(e){"use strict";function t(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var n=t(e);const r=function(e,t,n){let r=n,a=0;const i=e.length;for(;r<t.length;){const n=t[r];if(a<=0&&t.slice(r,r+i)===e)return r;"\\"===n?r++:"{"===n?a++:"}"===n&&a--,r++}return-1},a=/^\\begin{/,i=function(e,t){const i=function(e,t){let n;const i=[],l=new RegExp("("+t.map((e=>e.left.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"))).join("|")+")");for(;n=e.search(l),-1!==n;){n>0&&(i.push({type:"text",data:e.slice(0,n)}),e=e.slice(n));const l=t.findIndex((t=>e.startsWith(t.left)));if(n=r(t[l].right,e,t[l].left.length),-1===n)break;const o=e.slice(0,n+t[l].right.length),s=a.test(o)?o:e.slice(t[l].left.length,n);i.push({type:"math",data:s,rawData:o,display:t[l].display}),e=e.slice(n+t[l].right.length)}return""!==e&&i.push({type:"text",data:e}),i}(e,t.delimiters);if(1===i.length&&"text"===i[0].type)return null;const l=document.createDocumentFragment();for(let e=0;e<i.length;e++)if("text"===i[e].type)l.appendChild(document.createTextNode(i[e].data));else{const r=document.createElement("span");let a=i[e].data;t.displayMode=i[e].display;try{t.preProcess&&(a=t.preProcess(a)),n.default.render(a,r,t)}catch(r){if(!(r instanceof n.default.ParseError))throw r;t.errorCallback("Temml auto-render: Failed to parse `"+i[e].data+"` with ",r),l.appendChild(document.createTextNode(i[e].rawData));continue}l.appendChild(r)}return l},l=function(e,t){for(let n=0;n<e.childNodes.length;n++){const r=e.childNodes[n];if(3===r.nodeType){const a=i(r.textContent,t);a&&(n+=a.childNodes.length-1,e.replaceChild(a,r))}else if(1===r.nodeType){const e=" "+r.className+" ";-1===t.ignoredTags.indexOf(r.nodeName.toLowerCase())&&t.ignoredClasses.every((t=>-1===e.indexOf(" "+t+" ")))&&l(r,t)}}};return function(e,t){if(!e)throw new Error("No element provided to render");const r={};for(const e in t)Object.prototype.hasOwnProperty.call(t,e)&&(r[e]=t[e]);r.delimiters=r.delimiters||[{left:"$$",right:"$$",display:!0},{left:"\\(",right:"\\)",display:!1},{left:"\\begin{equation}",right:"\\end{equation}",display:!0},{left:"\\begin{align}",right:"\\end{align}",display:!0},{left:"\\begin{alignat}",right:"\\end{alignat}",display:!0},{left:"\\begin{gather}",right:"\\end{gather}",display:!0},{left:"\\begin{CD}",right:"\\end{CD}",display:!0},{left:"\\[",right:"\\]",display:!0}],r.ignoredTags=r.ignoredTags||["script","noscript","style","textarea","pre","code","option"],r.ignoredClasses=r.ignoredClasses||[],r.errorCallback=r.errorCallback||console.error,r.macros=r.macros||{},l(e,r),n.default.postProcess(e)}}(temml);
@@ -0,0 +1,84 @@
1
+ /* eslint no-constant-condition:0 */
2
+ const findEndOfMath = function(delimiter, text, startIndex) {
3
+ // Adapted from
4
+ // https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx
5
+ let index = startIndex;
6
+ let braceLevel = 0;
7
+
8
+ const delimLength = delimiter.length;
9
+
10
+ while (index < text.length) {
11
+ const character = text[index];
12
+
13
+ if (braceLevel <= 0 && text.slice(index, index + delimLength) === delimiter) {
14
+ return index;
15
+ } else if (character === "\\") {
16
+ index++;
17
+ } else if (character === "{") {
18
+ braceLevel++;
19
+ } else if (character === "}") {
20
+ braceLevel--;
21
+ }
22
+
23
+ index++;
24
+ }
25
+
26
+ return -1;
27
+ };
28
+
29
+ const escapeRegex = function(string) {
30
+ return string.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
31
+ };
32
+
33
+ const amsRegex = /^\\begin{/;
34
+
35
+ const splitAtDelimiters = function(text, delimiters) {
36
+ let index;
37
+ const data = [];
38
+
39
+ const regexLeft = new RegExp(
40
+ "(" + delimiters.map((x) => escapeRegex(x.left)).join("|") + ")"
41
+ )
42
+
43
+ while (true) {
44
+ index = text.search(regexLeft);
45
+ if (index === -1) {
46
+ break;
47
+ }
48
+ if (index > 0) {
49
+ data.push({
50
+ type: "text",
51
+ data: text.slice(0, index)
52
+ });
53
+ text = text.slice(index); // now text starts with delimiter
54
+ }
55
+ // ... so this always succeeds:
56
+ const i = delimiters.findIndex((delim) => text.startsWith(delim.left));
57
+ index = findEndOfMath(delimiters[i].right, text, delimiters[i].left.length);
58
+ if (index === -1) {
59
+ break;
60
+ }
61
+ const rawData = text.slice(0, index + delimiters[i].right.length);
62
+ const math = amsRegex.test(rawData)
63
+ ? rawData
64
+ : text.slice(delimiters[i].left.length, index);
65
+ data.push({
66
+ type: "math",
67
+ data: math,
68
+ rawData,
69
+ display: delimiters[i].display
70
+ });
71
+ text = text.slice(index + delimiters[i].right.length);
72
+ }
73
+
74
+ if (text !== "") {
75
+ data.push({
76
+ type: "text",
77
+ data: text
78
+ });
79
+ }
80
+
81
+ return data;
82
+ };
83
+
84
+ export default splitAtDelimiters;