temml 0.13.1 → 0.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -4
- package/contrib/mhchem/mhchem.min.js +1 -1
- package/dist/Temml-Asana.css +11 -13
- package/dist/Temml-Latin-Modern.css +11 -13
- package/dist/Temml-Libertinus.css +11 -13
- package/dist/Temml-Local.css +11 -13
- package/dist/Temml-NotoSans.css +11 -13
- package/dist/Temml-STIX2.css +11 -13
- package/dist/temml.cjs +220 -114
- package/dist/temml.js +220 -114
- package/dist/temml.min.js +1 -1
- package/dist/temml.mjs +220 -114
- package/dist/temmlPostProcess.js +1 -1
- package/package.json +2 -2
- package/src/Parser.js +5 -4
- package/src/Settings.js +1 -0
- package/src/functions/cancelto.js +2 -0
- package/src/functions/color.js +1 -1
- package/src/functions/{delimsizing.js → delimiter.js} +132 -42
- package/src/functions/enclose.js +1 -1
- package/src/functions/genfrac.js +32 -45
- package/src/functions/mclass.js +10 -2
- package/src/functions/op.js +1 -1
- package/src/functions/operatorname.js +9 -1
- package/src/functions/symbolsOrd.js +2 -2
- package/src/functions.js +1 -1
- package/src/linebreaking.js +3 -10
- package/src/macros.js +1 -0
- package/src/parseNode.js +1 -1
- package/src/parseTree.js +20 -4
- package/src/postProcess.js +1 -1
- package/src/symbols.js +2 -3
package/dist/temml.cjs
CHANGED
|
@@ -215,6 +215,7 @@ class Settings {
|
|
|
215
215
|
: [Infinity, Infinity]
|
|
216
216
|
);
|
|
217
217
|
this.maxExpand = Math.max(0, deflt(options.maxExpand, 1000)); // number
|
|
218
|
+
this.wrapDelimiterPairs = true; // boolean
|
|
218
219
|
}
|
|
219
220
|
|
|
220
221
|
/**
|
|
@@ -996,8 +997,7 @@ defineSymbol(math, textord, "\u2135", "\\aleph", true);
|
|
|
996
997
|
defineSymbol(math, textord, "\u2200", "\\forall", true);
|
|
997
998
|
defineSymbol(math, textord, "\u210f", "\\hbar", true);
|
|
998
999
|
defineSymbol(math, textord, "\u2203", "\\exists", true);
|
|
999
|
-
|
|
1000
|
-
defineSymbol(math, bin, "\u2207", "\\nabla", true);
|
|
1000
|
+
defineSymbol(math, open, "\u2207", "\\nabla", true);
|
|
1001
1001
|
defineSymbol(math, textord, "\u266d", "\\flat", true);
|
|
1002
1002
|
defineSymbol(math, textord, "\u2113", "\\ell", true);
|
|
1003
1003
|
defineSymbol(math, textord, "\u266e", "\\natural", true);
|
|
@@ -1090,7 +1090,7 @@ defineSymbol(math, mathord, "\u2295", "\\Earth");
|
|
|
1090
1090
|
|
|
1091
1091
|
// AMS Negated Binary Relations
|
|
1092
1092
|
defineSymbol(math, rel, "\u226e", "\\nless", true);
|
|
1093
|
-
// Symbol names
|
|
1093
|
+
// Symbol names preceded by "@" each have a corresponding macro.
|
|
1094
1094
|
defineSymbol(math, rel, "\u2a87", "\\lneq", true);
|
|
1095
1095
|
defineSymbol(math, rel, "\u2268", "\\lneqq", true);
|
|
1096
1096
|
defineSymbol(math, rel, "\u2268\ufe00", "\\lvertneqq");
|
|
@@ -2001,16 +2001,12 @@ for (let i = 0; i < 10; i++) {
|
|
|
2001
2001
|
* much of this module.
|
|
2002
2002
|
*/
|
|
2003
2003
|
|
|
2004
|
-
const openDelims = "([{⌊⌈⟨⟮⎰⟦⦃";
|
|
2005
|
-
const closeDelims = ")]}⌋⌉⟩⟯⎱⟦⦄";
|
|
2006
|
-
|
|
2007
2004
|
function setLineBreaks(expression, wrapMode, isDisplayMode) {
|
|
2008
2005
|
const mtrs = [];
|
|
2009
2006
|
let mrows = [];
|
|
2010
2007
|
let block = [];
|
|
2011
2008
|
let numTopLevelEquals = 0;
|
|
2012
2009
|
let i = 0;
|
|
2013
|
-
let level = 0;
|
|
2014
2010
|
while (i < expression.length) {
|
|
2015
2011
|
while (expression[i] instanceof DocumentFragment) {
|
|
2016
2012
|
expression.splice(i, 1, ...expression[i].children); // Expand the fragment.
|
|
@@ -2033,13 +2029,10 @@ function setLineBreaks(expression, wrapMode, isDisplayMode) {
|
|
|
2033
2029
|
}
|
|
2034
2030
|
block.push(node);
|
|
2035
2031
|
if (node.type && node.type === "mo" && node.children.length === 1 &&
|
|
2032
|
+
!(node.attributes.form && node.attributes.form === "prefix") && // unary operators
|
|
2036
2033
|
!Object.prototype.hasOwnProperty.call(node.attributes, "movablelimits")) {
|
|
2037
2034
|
const ch = node.children[0].text;
|
|
2038
|
-
if (
|
|
2039
|
-
level += 1;
|
|
2040
|
-
} else if (closeDelims.indexOf(ch) > -1) {
|
|
2041
|
-
level -= 1;
|
|
2042
|
-
} else if (level === 0 && wrapMode === "=" && ch === "=") {
|
|
2035
|
+
if (wrapMode === "=" && ch === "=") {
|
|
2043
2036
|
numTopLevelEquals += 1;
|
|
2044
2037
|
if (numTopLevelEquals > 1) {
|
|
2045
2038
|
block.pop();
|
|
@@ -2048,7 +2041,7 @@ function setLineBreaks(expression, wrapMode, isDisplayMode) {
|
|
|
2048
2041
|
mrows.push(element);
|
|
2049
2042
|
block = [node];
|
|
2050
2043
|
}
|
|
2051
|
-
} else if (
|
|
2044
|
+
} else if (wrapMode === "tex") {
|
|
2052
2045
|
// Check if the following node is a \nobreak text node, e.g. "~""
|
|
2053
2046
|
const next = i < expression.length - 1 ? expression[i + 1] : null;
|
|
2054
2047
|
let glueIsFreeOfNobreak = true;
|
|
@@ -3070,7 +3063,7 @@ function assertSymbolNodeType(node) {
|
|
|
3070
3063
|
* returns null.
|
|
3071
3064
|
*/
|
|
3072
3065
|
function checkSymbolNodeType(node) {
|
|
3073
|
-
if (node && (node.type === "atom" ||
|
|
3066
|
+
if (node && (node.type === "atom" || node.type === "delimiter" ||
|
|
3074
3067
|
Object.prototype.hasOwnProperty.call(NON_ATOMS, node.type))) {
|
|
3075
3068
|
return node;
|
|
3076
3069
|
}
|
|
@@ -4252,6 +4245,7 @@ defineMacro("\\upomega", "\\up@greek{\\omega}");
|
|
|
4252
4245
|
// cmll package
|
|
4253
4246
|
defineMacro("\\invamp", '\\mathbin{\\char"214b}');
|
|
4254
4247
|
defineMacro("\\parr", '\\mathbin{\\char"214b}');
|
|
4248
|
+
defineMacro("\\upand", '\\mathbin{\\char"214b}'); // STIX package
|
|
4255
4249
|
defineMacro("\\with", '\\mathbin{\\char"26}');
|
|
4256
4250
|
defineMacro("\\multimapinv", '\\mathrel{\\char"27dc}');
|
|
4257
4251
|
defineMacro("\\multimapboth", '\\mathrel{\\char"29df}');
|
|
@@ -7223,6 +7217,7 @@ defineFunction({
|
|
|
7223
7217
|
// That way, the arrow will be an overlay on the content.
|
|
7224
7218
|
const phantom = new MathNode("mphantom", [buildGroup$1(group.body, style)]);
|
|
7225
7219
|
const arrow = new MathNode("mrow", [phantom], ["tml-cancelto"]);
|
|
7220
|
+
arrow.style.color = style.color;
|
|
7226
7221
|
if (group.isCharacterBox && smalls.indexOf(group.body.body[0].text) > -1) {
|
|
7227
7222
|
arrow.style.left = "0.1em";
|
|
7228
7223
|
arrow.style.width = "90%";
|
|
@@ -7254,6 +7249,7 @@ defineFunction({
|
|
|
7254
7249
|
dummyNode = new MathNode("mphantom", [zeroWidthNode]); // Hide it.
|
|
7255
7250
|
}
|
|
7256
7251
|
const toNode = buildGroup$1(group.to, style);
|
|
7252
|
+
toNode.style.color = style.color;
|
|
7257
7253
|
const zeroWidthToNode = new MathNode("mpadded", [toNode]);
|
|
7258
7254
|
if (!group.isCharacterBox || /[f∫∑]/.test(group.body.body[0].text)) {
|
|
7259
7255
|
const w = new MathNode("mspace", []);
|
|
@@ -7312,7 +7308,7 @@ const toHex = num => {
|
|
|
7312
7308
|
|
|
7313
7309
|
// Colors from Tables 4.1 and 4.2 of the xcolor package.
|
|
7314
7310
|
// Table 4.1 (lower case) RGB values are taken from chroma and xcolor.dtx.
|
|
7315
|
-
// Table 4.2 (
|
|
7311
|
+
// Table 4.2 (Capitalized) values were sampled, because Chroma contains a unreliable
|
|
7316
7312
|
// conversion from cmyk to RGB. See https://tex.stackexchange.com/a/537274.
|
|
7317
7313
|
const xcolors = JSON.parse(`{
|
|
7318
7314
|
"Apricot": "#ffb484",
|
|
@@ -7871,7 +7867,41 @@ const delimiterSizes = {
|
|
|
7871
7867
|
"\\Bigg": { mclass: "mord", size: 4 }
|
|
7872
7868
|
};
|
|
7873
7869
|
|
|
7874
|
-
const
|
|
7870
|
+
const leftToRight = {
|
|
7871
|
+
"(": ")",
|
|
7872
|
+
"\\lparen": "\\rparen",
|
|
7873
|
+
"[": "]",
|
|
7874
|
+
"\\lbrack": "\\rbrack",
|
|
7875
|
+
"\\{": "\\}",
|
|
7876
|
+
"\\lbrace": "\\rbrace",
|
|
7877
|
+
"⦇": "⦈",
|
|
7878
|
+
"\\llparenthesis": "\\rrparenthesis",
|
|
7879
|
+
"\\lfloor": "\\rfloor",
|
|
7880
|
+
"\u230a": "\u230b",
|
|
7881
|
+
"\\lceil": "\\rceil",
|
|
7882
|
+
"\u2308": "\u2309",
|
|
7883
|
+
"\\langle": "\\rangle",
|
|
7884
|
+
"\u27e8": "\u27e9",
|
|
7885
|
+
"\\lAngle": "\\rAngle",
|
|
7886
|
+
"\u27ea": "\u27eb",
|
|
7887
|
+
"\\llangle": "\\rrangle",
|
|
7888
|
+
"⦉": "⦊",
|
|
7889
|
+
"\\lvert": "\\rvert",
|
|
7890
|
+
"\\lVert": "\\rVert",
|
|
7891
|
+
"\\lgroup": "\\rgroup",
|
|
7892
|
+
"\u27ee": "\u27ef",
|
|
7893
|
+
"\\lmoustache": "\\rmoustache",
|
|
7894
|
+
"\u23b0": "\u23b1",
|
|
7895
|
+
"\\llbracket": "\\rrbracket",
|
|
7896
|
+
"\u27e6": "\u27e7",
|
|
7897
|
+
"\\lBrace": "\\rBrace",
|
|
7898
|
+
"\u2983": "\u2984"
|
|
7899
|
+
};
|
|
7900
|
+
|
|
7901
|
+
const leftDelimiterNames = new Set(Object.keys(leftToRight));
|
|
7902
|
+
new Set(Object.values(leftToRight));
|
|
7903
|
+
|
|
7904
|
+
const delimiters = new Set([
|
|
7875
7905
|
"(",
|
|
7876
7906
|
"\\lparen",
|
|
7877
7907
|
")",
|
|
@@ -7927,7 +7957,7 @@ const delimiters = [
|
|
|
7927
7957
|
"\\llbracket",
|
|
7928
7958
|
"\\rrbracket",
|
|
7929
7959
|
"\u27e6",
|
|
7930
|
-
"\
|
|
7960
|
+
"\u27e7",
|
|
7931
7961
|
"\\lBrace",
|
|
7932
7962
|
"\\rBrace",
|
|
7933
7963
|
"\u2983",
|
|
@@ -7946,12 +7976,12 @@ const delimiters = [
|
|
|
7946
7976
|
"\\updownarrow",
|
|
7947
7977
|
"\\Updownarrow",
|
|
7948
7978
|
"."
|
|
7949
|
-
];
|
|
7979
|
+
]);
|
|
7950
7980
|
|
|
7951
7981
|
// Export isDelimiter for benefit of parser.
|
|
7952
|
-
const dels = ["}", "\\left", "\\middle", "\\right"];
|
|
7982
|
+
const dels = new Set(["}", "\\left", "\\middle", "\\right"]);
|
|
7953
7983
|
const isDelimiter = str => str.length > 0 &&
|
|
7954
|
-
(delimiters.
|
|
7984
|
+
(delimiters.has(str) || delimiterSizes[str] || dels.has(str));
|
|
7955
7985
|
|
|
7956
7986
|
// Metrics of the different sizes. Found by looking at TeX's output of
|
|
7957
7987
|
// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
|
|
@@ -7964,11 +7994,11 @@ function checkDelimiter(delim, context) {
|
|
|
7964
7994
|
delim = delim.body[0]; // Unwrap the braces
|
|
7965
7995
|
}
|
|
7966
7996
|
const symDelim = checkSymbolNodeType(delim);
|
|
7967
|
-
if (symDelim && delimiters.
|
|
7997
|
+
if (symDelim && delimiters.has(symDelim.text)) {
|
|
7968
7998
|
// If a character is not in the MathML operator dictionary, it will not stretch.
|
|
7969
7999
|
// Replace such characters w/characters that will stretch.
|
|
7970
|
-
if (
|
|
7971
|
-
if (
|
|
8000
|
+
if (symDelim.text === "<" || symDelim.text === "\\lt") { symDelim.text = "⟨"; }
|
|
8001
|
+
if (symDelim.text === ">" || symDelim.text === "\\gt") { symDelim.text = "⟩"; }
|
|
7972
8002
|
return symDelim;
|
|
7973
8003
|
} else if (symDelim) {
|
|
7974
8004
|
throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim);
|
|
@@ -7978,7 +8008,16 @@ function checkDelimiter(delim, context) {
|
|
|
7978
8008
|
}
|
|
7979
8009
|
|
|
7980
8010
|
// / \
|
|
7981
|
-
const needExplicitStretch = ["\u002F", "\u005C", "\\backslash", "\\vert", "|"];
|
|
8011
|
+
const needExplicitStretch = new Set(["\u002F", "\u005C", "\\backslash", "\u2216", "\\vert", "|"]);
|
|
8012
|
+
|
|
8013
|
+
const makeFenceMo = (delim, mode, form, isStretchy) => {
|
|
8014
|
+
const text = delim === "." ? "" : delim;
|
|
8015
|
+
const node = new MathNode("mo", [makeText(text, mode)]);
|
|
8016
|
+
node.setAttribute("fence", "true");
|
|
8017
|
+
node.setAttribute("form", form);
|
|
8018
|
+
node.setAttribute("stretchy", isStretchy ? "true" : "false");
|
|
8019
|
+
return node;
|
|
8020
|
+
};
|
|
7982
8021
|
|
|
7983
8022
|
defineFunction({
|
|
7984
8023
|
type: "delimsizing",
|
|
@@ -8029,9 +8068,9 @@ defineFunction({
|
|
|
8029
8068
|
},
|
|
8030
8069
|
mathmlBuilder: (group) => {
|
|
8031
8070
|
const children = [];
|
|
8071
|
+
const delim = group.delim === "." ? "" : group.delim;
|
|
8032
8072
|
|
|
8033
|
-
|
|
8034
|
-
children.push(makeText(group.delim, group.mode));
|
|
8073
|
+
children.push(makeText(delim, group.mode));
|
|
8035
8074
|
|
|
8036
8075
|
const node = new MathNode("mo", children);
|
|
8037
8076
|
|
|
@@ -8044,7 +8083,7 @@ defineFunction({
|
|
|
8044
8083
|
// defaults.
|
|
8045
8084
|
node.setAttribute("fence", "false");
|
|
8046
8085
|
}
|
|
8047
|
-
if (needExplicitStretch.
|
|
8086
|
+
if (needExplicitStretch.has(delim) || delim.indexOf("arrow") > -1) {
|
|
8048
8087
|
// We have to explicitly set stretchy to true.
|
|
8049
8088
|
node.setAttribute("stretchy", "true");
|
|
8050
8089
|
}
|
|
@@ -8057,7 +8096,7 @@ defineFunction({
|
|
|
8057
8096
|
|
|
8058
8097
|
function assertParsed(group) {
|
|
8059
8098
|
if (!group.body) {
|
|
8060
|
-
throw new Error("Bug: The
|
|
8099
|
+
throw new Error("Bug: The delim ParseNode wasn't fully parsed.");
|
|
8061
8100
|
}
|
|
8062
8101
|
}
|
|
8063
8102
|
|
|
@@ -8088,17 +8127,10 @@ defineFunction({
|
|
|
8088
8127
|
const delim = checkDelimiter(args[0], context);
|
|
8089
8128
|
|
|
8090
8129
|
const parser = context.parser;
|
|
8091
|
-
// Parse out the implicit body
|
|
8092
8130
|
++parser.leftrightDepth;
|
|
8093
|
-
|
|
8094
|
-
let body = parser.parseExpression(false, null, true);
|
|
8131
|
+
let body = parser.parseExpression(false, "\\right", true);
|
|
8095
8132
|
let nextToken = parser.fetch();
|
|
8096
8133
|
while (nextToken.text === "\\middle") {
|
|
8097
|
-
// `\middle`, from the ε-TeX package, ends one group and starts another group.
|
|
8098
|
-
// We had to parse this expression with `breakOnMiddle` enabled in order
|
|
8099
|
-
// to get TeX-compliant parsing of \over.
|
|
8100
|
-
// But we do not want, at this point, to end on \middle, so continue
|
|
8101
|
-
// to parse until we fetch a `\right`.
|
|
8102
8134
|
parser.consume();
|
|
8103
8135
|
const middle = parser.fetch().text;
|
|
8104
8136
|
if (!symbols.math[middle]) {
|
|
@@ -8107,11 +8139,10 @@ defineFunction({
|
|
|
8107
8139
|
checkDelimiter({ type: "atom", mode: "math", text: middle }, { funcName: "\\middle" });
|
|
8108
8140
|
body.push({ type: "middle", mode: "math", delim: middle });
|
|
8109
8141
|
parser.consume();
|
|
8110
|
-
body = body.concat(parser.parseExpression(false,
|
|
8142
|
+
body = body.concat(parser.parseExpression(false, "\\right", true));
|
|
8111
8143
|
nextToken = parser.fetch();
|
|
8112
8144
|
}
|
|
8113
8145
|
--parser.leftrightDepth;
|
|
8114
|
-
// Check the next token
|
|
8115
8146
|
parser.expect("\\right", false);
|
|
8116
8147
|
const right = assertNodeType(parser.parseFunction(), "leftright-right");
|
|
8117
8148
|
return {
|
|
@@ -8119,35 +8150,90 @@ defineFunction({
|
|
|
8119
8150
|
mode: parser.mode,
|
|
8120
8151
|
body,
|
|
8121
8152
|
left: delim.text,
|
|
8122
|
-
right: right.delim
|
|
8153
|
+
right: right.delim,
|
|
8154
|
+
isStretchy: true
|
|
8123
8155
|
};
|
|
8124
8156
|
},
|
|
8125
8157
|
mathmlBuilder: (group, style) => {
|
|
8126
8158
|
assertParsed(group);
|
|
8127
8159
|
const inner = buildExpression(group.body, style);
|
|
8128
8160
|
|
|
8129
|
-
|
|
8130
|
-
const leftNode = new MathNode("mo", [makeText(group.left, group.mode)]);
|
|
8131
|
-
leftNode.setAttribute("fence", "true");
|
|
8132
|
-
leftNode.setAttribute("form", "prefix");
|
|
8133
|
-
if (group.left === "/" || group.left === "\u005C" || group.left.indexOf("arrow") > -1) {
|
|
8134
|
-
leftNode.setAttribute("stretchy", "true");
|
|
8135
|
-
}
|
|
8161
|
+
const leftNode = makeFenceMo(group.left, group.mode, "prefix", true);
|
|
8136
8162
|
inner.unshift(leftNode);
|
|
8137
8163
|
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8164
|
+
const rightNode = makeFenceMo(group.right, group.mode, "postfix", true);
|
|
8165
|
+
if (group.body.length > 0) {
|
|
8166
|
+
const lastElement = group.body[group.body.length - 1];
|
|
8167
|
+
if (lastElement.type === "color" && !lastElement.isTextColor) {
|
|
8168
|
+
rightNode.setAttribute("mathcolor", lastElement.color);
|
|
8169
|
+
}
|
|
8144
8170
|
}
|
|
8171
|
+
inner.push(rightNode);
|
|
8172
|
+
|
|
8173
|
+
return makeRow(inner);
|
|
8174
|
+
}
|
|
8175
|
+
});
|
|
8176
|
+
|
|
8177
|
+
defineFunction({
|
|
8178
|
+
type: "delimiter",
|
|
8179
|
+
names: Array.from(leftDelimiterNames),
|
|
8180
|
+
props: {
|
|
8181
|
+
numArgs: 0,
|
|
8182
|
+
allowedInText: true,
|
|
8183
|
+
allowedInMath: true,
|
|
8184
|
+
allowedInArgument: true
|
|
8185
|
+
},
|
|
8186
|
+
handler: ({ parser, funcName, token }) => {
|
|
8187
|
+
if (parser.mode === "text") {
|
|
8188
|
+
return {
|
|
8189
|
+
type: "textord",
|
|
8190
|
+
mode: "text",
|
|
8191
|
+
text: funcName,
|
|
8192
|
+
loc: token.loc
|
|
8193
|
+
}
|
|
8194
|
+
} else if (!parser.settings.wrapDelimiterPairs) {
|
|
8195
|
+
// Treat this token as an ordinary symbol.
|
|
8196
|
+
return {
|
|
8197
|
+
type: "atom",
|
|
8198
|
+
mode: "math",
|
|
8199
|
+
family: "open",
|
|
8200
|
+
loc: token.loc,
|
|
8201
|
+
text: funcName
|
|
8202
|
+
};
|
|
8203
|
+
}
|
|
8204
|
+
// Otherwise, try to wrap a pair of delimiters with an <mrow>.
|
|
8205
|
+
const rightDelim = leftToRight[funcName];
|
|
8206
|
+
// Parse the inner expression, looking for the corresponding right delimiter.
|
|
8207
|
+
const body = parser.parseExpression(false, rightDelim, false);
|
|
8208
|
+
const nextToken = parser.fetch().text;
|
|
8209
|
+
|
|
8210
|
+
if (nextToken !== rightDelim) {
|
|
8211
|
+
// We were unable to find a matching right delimiter.
|
|
8212
|
+
// Throw control back to renderToMathMLTree.
|
|
8213
|
+
// It will reparse the entire expression with wrapDelimiterPairs set to false.
|
|
8214
|
+
throw new ParseError("Unmatched delimiter");
|
|
8215
|
+
}
|
|
8216
|
+
parser.consume();
|
|
8217
|
+
|
|
8218
|
+
return {
|
|
8219
|
+
type: "delimiter",
|
|
8220
|
+
mode: parser.mode,
|
|
8221
|
+
body,
|
|
8222
|
+
left: funcName,
|
|
8223
|
+
right: rightDelim
|
|
8224
|
+
};
|
|
8225
|
+
},
|
|
8226
|
+
mathmlBuilder: (group, style) => {
|
|
8227
|
+
assertParsed(group);
|
|
8228
|
+
const inner = buildExpression(group.body, style);
|
|
8229
|
+
|
|
8230
|
+
const leftNode = makeFenceMo(group.left, group.mode, "prefix", false);
|
|
8231
|
+
inner.unshift(leftNode);
|
|
8232
|
+
|
|
8233
|
+
const rightNode = makeFenceMo(group.right, group.mode, "postfix", false);
|
|
8145
8234
|
if (group.body.length > 0) {
|
|
8146
8235
|
const lastElement = group.body[group.body.length - 1];
|
|
8147
8236
|
if (lastElement.type === "color" && !lastElement.isTextColor) {
|
|
8148
|
-
// \color is a switch. If the last element is of type "color" then
|
|
8149
|
-
// the user set the \color switch and left it on.
|
|
8150
|
-
// A \right delimiter turns the switch off, but the delimiter itself gets the color.
|
|
8151
8237
|
rightNode.setAttribute("mathcolor", lastElement.color);
|
|
8152
8238
|
}
|
|
8153
8239
|
}
|
|
@@ -8176,7 +8262,7 @@ defineFunction({
|
|
|
8176
8262
|
delim: delim.text
|
|
8177
8263
|
};
|
|
8178
8264
|
},
|
|
8179
|
-
mathmlBuilder: (group
|
|
8265
|
+
mathmlBuilder: (group) => {
|
|
8180
8266
|
const textNode = makeText(group.delim, group.mode);
|
|
8181
8267
|
const middleNode = new MathNode("mo", [textNode]);
|
|
8182
8268
|
middleNode.setAttribute("fence", "true");
|
|
@@ -8222,7 +8308,7 @@ const mathmlBuilder$7 = (group, style) => {
|
|
|
8222
8308
|
break
|
|
8223
8309
|
case "\\xcancel":
|
|
8224
8310
|
node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
|
|
8225
|
-
node.
|
|
8311
|
+
node.children.push(new MathNode("mrow", [], ["tml-cancel", "tml-xcancel"]));
|
|
8226
8312
|
break
|
|
8227
8313
|
// cancelto is handled in cancelto.js
|
|
8228
8314
|
case "\\longdiv":
|
|
@@ -8659,22 +8745,37 @@ defineFunction({
|
|
|
8659
8745
|
const stylArray = ["display", "text", "script", "scriptscript"];
|
|
8660
8746
|
const scriptLevel = { auto: -1, display: 0, text: 0, script: 1, scriptscript: 2 };
|
|
8661
8747
|
|
|
8748
|
+
const adjustStyle = (functionSize, originalStyle) => {
|
|
8749
|
+
// Figure out what style this fraction should be in based on the
|
|
8750
|
+
// function used
|
|
8751
|
+
let style = originalStyle;
|
|
8752
|
+
if (functionSize === "display") { //\tfrac or \cfrac
|
|
8753
|
+
// Get display style as a default.
|
|
8754
|
+
// If incoming style is sub/sup, use style.text() to get correct size.
|
|
8755
|
+
const newSize = style.level >= StyleLevel.SCRIPT ? StyleLevel.TEXT : StyleLevel.DISPLAY;
|
|
8756
|
+
style = style.withLevel(newSize);
|
|
8757
|
+
} else if (functionSize === "text" &&
|
|
8758
|
+
style.level === StyleLevel.DISPLAY) {
|
|
8759
|
+
// We're in a \tfrac but incoming style is displaystyle, so:
|
|
8760
|
+
style = style.withLevel(StyleLevel.TEXT);
|
|
8761
|
+
} else if (functionSize === "auto") {
|
|
8762
|
+
style = style.incrementLevel();
|
|
8763
|
+
} else if (functionSize === "script") {
|
|
8764
|
+
style = style.withLevel(StyleLevel.SCRIPT);
|
|
8765
|
+
} else if (functionSize === "scriptscript") {
|
|
8766
|
+
style = style.withLevel(StyleLevel.SCRIPTSCRIPT);
|
|
8767
|
+
}
|
|
8768
|
+
return style;
|
|
8769
|
+
};
|
|
8770
|
+
|
|
8662
8771
|
const mathmlBuilder$5 = (group, style) => {
|
|
8663
|
-
|
|
8664
|
-
// We may need that info for \mathchoice or for adjusting em dimensions.
|
|
8665
|
-
const childOptions = group.scriptLevel === "auto"
|
|
8666
|
-
? style.incrementLevel()
|
|
8667
|
-
: group.scriptLevel === "display"
|
|
8668
|
-
? style.withLevel(StyleLevel.TEXT)
|
|
8669
|
-
: group.scriptLevel === "text"
|
|
8670
|
-
? style.withLevel(StyleLevel.SCRIPT)
|
|
8671
|
-
: style.withLevel(StyleLevel.SCRIPTSCRIPT);
|
|
8772
|
+
style = adjustStyle(group.scriptLevel, style);
|
|
8672
8773
|
|
|
8673
8774
|
// Chromium (wrongly) continues to shrink fractions beyond scriptscriptlevel.
|
|
8674
8775
|
// So we check for levels that Chromium shrinks too small.
|
|
8675
8776
|
// If necessary, set an explicit fraction depth.
|
|
8676
|
-
const numer = buildGroup$1(group.numer,
|
|
8677
|
-
const denom = buildGroup$1(group.denom,
|
|
8777
|
+
const numer = buildGroup$1(group.numer, style);
|
|
8778
|
+
const denom = buildGroup$1(group.denom, style);
|
|
8678
8779
|
if (style.level === 3) {
|
|
8679
8780
|
numer.style.mathDepth = "2";
|
|
8680
8781
|
numer.setAttribute("scriptlevel", "2");
|
|
@@ -8727,6 +8828,7 @@ const mathmlBuilder$5 = (group, style) => {
|
|
|
8727
8828
|
defineFunction({
|
|
8728
8829
|
type: "genfrac",
|
|
8729
8830
|
names: [
|
|
8831
|
+
"\\cfrac",
|
|
8730
8832
|
"\\dfrac",
|
|
8731
8833
|
"\\frac",
|
|
8732
8834
|
"\\tfrac",
|
|
@@ -8750,6 +8852,7 @@ defineFunction({
|
|
|
8750
8852
|
let scriptLevel = "auto";
|
|
8751
8853
|
|
|
8752
8854
|
switch (funcName) {
|
|
8855
|
+
case "\\cfrac":
|
|
8753
8856
|
case "\\dfrac":
|
|
8754
8857
|
case "\\frac":
|
|
8755
8858
|
case "\\tfrac":
|
|
@@ -8776,15 +8879,10 @@ defineFunction({
|
|
|
8776
8879
|
throw new Error("Unrecognized genfrac command");
|
|
8777
8880
|
}
|
|
8778
8881
|
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
|
|
8782
|
-
|
|
8783
|
-
break;
|
|
8784
|
-
case "\\tfrac":
|
|
8785
|
-
case "\\tbinom":
|
|
8786
|
-
scriptLevel = "text";
|
|
8787
|
-
break;
|
|
8882
|
+
if (funcName === "\\cfrac" || funcName.startsWith("\\d")) {
|
|
8883
|
+
scriptLevel = "display";
|
|
8884
|
+
} else if (funcName.startsWith("\\t")) {
|
|
8885
|
+
scriptLevel = "text";
|
|
8788
8886
|
}
|
|
8789
8887
|
|
|
8790
8888
|
return {
|
|
@@ -8803,31 +8901,6 @@ defineFunction({
|
|
|
8803
8901
|
mathmlBuilder: mathmlBuilder$5
|
|
8804
8902
|
});
|
|
8805
8903
|
|
|
8806
|
-
defineFunction({
|
|
8807
|
-
type: "genfrac",
|
|
8808
|
-
names: ["\\cfrac"],
|
|
8809
|
-
props: {
|
|
8810
|
-
numArgs: 2
|
|
8811
|
-
},
|
|
8812
|
-
handler: ({ parser, funcName }, args) => {
|
|
8813
|
-
const numer = args[0];
|
|
8814
|
-
const denom = args[1];
|
|
8815
|
-
|
|
8816
|
-
return {
|
|
8817
|
-
type: "genfrac",
|
|
8818
|
-
mode: parser.mode,
|
|
8819
|
-
continued: true,
|
|
8820
|
-
numer,
|
|
8821
|
-
denom,
|
|
8822
|
-
hasBarLine: true,
|
|
8823
|
-
leftDelim: null,
|
|
8824
|
-
rightDelim: null,
|
|
8825
|
-
scriptLevel: "display",
|
|
8826
|
-
barSize: null
|
|
8827
|
-
};
|
|
8828
|
-
}
|
|
8829
|
-
});
|
|
8830
|
-
|
|
8831
8904
|
// Infix generalized fractions -- these are not rendered directly, but replaced
|
|
8832
8905
|
// immediately by one of the variants above.
|
|
8833
8906
|
defineFunction({
|
|
@@ -9656,8 +9729,16 @@ const binrelClass = (arg) => {
|
|
|
9656
9729
|
const atom = arg.type === "ordgroup" && arg.body.length && arg.body.length === 1
|
|
9657
9730
|
? arg.body[0]
|
|
9658
9731
|
: arg;
|
|
9659
|
-
if (atom.type === "atom"
|
|
9660
|
-
|
|
9732
|
+
if (atom.type === "atom") {
|
|
9733
|
+
// BIN args are sometimes changed to OPEN, so check the original family.
|
|
9734
|
+
const family = arg.body.length > 0 && arg.body[0].text && symbols.math[arg.body[0].text]
|
|
9735
|
+
? symbols.math[arg.body[0].text].group
|
|
9736
|
+
: atom.family;
|
|
9737
|
+
if (family === "bin" || family === "rel") {
|
|
9738
|
+
return "m" + family;
|
|
9739
|
+
} else {
|
|
9740
|
+
return "mord";
|
|
9741
|
+
}
|
|
9661
9742
|
} else {
|
|
9662
9743
|
return "mord";
|
|
9663
9744
|
}
|
|
@@ -10228,6 +10309,14 @@ const mathmlBuilder$1 = (group, style) => {
|
|
|
10228
10309
|
if ((node.type === "mrow" || node.type === "mpadded") && node.children.length === 1 &&
|
|
10229
10310
|
node.children[0] instanceof MathNode) {
|
|
10230
10311
|
node = node.children[0];
|
|
10312
|
+
} else if (node.type === "mrow" && node.children.length === 2 &&
|
|
10313
|
+
node.children[0] instanceof MathNode &&
|
|
10314
|
+
node.children[1] instanceof MathNode &&
|
|
10315
|
+
node.children[1].type === "mspace" && !node.children[1].attributes.width &&
|
|
10316
|
+
node.children[1].children.length === 0) {
|
|
10317
|
+
// This is a workaround for a Firefox bug that applies spacing to
|
|
10318
|
+
// an <mi> with mathvariant="normal".
|
|
10319
|
+
node = node.children[0];
|
|
10231
10320
|
}
|
|
10232
10321
|
switch (node.type) {
|
|
10233
10322
|
case "mi":
|
|
@@ -11498,8 +11587,8 @@ defineFunctionBuilders({
|
|
|
11498
11587
|
node.setAttribute("mathvariant", "normal");
|
|
11499
11588
|
if (text.text.length === 1) {
|
|
11500
11589
|
// A Firefox bug will apply spacing here, but there should be none. Fix it.
|
|
11501
|
-
|
|
11502
|
-
node
|
|
11590
|
+
const mspace = new MathNode("mspace", []);
|
|
11591
|
+
node = new MathNode("mrow", [node, mspace]);
|
|
11503
11592
|
}
|
|
11504
11593
|
}
|
|
11505
11594
|
return node
|
|
@@ -13036,7 +13125,7 @@ class Parser {
|
|
|
13036
13125
|
* Parses an "expression", which is a list of atoms.
|
|
13037
13126
|
*
|
|
13038
13127
|
* `breakOnInfix`: Should the parsing stop when we hit infix nodes? This
|
|
13039
|
-
* happens when functions have higher precedence
|
|
13128
|
+
* happens when functions have higher precedence than infix
|
|
13040
13129
|
* nodes in implicit parses.
|
|
13041
13130
|
*
|
|
13042
13131
|
* `breakOnTokenText`: The text of the token that the expression should end
|
|
@@ -13644,7 +13733,7 @@ class Parser {
|
|
|
13644
13733
|
) {
|
|
13645
13734
|
const firstToken = this.fetch();
|
|
13646
13735
|
const text = firstToken.text;
|
|
13647
|
-
|
|
13736
|
+
if (name === "argument to '\\left'") { return this.parseSymbol() }
|
|
13648
13737
|
let result;
|
|
13649
13738
|
// Try to parse an open brace or \begingroup
|
|
13650
13739
|
if (text === "{" || text === "\\begingroup" || text === "\\toggle") {
|
|
@@ -13791,7 +13880,8 @@ class Parser {
|
|
|
13791
13880
|
let symbol;
|
|
13792
13881
|
if (symbols[this.mode][text]) {
|
|
13793
13882
|
let group = symbols[this.mode][text].group;
|
|
13794
|
-
if (group === "bin" &&
|
|
13883
|
+
if (group === "bin" &&
|
|
13884
|
+
(binLeftCancellers.includes(this.prevAtomType) || this.prevAtomType === "")) {
|
|
13795
13885
|
// Change from a binary operator to a unary (prefix) operator
|
|
13796
13886
|
group = "open";
|
|
13797
13887
|
}
|
|
@@ -13887,11 +13977,27 @@ const parseTree = function(toParse, settings) {
|
|
|
13887
13977
|
if (!(typeof toParse === "string" || toParse instanceof String)) {
|
|
13888
13978
|
throw new TypeError("Temml can only parse string typed expression")
|
|
13889
13979
|
}
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
13980
|
+
let tree;
|
|
13981
|
+
let parser;
|
|
13982
|
+
try {
|
|
13983
|
+
parser = new Parser(toParse, settings);
|
|
13984
|
+
// Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
|
|
13985
|
+
delete parser.gullet.macros.current["\\df@tag"];
|
|
13893
13986
|
|
|
13894
|
-
|
|
13987
|
+
tree = parser.parse();
|
|
13988
|
+
} catch (error) {
|
|
13989
|
+
if (error.toString() === "ParseError: Unmatched delimiter") {
|
|
13990
|
+
// Abandon the attempt to wrap delimiter pairs in an <mrow>.
|
|
13991
|
+
// Try again, and put each delimiter into an <mo> element.
|
|
13992
|
+
settings.wrapDelimiterPairs = false;
|
|
13993
|
+
parser = new Parser(toParse, settings);
|
|
13994
|
+
// Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
|
|
13995
|
+
delete parser.gullet.macros.current["\\df@tag"];
|
|
13996
|
+
tree = parser.parse();
|
|
13997
|
+
} else {
|
|
13998
|
+
throw error;
|
|
13999
|
+
}
|
|
14000
|
+
}
|
|
13895
14001
|
|
|
13896
14002
|
// LaTeX ignores a \tag placed outside an AMS environment.
|
|
13897
14003
|
if (!(tree.length > 0 && tree[0].type && tree[0].type === "array" && tree[0].addEqnNum)) {
|
|
@@ -14068,7 +14174,7 @@ class Style {
|
|
|
14068
14174
|
* https://mit-license.org/
|
|
14069
14175
|
*/
|
|
14070
14176
|
|
|
14071
|
-
const version = "0.13.
|
|
14177
|
+
const version = "0.13.02";
|
|
14072
14178
|
|
|
14073
14179
|
function postProcess(block) {
|
|
14074
14180
|
const labelMap = {};
|