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
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import defineFunction, { ordargument } from "../defineFunction";
|
|
2
|
+
import * as mml from "../buildMathML";
|
|
3
|
+
|
|
4
|
+
// Non-mathy text, possibly in a font
|
|
5
|
+
const textFontFamilies = {
|
|
6
|
+
"\\text": undefined,
|
|
7
|
+
"\\textrm": "textrm",
|
|
8
|
+
"\\textsf": "textsf",
|
|
9
|
+
"\\texttt": "texttt",
|
|
10
|
+
"\\textnormal": "textrm",
|
|
11
|
+
"\\textsc": "textsc" // small caps
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const textFontWeights = {
|
|
15
|
+
"\\textbf": "textbf",
|
|
16
|
+
"\\textmd": "textmd"
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const textFontShapes = {
|
|
20
|
+
"\\textit": "textit",
|
|
21
|
+
"\\textup": "textup"
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const styleWithFont = (group, style) => {
|
|
25
|
+
const font = group.font;
|
|
26
|
+
// Checks if the argument is a font family or a font style.
|
|
27
|
+
if (!font) {
|
|
28
|
+
return style;
|
|
29
|
+
} else if (textFontFamilies[font]) {
|
|
30
|
+
return style.withTextFontFamily(textFontFamilies[font]);
|
|
31
|
+
} else if (textFontWeights[font]) {
|
|
32
|
+
return style.withTextFontWeight(textFontWeights[font]);
|
|
33
|
+
} else {
|
|
34
|
+
return style.withTextFontShape(textFontShapes[font]);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
defineFunction({
|
|
39
|
+
type: "text",
|
|
40
|
+
names: [
|
|
41
|
+
// Font families
|
|
42
|
+
"\\text",
|
|
43
|
+
"\\textrm",
|
|
44
|
+
"\\textsf",
|
|
45
|
+
"\\texttt",
|
|
46
|
+
"\\textnormal",
|
|
47
|
+
"\\textsc",
|
|
48
|
+
// Font weights
|
|
49
|
+
"\\textbf",
|
|
50
|
+
"\\textmd",
|
|
51
|
+
// Font Shapes
|
|
52
|
+
"\\textit",
|
|
53
|
+
"\\textup"
|
|
54
|
+
],
|
|
55
|
+
props: {
|
|
56
|
+
numArgs: 1,
|
|
57
|
+
argTypes: ["text"],
|
|
58
|
+
allowedInArgument: true,
|
|
59
|
+
allowedInText: true
|
|
60
|
+
},
|
|
61
|
+
handler({ parser, funcName }, args) {
|
|
62
|
+
const body = args[0];
|
|
63
|
+
return {
|
|
64
|
+
type: "text",
|
|
65
|
+
mode: parser.mode,
|
|
66
|
+
body: ordargument(body),
|
|
67
|
+
font: funcName
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
mathmlBuilder(group, style) {
|
|
71
|
+
const newStyle = styleWithFont(group, style)
|
|
72
|
+
const mrow = mml.buildExpressionRow(group.body, newStyle)
|
|
73
|
+
return mml.consolidateText(mrow)
|
|
74
|
+
}
|
|
75
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import defineFunction from "../defineFunction";
|
|
2
|
+
import mathMLTree from "../mathMLTree";
|
|
3
|
+
import * as mml from "../buildMathML";
|
|
4
|
+
|
|
5
|
+
// Two functions included to enable migration from Mathjax.
|
|
6
|
+
|
|
7
|
+
defineFunction({
|
|
8
|
+
type: "tip",
|
|
9
|
+
names: ["\\mathtip"],
|
|
10
|
+
props: {
|
|
11
|
+
numArgs: 2
|
|
12
|
+
},
|
|
13
|
+
handler({ parser }, args) {
|
|
14
|
+
return {
|
|
15
|
+
type: "tip",
|
|
16
|
+
mode: parser.mode,
|
|
17
|
+
body: args[0],
|
|
18
|
+
tip: args[1]
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
mathmlBuilder: (group, style) => {
|
|
22
|
+
const math = mml.buildGroup(group.body, style)
|
|
23
|
+
const tip = mml.buildGroup(group.tip, style)
|
|
24
|
+
// Browsers don't support the tooltip actiontype.
|
|
25
|
+
// TODO: Come back and fix \mathtip when it can be done via CSS w/o a JS event.
|
|
26
|
+
const node = new mathMLTree.MathNode("maction", [math, tip], ["tml-tip"])
|
|
27
|
+
node.setAttribute("actiontype", "tooltip")
|
|
28
|
+
return node
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
defineFunction({
|
|
33
|
+
type: "tip",
|
|
34
|
+
names: ["\\texttip"],
|
|
35
|
+
props: {
|
|
36
|
+
numArgs: 2,
|
|
37
|
+
argTypes: ["math", "text"]
|
|
38
|
+
},
|
|
39
|
+
handler({ parser }, args) {
|
|
40
|
+
return {
|
|
41
|
+
type: "tip",
|
|
42
|
+
mode: parser.mode,
|
|
43
|
+
body: args[0],
|
|
44
|
+
tip: args[1]
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
mathmlBuilder: (group, style) => {
|
|
48
|
+
const math = mml.buildGroup(group.body, style)
|
|
49
|
+
const tip = mml.buildGroup(group.tip, style)
|
|
50
|
+
// args[1] only accepted text, so tip is a <mtext> element or a <mrow> of them.
|
|
51
|
+
let str = ""
|
|
52
|
+
if (tip.type === "mtext") {
|
|
53
|
+
str = tip.children[0].text
|
|
54
|
+
} else {
|
|
55
|
+
for (const child of tip.children) {
|
|
56
|
+
str += child.children[0].text
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Implement \texttip via a title attribute.
|
|
60
|
+
math.setAttribute("title", str)
|
|
61
|
+
return math
|
|
62
|
+
}
|
|
63
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineFunctionBuilders } from "../defineFunction";
|
|
2
|
+
import mathMLTree from "../mathMLTree";
|
|
3
|
+
import * as mml from "../buildMathML";
|
|
4
|
+
|
|
5
|
+
defineFunctionBuilders({
|
|
6
|
+
type: "toggle",
|
|
7
|
+
mathmlBuilder(group, style) {
|
|
8
|
+
const expression = mml.buildExpression(group.body, style)
|
|
9
|
+
const node = new mathMLTree.MathNode("maction", expression, [], { cursor: "default" })
|
|
10
|
+
node.setAttribute("actiontype", "toggle")
|
|
11
|
+
return node
|
|
12
|
+
}
|
|
13
|
+
})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import defineFunction from "../defineFunction";
|
|
2
|
+
import mathMLTree from "../mathMLTree";
|
|
3
|
+
import ParseError from "../ParseError";
|
|
4
|
+
|
|
5
|
+
defineFunction({
|
|
6
|
+
type: "verb",
|
|
7
|
+
names: ["\\verb"],
|
|
8
|
+
props: {
|
|
9
|
+
numArgs: 0,
|
|
10
|
+
allowedInText: true
|
|
11
|
+
},
|
|
12
|
+
handler(context, args, optArgs) {
|
|
13
|
+
// \verb and \verb* are dealt with directly in Parser.js.
|
|
14
|
+
// If we end up here, it's because of a failure to match the two delimiters
|
|
15
|
+
// in the regex in Lexer.js. LaTeX raises the following error when \verb is
|
|
16
|
+
// terminated by end of line (or file).
|
|
17
|
+
throw new ParseError("\\verb ended by end of line instead of matching delimiter");
|
|
18
|
+
},
|
|
19
|
+
mathmlBuilder(group, style) {
|
|
20
|
+
const text = new mathMLTree.TextNode(makeVerb(group));
|
|
21
|
+
const node = new mathMLTree.MathNode("mtext", [text]);
|
|
22
|
+
node.setAttribute("mathvariant", "monospace");
|
|
23
|
+
return node;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Converts verb group into body string.
|
|
29
|
+
*
|
|
30
|
+
* \verb* replaces each space with an open box \u2423
|
|
31
|
+
* \verb replaces each space with a no-break space \xA0
|
|
32
|
+
*/
|
|
33
|
+
const makeVerb = (group) => group.body.replace(/ /g, group.star ? "\u2423" : "\xA0");
|
package/src/functions.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** Include this to ensure that all functions are defined. */
|
|
2
|
+
import { _functions } from "./defineFunction";
|
|
3
|
+
|
|
4
|
+
const functions = _functions;
|
|
5
|
+
export default functions;
|
|
6
|
+
|
|
7
|
+
// TODO(kevinb): have functions return an object and call defineFunction with
|
|
8
|
+
// that object in this file instead of relying on side-effects.
|
|
9
|
+
import "./functions/accent";
|
|
10
|
+
import "./functions/accentunder";
|
|
11
|
+
import "./functions/arrow";
|
|
12
|
+
//import "./functions/cancelto";
|
|
13
|
+
import "./environments/cd";
|
|
14
|
+
import "./functions/char";
|
|
15
|
+
import "./functions/color";
|
|
16
|
+
import "./functions/cr";
|
|
17
|
+
import "./functions/def";
|
|
18
|
+
import "./functions/delimsizing";
|
|
19
|
+
import "./functions/enclose";
|
|
20
|
+
import "./functions/environment";
|
|
21
|
+
import "./functions/envTag";
|
|
22
|
+
import "./functions/font";
|
|
23
|
+
import "./functions/genfrac";
|
|
24
|
+
import "./functions/horizBrace";
|
|
25
|
+
import "./functions/href";
|
|
26
|
+
import "./functions/html";
|
|
27
|
+
import "./functions/includegraphics";
|
|
28
|
+
import "./functions/kern";
|
|
29
|
+
import "./functions/label";
|
|
30
|
+
import "./functions/lap";
|
|
31
|
+
import "./functions/math";
|
|
32
|
+
import "./functions/mathchoice";
|
|
33
|
+
import "./functions/mclass";
|
|
34
|
+
import "./functions/multiscript";
|
|
35
|
+
import "./functions/not";
|
|
36
|
+
import "./functions/op";
|
|
37
|
+
import "./functions/operatorname";
|
|
38
|
+
import "./functions/ordgroup";
|
|
39
|
+
import "./functions/phantom";
|
|
40
|
+
import "./functions/pmb";
|
|
41
|
+
import "./functions/raise";
|
|
42
|
+
import "./functions/ref";
|
|
43
|
+
import "./functions/relax";
|
|
44
|
+
import "./functions/rule";
|
|
45
|
+
import "./functions/sizing";
|
|
46
|
+
import "./functions/smash";
|
|
47
|
+
import "./functions/sqrt";
|
|
48
|
+
import "./functions/styling";
|
|
49
|
+
import "./functions/supsub";
|
|
50
|
+
import "./functions/symbolsOp";
|
|
51
|
+
import "./functions/symbolsOrd";
|
|
52
|
+
import "./functions/symbolsSpacing";
|
|
53
|
+
import "./functions/tag";
|
|
54
|
+
import "./functions/text";
|
|
55
|
+
// import "./functions/tip";
|
|
56
|
+
// import "./functions/toggle";
|
|
57
|
+
import "./functions/verb";
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import mathMLTree from "./mathMLTree"
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Neither Firefox nor Chrome support hard line breaks or soft line breaks.
|
|
5
|
+
* (Despite https://www.w3.org/Math/draft-spec/mathml.html#chapter3_presm.lbattrs)
|
|
6
|
+
* So Temml has work-arounds for both hard and soft breaks.
|
|
7
|
+
* The work-arounds sadly do not work simultaneously. Any top-level hard
|
|
8
|
+
* break makes soft line breaks impossible.
|
|
9
|
+
*
|
|
10
|
+
* Hard breaks are simulated by creating a <mtable> and putting each line in its own <mtr>.
|
|
11
|
+
*
|
|
12
|
+
* To create soft line breaks, Temml avoids using the <semantics> and <annotation> tags.
|
|
13
|
+
* Then the top level of a <math> element can be occupied by <mrow> elements, and the browser
|
|
14
|
+
* will break after a <mrow> if the expression extends beyond the container limit.
|
|
15
|
+
*
|
|
16
|
+
* We want the expression to render with soft line breaks after each top-level binary or
|
|
17
|
+
* relational operator, per TeXbook p. 173. So we gather the expression into <mrow>s so that
|
|
18
|
+
* each <mrow> ends in a binary or relational operator.
|
|
19
|
+
*
|
|
20
|
+
* Soft line breaks will not work in Chromium and Safari, only Firefox.
|
|
21
|
+
*
|
|
22
|
+
* Hopefully browsers will someday do their own linebreaking and we will be able to delete
|
|
23
|
+
* much of this module.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
export default function setLineBreaks(expression, wrapMode, isDisplayMode, color) {
|
|
27
|
+
if (color === undefined && wrapMode !== "none") {
|
|
28
|
+
// First, make one pass through the expression and split any color nodes.
|
|
29
|
+
const upperLimit = expression.length - 1
|
|
30
|
+
for (let i = upperLimit; i >= 0; i--) {
|
|
31
|
+
const node = expression[i];
|
|
32
|
+
if (node.type === "mstyle" && node.attributes.mathcolor) {
|
|
33
|
+
const color = node.attributes.mathcolor
|
|
34
|
+
const fragment = setLineBreaks(node.children, wrapMode, isDisplayMode, color)
|
|
35
|
+
if (!(fragment.type && fragment.type !== "mtable")) {
|
|
36
|
+
expression.splice(i, 1, ...fragment.children)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const tagName = color ? "mstyle" : "mrow"
|
|
43
|
+
|
|
44
|
+
const mtrs = [];
|
|
45
|
+
let mrows = [];
|
|
46
|
+
let block = [];
|
|
47
|
+
let numTopLevelEquals = 0
|
|
48
|
+
let canBeBIN = false // The first node cannot be an infix binary operator.
|
|
49
|
+
for (let i = 0; i < expression.length; i++) {
|
|
50
|
+
const node = expression[i];
|
|
51
|
+
if (node.type && node.type === "mstyle" && node.attributes.mathcolor) {
|
|
52
|
+
if (block.length > 0) {
|
|
53
|
+
// Start a new block. (Insert a soft linebreak.)
|
|
54
|
+
mrows.push(new mathMLTree.MathNode(tagName, block))
|
|
55
|
+
}
|
|
56
|
+
// Insert the mstyle
|
|
57
|
+
mrows.push(node)
|
|
58
|
+
block = [];
|
|
59
|
+
continue
|
|
60
|
+
}
|
|
61
|
+
if (node.attributes && node.attributes.linebreak &&
|
|
62
|
+
node.attributes.linebreak === "newline") {
|
|
63
|
+
// A hard line break. Create a <mtr> for the current block.
|
|
64
|
+
if (block.length > 0) {
|
|
65
|
+
const element = new mathMLTree.MathNode(tagName, block)
|
|
66
|
+
if (color) { element.setAttribute("mathcolor", color) }
|
|
67
|
+
mrows.push(new mathMLTree.MathNode(tagName, block))
|
|
68
|
+
}
|
|
69
|
+
mrows.push(node)
|
|
70
|
+
block = [];
|
|
71
|
+
const mtd = new mathMLTree.MathNode("mtd", mrows)
|
|
72
|
+
mtrs.push(new mathMLTree.MathNode("mtr", [mtd]))
|
|
73
|
+
mrows = [];
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
block.push(node);
|
|
77
|
+
if (node.type && node.type === "mo" && wrapMode === "=") {
|
|
78
|
+
if (node.children.length === 1 && node.children[0].text === "=") {
|
|
79
|
+
numTopLevelEquals += 1
|
|
80
|
+
if (numTopLevelEquals > 1) {
|
|
81
|
+
block.pop()
|
|
82
|
+
// Start a new block. (Insert a soft linebreak.)
|
|
83
|
+
const element = new mathMLTree.MathNode(tagName, block)
|
|
84
|
+
if (color) { element.setAttribute("mathcolor", color) }
|
|
85
|
+
mrows.push(element)
|
|
86
|
+
block = [node];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} else if (node.type && node.type === "mo" && wrapMode === "tex") {
|
|
90
|
+
// This may be a place for a soft line break.
|
|
91
|
+
if (canBeBIN && !node.attributes.form) {
|
|
92
|
+
// Check if the following node is a \nobreak text node, e.g. "~""
|
|
93
|
+
const next = i < expression.length - 1 ? expression[i + 1] : null;
|
|
94
|
+
let glueIsFreeOfNobreak = true;
|
|
95
|
+
if (
|
|
96
|
+
!(
|
|
97
|
+
next &&
|
|
98
|
+
next.type === "mtext" &&
|
|
99
|
+
next.attributes.linebreak &&
|
|
100
|
+
next.attributes.linebreak === "nobreak"
|
|
101
|
+
)
|
|
102
|
+
) {
|
|
103
|
+
// We may need to start a new block.
|
|
104
|
+
// First, put any post-operator glue on same line as operator.
|
|
105
|
+
for (let j = i + 1; j < expression.length; j++) {
|
|
106
|
+
const nd = expression[j];
|
|
107
|
+
if (
|
|
108
|
+
nd.type &&
|
|
109
|
+
nd.type === "mspace" &&
|
|
110
|
+
!(nd.attributes.linebreak && nd.attributes.linebreak === "newline")
|
|
111
|
+
) {
|
|
112
|
+
block.push(nd);
|
|
113
|
+
i += 1;
|
|
114
|
+
if (
|
|
115
|
+
nd.attributes &&
|
|
116
|
+
nd.attributes.linebreak &&
|
|
117
|
+
nd.attributes.linebreak === "nobreak"
|
|
118
|
+
) {
|
|
119
|
+
glueIsFreeOfNobreak = false;
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (glueIsFreeOfNobreak) {
|
|
127
|
+
// Start a new block. (Insert a soft linebreak.)
|
|
128
|
+
const element = new mathMLTree.MathNode(tagName, block)
|
|
129
|
+
if (color) { element.setAttribute("mathcolor", color) }
|
|
130
|
+
mrows.push(element)
|
|
131
|
+
block = [];
|
|
132
|
+
}
|
|
133
|
+
canBeBIN = false;
|
|
134
|
+
}
|
|
135
|
+
const isOpenDelimiter = node.attributes.form && node.attributes.form === "prefix";
|
|
136
|
+
// Any operator that follows an open delimiter is unary.
|
|
137
|
+
canBeBIN = !(node.attributes.separator || isOpenDelimiter);
|
|
138
|
+
} else {
|
|
139
|
+
canBeBIN = true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (block.length > 0) {
|
|
143
|
+
const element = new mathMLTree.MathNode(tagName, block)
|
|
144
|
+
if (color) { element.setAttribute("mathcolor", color) }
|
|
145
|
+
mrows.push(element)
|
|
146
|
+
}
|
|
147
|
+
if (mtrs.length > 0) {
|
|
148
|
+
const mtd = new mathMLTree.MathNode("mtd", mrows)
|
|
149
|
+
const mtr = new mathMLTree.MathNode("mtr", [mtd])
|
|
150
|
+
mtrs.push(mtr)
|
|
151
|
+
const mtable = new mathMLTree.MathNode("mtable", mtrs)
|
|
152
|
+
if (!isDisplayMode) {
|
|
153
|
+
mtable.setAttribute("columnalign", "left")
|
|
154
|
+
mtable.setAttribute("rowspacing", "0em")
|
|
155
|
+
}
|
|
156
|
+
return mtable
|
|
157
|
+
}
|
|
158
|
+
return mathMLTree.newDocumentFragment(mrows);
|
|
159
|
+
}
|