temml 0.13.1 → 0.13.3
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 +16 -13
- package/dist/Temml-Latin-Modern.css +16 -13
- package/dist/Temml-Libertinus.css +16 -13
- package/dist/Temml-Local.css +16 -13
- package/dist/Temml-NotoSans.css +16 -13
- package/dist/Temml-STIX2.css +16 -13
- package/dist/temml.cjs +629 -500
- package/dist/temml.js +502 -373
- package/dist/temml.min.js +1 -1
- package/dist/temml.mjs +629 -500
- package/dist/temmlPostProcess.js +1 -1
- package/package.json +6 -4
- package/src/MacroExpander.js +2 -1
- package/src/Parser.js +5 -4
- package/src/Settings.js +1 -0
- package/src/environments/array.js +2 -2
- package/src/functions/bordermatrix.js +3 -5
- package/src/functions/cancelto.js +2 -0
- package/src/functions/color.js +1 -1
- package/src/functions/{delimsizing.js → delimiter.js} +139 -52
- package/src/functions/enclose.js +21 -2
- package/src/functions/font.js +14 -4
- 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/phantom.js +1 -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.mjs
CHANGED
|
@@ -213,6 +213,7 @@ class Settings {
|
|
|
213
213
|
: [Infinity, Infinity]
|
|
214
214
|
);
|
|
215
215
|
this.maxExpand = Math.max(0, deflt(options.maxExpand, 1000)); // number
|
|
216
|
+
this.wrapDelimiterPairs = true; // boolean
|
|
216
217
|
}
|
|
217
218
|
|
|
218
219
|
/**
|
|
@@ -994,8 +995,7 @@ defineSymbol(math, textord, "\u2135", "\\aleph", true);
|
|
|
994
995
|
defineSymbol(math, textord, "\u2200", "\\forall", true);
|
|
995
996
|
defineSymbol(math, textord, "\u210f", "\\hbar", true);
|
|
996
997
|
defineSymbol(math, textord, "\u2203", "\\exists", true);
|
|
997
|
-
|
|
998
|
-
defineSymbol(math, bin, "\u2207", "\\nabla", true);
|
|
998
|
+
defineSymbol(math, open, "\u2207", "\\nabla", true);
|
|
999
999
|
defineSymbol(math, textord, "\u266d", "\\flat", true);
|
|
1000
1000
|
defineSymbol(math, textord, "\u2113", "\\ell", true);
|
|
1001
1001
|
defineSymbol(math, textord, "\u266e", "\\natural", true);
|
|
@@ -1088,7 +1088,7 @@ defineSymbol(math, mathord, "\u2295", "\\Earth");
|
|
|
1088
1088
|
|
|
1089
1089
|
// AMS Negated Binary Relations
|
|
1090
1090
|
defineSymbol(math, rel, "\u226e", "\\nless", true);
|
|
1091
|
-
// Symbol names
|
|
1091
|
+
// Symbol names preceded by "@" each have a corresponding macro.
|
|
1092
1092
|
defineSymbol(math, rel, "\u2a87", "\\lneq", true);
|
|
1093
1093
|
defineSymbol(math, rel, "\u2268", "\\lneqq", true);
|
|
1094
1094
|
defineSymbol(math, rel, "\u2268\ufe00", "\\lvertneqq");
|
|
@@ -1999,16 +1999,12 @@ for (let i = 0; i < 10; i++) {
|
|
|
1999
1999
|
* much of this module.
|
|
2000
2000
|
*/
|
|
2001
2001
|
|
|
2002
|
-
const openDelims = "([{⌊⌈⟨⟮⎰⟦⦃";
|
|
2003
|
-
const closeDelims = ")]}⌋⌉⟩⟯⎱⟦⦄";
|
|
2004
|
-
|
|
2005
2002
|
function setLineBreaks(expression, wrapMode, isDisplayMode) {
|
|
2006
2003
|
const mtrs = [];
|
|
2007
2004
|
let mrows = [];
|
|
2008
2005
|
let block = [];
|
|
2009
2006
|
let numTopLevelEquals = 0;
|
|
2010
2007
|
let i = 0;
|
|
2011
|
-
let level = 0;
|
|
2012
2008
|
while (i < expression.length) {
|
|
2013
2009
|
while (expression[i] instanceof DocumentFragment) {
|
|
2014
2010
|
expression.splice(i, 1, ...expression[i].children); // Expand the fragment.
|
|
@@ -2031,13 +2027,10 @@ function setLineBreaks(expression, wrapMode, isDisplayMode) {
|
|
|
2031
2027
|
}
|
|
2032
2028
|
block.push(node);
|
|
2033
2029
|
if (node.type && node.type === "mo" && node.children.length === 1 &&
|
|
2030
|
+
!(node.attributes.form && node.attributes.form === "prefix") && // unary operators
|
|
2034
2031
|
!Object.prototype.hasOwnProperty.call(node.attributes, "movablelimits")) {
|
|
2035
2032
|
const ch = node.children[0].text;
|
|
2036
|
-
if (
|
|
2037
|
-
level += 1;
|
|
2038
|
-
} else if (closeDelims.indexOf(ch) > -1) {
|
|
2039
|
-
level -= 1;
|
|
2040
|
-
} else if (level === 0 && wrapMode === "=" && ch === "=") {
|
|
2033
|
+
if (wrapMode === "=" && ch === "=") {
|
|
2041
2034
|
numTopLevelEquals += 1;
|
|
2042
2035
|
if (numTopLevelEquals > 1) {
|
|
2043
2036
|
block.pop();
|
|
@@ -2046,7 +2039,7 @@ function setLineBreaks(expression, wrapMode, isDisplayMode) {
|
|
|
2046
2039
|
mrows.push(element);
|
|
2047
2040
|
block = [node];
|
|
2048
2041
|
}
|
|
2049
|
-
} else if (
|
|
2042
|
+
} else if (wrapMode === "tex") {
|
|
2050
2043
|
// Check if the following node is a \nobreak text node, e.g. "~""
|
|
2051
2044
|
const next = i < expression.length - 1 ? expression[i + 1] : null;
|
|
2052
2045
|
let glueIsFreeOfNobreak = true;
|
|
@@ -3068,7 +3061,7 @@ function assertSymbolNodeType(node) {
|
|
|
3068
3061
|
* returns null.
|
|
3069
3062
|
*/
|
|
3070
3063
|
function checkSymbolNodeType(node) {
|
|
3071
|
-
if (node && (node.type === "atom" ||
|
|
3064
|
+
if (node && (node.type === "atom" || node.type === "delimiter" ||
|
|
3072
3065
|
Object.prototype.hasOwnProperty.call(NON_ATOMS, node.type))) {
|
|
3073
3066
|
return node;
|
|
3074
3067
|
}
|
|
@@ -4250,6 +4243,7 @@ defineMacro("\\upomega", "\\up@greek{\\omega}");
|
|
|
4250
4243
|
// cmll package
|
|
4251
4244
|
defineMacro("\\invamp", '\\mathbin{\\char"214b}');
|
|
4252
4245
|
defineMacro("\\parr", '\\mathbin{\\char"214b}');
|
|
4246
|
+
defineMacro("\\upand", '\\mathbin{\\char"214b}'); // STIX package
|
|
4253
4247
|
defineMacro("\\with", '\\mathbin{\\char"26}');
|
|
4254
4248
|
defineMacro("\\multimapinv", '\\mathrel{\\char"27dc}');
|
|
4255
4249
|
defineMacro("\\multimapboth", '\\mathrel{\\char"29df}');
|
|
@@ -6524,9 +6518,9 @@ const mathmlBuilder$9 = function(group, style) {
|
|
|
6524
6518
|
}
|
|
6525
6519
|
if (mustSquashRow) {
|
|
6526
6520
|
// All the cell contents are \hphantom. Squash the cell.
|
|
6521
|
+
// TODO: Remove the next line when Firefox no longer needs it.
|
|
6522
|
+
mtr.classes.push("ff-squash"); // necessary in Firefox only.
|
|
6527
6523
|
for (let j = 0; j < mtr.children.length; j++) {
|
|
6528
|
-
mtr.children[j].style.display = "block"; // necessary in Firefox only
|
|
6529
|
-
mtr.children[j].style.height = "0"; // necessary in Firefox only
|
|
6530
6524
|
mtr.children[j].style.paddingTop = "0";
|
|
6531
6525
|
mtr.children[j].style.paddingBottom = "0";
|
|
6532
6526
|
}
|
|
@@ -7167,13 +7161,11 @@ defineFunction({
|
|
|
7167
7161
|
},
|
|
7168
7162
|
handler: ({ parser, funcName }, args, optArgs) => {
|
|
7169
7163
|
// Find out if the author has defined custom delimiters
|
|
7170
|
-
let delimiters = ["(", ")"];
|
|
7164
|
+
let delimiters = ["(", ")"]; // default
|
|
7171
7165
|
if (funcName === "\\bordermatrix" && optArgs[0] && optArgs[0].body) {
|
|
7172
7166
|
const body = optArgs[0].body;
|
|
7173
|
-
if (body.length ===
|
|
7174
|
-
|
|
7175
|
-
delimiters = [body[0].text, body[1].text];
|
|
7176
|
-
}
|
|
7167
|
+
if (body.length === 1 && body[0].type === "delimiter") {
|
|
7168
|
+
delimiters = [body[0].left, body[0].right];
|
|
7177
7169
|
}
|
|
7178
7170
|
}
|
|
7179
7171
|
// consume the opening brace
|
|
@@ -7221,6 +7213,7 @@ defineFunction({
|
|
|
7221
7213
|
// That way, the arrow will be an overlay on the content.
|
|
7222
7214
|
const phantom = new MathNode("mphantom", [buildGroup$1(group.body, style)]);
|
|
7223
7215
|
const arrow = new MathNode("mrow", [phantom], ["tml-cancelto"]);
|
|
7216
|
+
arrow.style.color = style.color;
|
|
7224
7217
|
if (group.isCharacterBox && smalls.indexOf(group.body.body[0].text) > -1) {
|
|
7225
7218
|
arrow.style.left = "0.1em";
|
|
7226
7219
|
arrow.style.width = "90%";
|
|
@@ -7252,6 +7245,7 @@ defineFunction({
|
|
|
7252
7245
|
dummyNode = new MathNode("mphantom", [zeroWidthNode]); // Hide it.
|
|
7253
7246
|
}
|
|
7254
7247
|
const toNode = buildGroup$1(group.to, style);
|
|
7248
|
+
toNode.style.color = style.color;
|
|
7255
7249
|
const zeroWidthToNode = new MathNode("mpadded", [toNode]);
|
|
7256
7250
|
if (!group.isCharacterBox || /[f∫∑]/.test(group.body.body[0].text)) {
|
|
7257
7251
|
const w = new MathNode("mspace", []);
|
|
@@ -7310,7 +7304,7 @@ const toHex = num => {
|
|
|
7310
7304
|
|
|
7311
7305
|
// Colors from Tables 4.1 and 4.2 of the xcolor package.
|
|
7312
7306
|
// Table 4.1 (lower case) RGB values are taken from chroma and xcolor.dtx.
|
|
7313
|
-
// Table 4.2 (
|
|
7307
|
+
// Table 4.2 (Capitalized) values were sampled, because Chroma contains a unreliable
|
|
7314
7308
|
// conversion from cmyk to RGB. See https://tex.stackexchange.com/a/537274.
|
|
7315
7309
|
const xcolors = JSON.parse(`{
|
|
7316
7310
|
"Apricot": "#ffb484",
|
|
@@ -7869,7 +7863,41 @@ const delimiterSizes = {
|
|
|
7869
7863
|
"\\Bigg": { mclass: "mord", size: 4 }
|
|
7870
7864
|
};
|
|
7871
7865
|
|
|
7872
|
-
const
|
|
7866
|
+
const leftToRight = {
|
|
7867
|
+
"(": ")",
|
|
7868
|
+
"\\lparen": "\\rparen",
|
|
7869
|
+
"[": "]",
|
|
7870
|
+
"\\lbrack": "\\rbrack",
|
|
7871
|
+
"\\{": "\\}",
|
|
7872
|
+
"\\lbrace": "\\rbrace",
|
|
7873
|
+
"⦇": "⦈",
|
|
7874
|
+
"\\llparenthesis": "\\rrparenthesis",
|
|
7875
|
+
"\\lfloor": "\\rfloor",
|
|
7876
|
+
"\u230a": "\u230b",
|
|
7877
|
+
"\\lceil": "\\rceil",
|
|
7878
|
+
"\u2308": "\u2309",
|
|
7879
|
+
"\\langle": "\\rangle",
|
|
7880
|
+
"\u27e8": "\u27e9",
|
|
7881
|
+
"\\lAngle": "\\rAngle",
|
|
7882
|
+
"\u27ea": "\u27eb",
|
|
7883
|
+
"\\llangle": "\\rrangle",
|
|
7884
|
+
"⦉": "⦊",
|
|
7885
|
+
"\\lvert": "\\rvert",
|
|
7886
|
+
"\\lVert": "\\rVert",
|
|
7887
|
+
"\\lgroup": "\\rgroup",
|
|
7888
|
+
"\u27ee": "\u27ef",
|
|
7889
|
+
"\\lmoustache": "\\rmoustache",
|
|
7890
|
+
"\u23b0": "\u23b1",
|
|
7891
|
+
"\\llbracket": "\\rrbracket",
|
|
7892
|
+
"\u27e6": "\u27e7",
|
|
7893
|
+
"\\lBrace": "\\rBrace",
|
|
7894
|
+
"\u2983": "\u2984"
|
|
7895
|
+
};
|
|
7896
|
+
|
|
7897
|
+
const leftDelimiterNames = new Set(Object.keys(leftToRight));
|
|
7898
|
+
new Set(Object.values(leftToRight));
|
|
7899
|
+
|
|
7900
|
+
const delimiters = new Set([
|
|
7873
7901
|
"(",
|
|
7874
7902
|
"\\lparen",
|
|
7875
7903
|
")",
|
|
@@ -7925,7 +7953,7 @@ const delimiters = [
|
|
|
7925
7953
|
"\\llbracket",
|
|
7926
7954
|
"\\rrbracket",
|
|
7927
7955
|
"\u27e6",
|
|
7928
|
-
"\
|
|
7956
|
+
"\u27e7",
|
|
7929
7957
|
"\\lBrace",
|
|
7930
7958
|
"\\rBrace",
|
|
7931
7959
|
"\u2983",
|
|
@@ -7944,12 +7972,12 @@ const delimiters = [
|
|
|
7944
7972
|
"\\updownarrow",
|
|
7945
7973
|
"\\Updownarrow",
|
|
7946
7974
|
"."
|
|
7947
|
-
];
|
|
7975
|
+
]);
|
|
7948
7976
|
|
|
7949
7977
|
// Export isDelimiter for benefit of parser.
|
|
7950
|
-
const dels = ["}", "\\left", "\\middle", "\\right"];
|
|
7978
|
+
const dels = new Set(["}", "\\left", "\\middle", "\\right"]);
|
|
7951
7979
|
const isDelimiter = str => str.length > 0 &&
|
|
7952
|
-
(delimiters.
|
|
7980
|
+
(delimiters.has(str) || delimiterSizes[str] || dels.has(str));
|
|
7953
7981
|
|
|
7954
7982
|
// Metrics of the different sizes. Found by looking at TeX's output of
|
|
7955
7983
|
// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
|
|
@@ -7962,11 +7990,11 @@ function checkDelimiter(delim, context) {
|
|
|
7962
7990
|
delim = delim.body[0]; // Unwrap the braces
|
|
7963
7991
|
}
|
|
7964
7992
|
const symDelim = checkSymbolNodeType(delim);
|
|
7965
|
-
if (symDelim && delimiters.
|
|
7993
|
+
if (symDelim && delimiters.has(symDelim.text)) {
|
|
7966
7994
|
// If a character is not in the MathML operator dictionary, it will not stretch.
|
|
7967
7995
|
// Replace such characters w/characters that will stretch.
|
|
7968
|
-
if (
|
|
7969
|
-
if (
|
|
7996
|
+
if (symDelim.text === "<" || symDelim.text === "\\lt") { symDelim.text = "⟨"; }
|
|
7997
|
+
if (symDelim.text === ">" || symDelim.text === "\\gt") { symDelim.text = "⟩"; }
|
|
7970
7998
|
return symDelim;
|
|
7971
7999
|
} else if (symDelim) {
|
|
7972
8000
|
throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim);
|
|
@@ -7976,7 +8004,16 @@ function checkDelimiter(delim, context) {
|
|
|
7976
8004
|
}
|
|
7977
8005
|
|
|
7978
8006
|
// / \
|
|
7979
|
-
const needExplicitStretch = ["\u002F", "\u005C", "\\backslash", "\\vert", "|"];
|
|
8007
|
+
const needExplicitStretch = new Set(["\u002F", "\u005C", "\\backslash", "\u2216", "\\vert", "|"]);
|
|
8008
|
+
|
|
8009
|
+
const makeFenceMo = (delim, mode, form, isStretchy) => {
|
|
8010
|
+
const text = delim === "." ? "" : delim;
|
|
8011
|
+
const node = new MathNode("mo", [makeText(text, mode)]);
|
|
8012
|
+
node.setAttribute("fence", "true");
|
|
8013
|
+
node.setAttribute("form", form);
|
|
8014
|
+
node.setAttribute("stretchy", isStretchy ? "true" : "false");
|
|
8015
|
+
return node;
|
|
8016
|
+
};
|
|
7980
8017
|
|
|
7981
8018
|
defineFunction({
|
|
7982
8019
|
type: "delimsizing",
|
|
@@ -8027,9 +8064,9 @@ defineFunction({
|
|
|
8027
8064
|
},
|
|
8028
8065
|
mathmlBuilder: (group) => {
|
|
8029
8066
|
const children = [];
|
|
8067
|
+
const delim = group.delim === "." ? "" : group.delim;
|
|
8030
8068
|
|
|
8031
|
-
|
|
8032
|
-
children.push(makeText(group.delim, group.mode));
|
|
8069
|
+
children.push(makeText(delim, group.mode));
|
|
8033
8070
|
|
|
8034
8071
|
const node = new MathNode("mo", children);
|
|
8035
8072
|
|
|
@@ -8042,7 +8079,7 @@ defineFunction({
|
|
|
8042
8079
|
// defaults.
|
|
8043
8080
|
node.setAttribute("fence", "false");
|
|
8044
8081
|
}
|
|
8045
|
-
if (needExplicitStretch.
|
|
8082
|
+
if (needExplicitStretch.has(delim) || delim.indexOf("arrow") > -1) {
|
|
8046
8083
|
// We have to explicitly set stretchy to true.
|
|
8047
8084
|
node.setAttribute("stretchy", "true");
|
|
8048
8085
|
}
|
|
@@ -8055,7 +8092,7 @@ defineFunction({
|
|
|
8055
8092
|
|
|
8056
8093
|
function assertParsed(group) {
|
|
8057
8094
|
if (!group.body) {
|
|
8058
|
-
throw new Error("Bug: The
|
|
8095
|
+
throw new Error("Bug: The delim ParseNode wasn't fully parsed.");
|
|
8059
8096
|
}
|
|
8060
8097
|
}
|
|
8061
8098
|
|
|
@@ -8086,17 +8123,10 @@ defineFunction({
|
|
|
8086
8123
|
const delim = checkDelimiter(args[0], context);
|
|
8087
8124
|
|
|
8088
8125
|
const parser = context.parser;
|
|
8089
|
-
// Parse out the implicit body
|
|
8090
8126
|
++parser.leftrightDepth;
|
|
8091
|
-
|
|
8092
|
-
let body = parser.parseExpression(false, null, true);
|
|
8127
|
+
let body = parser.parseExpression(false, "\\right", true);
|
|
8093
8128
|
let nextToken = parser.fetch();
|
|
8094
8129
|
while (nextToken.text === "\\middle") {
|
|
8095
|
-
// `\middle`, from the ε-TeX package, ends one group and starts another group.
|
|
8096
|
-
// We had to parse this expression with `breakOnMiddle` enabled in order
|
|
8097
|
-
// to get TeX-compliant parsing of \over.
|
|
8098
|
-
// But we do not want, at this point, to end on \middle, so continue
|
|
8099
|
-
// to parse until we fetch a `\right`.
|
|
8100
8130
|
parser.consume();
|
|
8101
8131
|
const middle = parser.fetch().text;
|
|
8102
8132
|
if (!symbols.math[middle]) {
|
|
@@ -8105,11 +8135,10 @@ defineFunction({
|
|
|
8105
8135
|
checkDelimiter({ type: "atom", mode: "math", text: middle }, { funcName: "\\middle" });
|
|
8106
8136
|
body.push({ type: "middle", mode: "math", delim: middle });
|
|
8107
8137
|
parser.consume();
|
|
8108
|
-
body = body.concat(parser.parseExpression(false,
|
|
8138
|
+
body = body.concat(parser.parseExpression(false, "\\right", true));
|
|
8109
8139
|
nextToken = parser.fetch();
|
|
8110
8140
|
}
|
|
8111
8141
|
--parser.leftrightDepth;
|
|
8112
|
-
// Check the next token
|
|
8113
8142
|
parser.expect("\\right", false);
|
|
8114
8143
|
const right = assertNodeType(parser.parseFunction(), "leftright-right");
|
|
8115
8144
|
return {
|
|
@@ -8117,35 +8146,90 @@ defineFunction({
|
|
|
8117
8146
|
mode: parser.mode,
|
|
8118
8147
|
body,
|
|
8119
8148
|
left: delim.text,
|
|
8120
|
-
right: right.delim
|
|
8149
|
+
right: right.delim,
|
|
8150
|
+
isStretchy: true
|
|
8121
8151
|
};
|
|
8122
8152
|
},
|
|
8123
8153
|
mathmlBuilder: (group, style) => {
|
|
8124
8154
|
assertParsed(group);
|
|
8125
8155
|
const inner = buildExpression(group.body, style);
|
|
8126
8156
|
|
|
8127
|
-
|
|
8128
|
-
const leftNode = new MathNode("mo", [makeText(group.left, group.mode)]);
|
|
8129
|
-
leftNode.setAttribute("fence", "true");
|
|
8130
|
-
leftNode.setAttribute("form", "prefix");
|
|
8131
|
-
if (group.left === "/" || group.left === "\u005C" || group.left.indexOf("arrow") > -1) {
|
|
8132
|
-
leftNode.setAttribute("stretchy", "true");
|
|
8133
|
-
}
|
|
8157
|
+
const leftNode = makeFenceMo(group.left, group.mode, "prefix", true);
|
|
8134
8158
|
inner.unshift(leftNode);
|
|
8135
8159
|
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8160
|
+
const rightNode = makeFenceMo(group.right, group.mode, "postfix", true);
|
|
8161
|
+
if (group.body.length > 0) {
|
|
8162
|
+
const lastElement = group.body[group.body.length - 1];
|
|
8163
|
+
if (lastElement.type === "color" && !lastElement.isTextColor) {
|
|
8164
|
+
rightNode.setAttribute("mathcolor", lastElement.color);
|
|
8165
|
+
}
|
|
8166
|
+
}
|
|
8167
|
+
inner.push(rightNode);
|
|
8168
|
+
|
|
8169
|
+
return makeRow(inner);
|
|
8170
|
+
}
|
|
8171
|
+
});
|
|
8172
|
+
|
|
8173
|
+
defineFunction({
|
|
8174
|
+
type: "delimiter",
|
|
8175
|
+
names: Array.from(leftDelimiterNames),
|
|
8176
|
+
props: {
|
|
8177
|
+
numArgs: 0,
|
|
8178
|
+
allowedInText: true,
|
|
8179
|
+
allowedInMath: true,
|
|
8180
|
+
allowedInArgument: true
|
|
8181
|
+
},
|
|
8182
|
+
handler: ({ parser, funcName, token }) => {
|
|
8183
|
+
if (parser.mode === "text") {
|
|
8184
|
+
return {
|
|
8185
|
+
type: "textord",
|
|
8186
|
+
mode: "text",
|
|
8187
|
+
text: funcName,
|
|
8188
|
+
loc: token.loc
|
|
8189
|
+
}
|
|
8190
|
+
} else if (!parser.settings.wrapDelimiterPairs) {
|
|
8191
|
+
// Treat this token as an ordinary symbol.
|
|
8192
|
+
return {
|
|
8193
|
+
type: "atom",
|
|
8194
|
+
mode: "math",
|
|
8195
|
+
family: "open",
|
|
8196
|
+
loc: token.loc,
|
|
8197
|
+
text: funcName
|
|
8198
|
+
};
|
|
8199
|
+
}
|
|
8200
|
+
// Otherwise, try to wrap a pair of delimiters with an <mrow>.
|
|
8201
|
+
const rightDelim = leftToRight[funcName];
|
|
8202
|
+
// Parse the inner expression, looking for the corresponding right delimiter.
|
|
8203
|
+
const body = parser.parseExpression(false, rightDelim, false);
|
|
8204
|
+
const nextToken = parser.fetch().text;
|
|
8205
|
+
|
|
8206
|
+
if (nextToken !== rightDelim) {
|
|
8207
|
+
// We were unable to find a matching right delimiter.
|
|
8208
|
+
// Throw control back to renderToMathMLTree.
|
|
8209
|
+
// It will reparse the entire expression with wrapDelimiterPairs set to false.
|
|
8210
|
+
throw new ParseError("Unmatched delimiter");
|
|
8142
8211
|
}
|
|
8212
|
+
parser.consume();
|
|
8213
|
+
|
|
8214
|
+
return {
|
|
8215
|
+
type: "delimiter",
|
|
8216
|
+
mode: parser.mode,
|
|
8217
|
+
body,
|
|
8218
|
+
left: funcName,
|
|
8219
|
+
right: rightDelim
|
|
8220
|
+
};
|
|
8221
|
+
},
|
|
8222
|
+
mathmlBuilder: (group, style) => {
|
|
8223
|
+
assertParsed(group);
|
|
8224
|
+
const inner = buildExpression(group.body, style);
|
|
8225
|
+
|
|
8226
|
+
const leftNode = makeFenceMo(group.left, group.mode, "prefix", false);
|
|
8227
|
+
inner.unshift(leftNode);
|
|
8228
|
+
|
|
8229
|
+
const rightNode = makeFenceMo(group.right, group.mode, "postfix", false);
|
|
8143
8230
|
if (group.body.length > 0) {
|
|
8144
8231
|
const lastElement = group.body[group.body.length - 1];
|
|
8145
8232
|
if (lastElement.type === "color" && !lastElement.isTextColor) {
|
|
8146
|
-
// \color is a switch. If the last element is of type "color" then
|
|
8147
|
-
// the user set the \color switch and left it on.
|
|
8148
|
-
// A \right delimiter turns the switch off, but the delimiter itself gets the color.
|
|
8149
8233
|
rightNode.setAttribute("mathcolor", lastElement.color);
|
|
8150
8234
|
}
|
|
8151
8235
|
}
|
|
@@ -8174,20 +8258,17 @@ defineFunction({
|
|
|
8174
8258
|
delim: delim.text
|
|
8175
8259
|
};
|
|
8176
8260
|
},
|
|
8177
|
-
mathmlBuilder: (group
|
|
8261
|
+
mathmlBuilder: (group) => {
|
|
8178
8262
|
const textNode = makeText(group.delim, group.mode);
|
|
8179
8263
|
const middleNode = new MathNode("mo", [textNode]);
|
|
8180
|
-
middleNode.setAttribute("
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
// \middle should get delimiter spacing instead.
|
|
8189
|
-
middleNode.setAttribute("lspace", "0.05em");
|
|
8190
|
-
middleNode.setAttribute("rspace", "0.05em");
|
|
8264
|
+
middleNode.setAttribute("stretchy", "true");
|
|
8265
|
+
middleNode.setAttribute("form", "infix");
|
|
8266
|
+
if (textNode.text !== "/") {
|
|
8267
|
+
// MathML gives 5/18em spacing to each <mo> element.
|
|
8268
|
+
// \middle should get delimiter spacing instead.
|
|
8269
|
+
middleNode.setAttribute("lspace", "0.05em");
|
|
8270
|
+
middleNode.setAttribute("rspace", "0.05em");
|
|
8271
|
+
}
|
|
8191
8272
|
return middleNode;
|
|
8192
8273
|
}
|
|
8193
8274
|
});
|
|
@@ -8220,7 +8301,7 @@ const mathmlBuilder$7 = (group, style) => {
|
|
|
8220
8301
|
break
|
|
8221
8302
|
case "\\xcancel":
|
|
8222
8303
|
node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
|
|
8223
|
-
node.
|
|
8304
|
+
node.children.push(new MathNode("mrow", [], ["tml-cancel", "tml-xcancel"]));
|
|
8224
8305
|
break
|
|
8225
8306
|
// cancelto is handled in cancelto.js
|
|
8226
8307
|
case "\\longdiv":
|
|
@@ -8354,7 +8435,7 @@ defineFunction({
|
|
|
8354
8435
|
|
|
8355
8436
|
defineFunction({
|
|
8356
8437
|
type: "enclose",
|
|
8357
|
-
names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\
|
|
8438
|
+
names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\overline",
|
|
8358
8439
|
"\\boxed", "\\longdiv", "\\phase"],
|
|
8359
8440
|
props: {
|
|
8360
8441
|
numArgs: 1
|
|
@@ -8371,6 +8452,25 @@ defineFunction({
|
|
|
8371
8452
|
mathmlBuilder: mathmlBuilder$7
|
|
8372
8453
|
});
|
|
8373
8454
|
|
|
8455
|
+
defineFunction({
|
|
8456
|
+
type: "enclose",
|
|
8457
|
+
names: ["\\sout"],
|
|
8458
|
+
props: {
|
|
8459
|
+
numArgs: 1,
|
|
8460
|
+
allowedInText: true
|
|
8461
|
+
},
|
|
8462
|
+
handler({ parser, funcName }, args) {
|
|
8463
|
+
const body = args[0];
|
|
8464
|
+
return {
|
|
8465
|
+
type: "enclose",
|
|
8466
|
+
mode: parser.mode,
|
|
8467
|
+
label: funcName,
|
|
8468
|
+
body
|
|
8469
|
+
};
|
|
8470
|
+
},
|
|
8471
|
+
mathmlBuilder: mathmlBuilder$7
|
|
8472
|
+
});
|
|
8473
|
+
|
|
8374
8474
|
defineFunction({
|
|
8375
8475
|
type: "enclose",
|
|
8376
8476
|
names: ["\\underline"],
|
|
@@ -8503,145 +8603,380 @@ defineFunction({
|
|
|
8503
8603
|
}
|
|
8504
8604
|
});
|
|
8505
8605
|
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
if (group.body.body[0].type !== "mathord") { return false }
|
|
8511
|
-
for (let i = 1; i < group.body.body.length; i++) {
|
|
8512
|
-
const parseNodeType = group.body.body[i].type;
|
|
8513
|
-
if (!(parseNodeType === "mathord" ||
|
|
8514
|
-
(parseNodeType === "textord" && !isNaN(group.body.body[i].text)))) {
|
|
8515
|
-
return false
|
|
8516
|
-
}
|
|
8517
|
-
}
|
|
8518
|
-
return true
|
|
8519
|
-
};
|
|
8520
|
-
|
|
8521
|
-
const mathmlBuilder$6 = (group, style) => {
|
|
8522
|
-
const font = group.font;
|
|
8523
|
-
const newStyle = style.withFont(font);
|
|
8524
|
-
const mathGroup = buildGroup$1(group.body, newStyle);
|
|
8606
|
+
// Chromium does not support the MathML `mathvariant` attribute.
|
|
8607
|
+
// Instead, we replace ASCII characters with Unicode characters that
|
|
8608
|
+
// are defined in the font as bold, italic, double-struck, etc.
|
|
8609
|
+
// This module identifies those Unicode code points.
|
|
8525
8610
|
|
|
8526
|
-
|
|
8527
|
-
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
mi.children[0].text += mathGroup.children[i].children[0].children
|
|
8541
|
-
? mathGroup.children[i].children[0].children[0].text
|
|
8542
|
-
: mathGroup.children[i].children[0].text;
|
|
8543
|
-
}
|
|
8544
|
-
// Wrap in a <mpadded> to prevent the same Firefox bug.
|
|
8545
|
-
const mpadded = new MathNode("mpadded", [mi]);
|
|
8546
|
-
mpadded.setAttribute("lspace", "0");
|
|
8547
|
-
return mpadded
|
|
8548
|
-
}
|
|
8549
|
-
let canConsolidate = mathGroup.children[0].type === "mo";
|
|
8550
|
-
for (let i = 1; i < mathGroup.children.length; i++) {
|
|
8551
|
-
if (mathGroup.children[i].type === "mo" && font === "boldsymbol") {
|
|
8552
|
-
mathGroup.children[i].style.fontWeight = "bold";
|
|
8553
|
-
}
|
|
8554
|
-
if (mathGroup.children[i].type !== "mi") { canConsolidate = false; }
|
|
8555
|
-
const localVariant = mathGroup.children[i].attributes &&
|
|
8556
|
-
mathGroup.children[i].attributes.mathvariant || "";
|
|
8557
|
-
if (localVariant !== "normal") { canConsolidate = false; }
|
|
8558
|
-
}
|
|
8559
|
-
if (!canConsolidate) { return mathGroup }
|
|
8560
|
-
// Consolidate the <mi> elements.
|
|
8561
|
-
const mi = mathGroup.children[0];
|
|
8562
|
-
for (let i = 1; i < mathGroup.children.length; i++) {
|
|
8563
|
-
mi.children.push(mathGroup.children[i].children[0]);
|
|
8564
|
-
}
|
|
8565
|
-
if (mi.attributes.mathvariant && mi.attributes.mathvariant === "normal") {
|
|
8566
|
-
// Workaround for a Firefox bug that renders spurious space around
|
|
8567
|
-
// a <mi mathvariant="normal">
|
|
8568
|
-
// Ref: https://bugs.webkit.org/show_bug.cgi?id=129097
|
|
8569
|
-
// We insert a text node that contains a zero-width space and wrap in an mrow.
|
|
8570
|
-
// TODO: Get rid of this <mi> workaround when the Firefox bug is fixed.
|
|
8571
|
-
const bogus = new MathNode("mtext", new TextNode("\u200b"));
|
|
8572
|
-
return new MathNode("mrow", [bogus, mi])
|
|
8573
|
-
}
|
|
8574
|
-
return mi
|
|
8575
|
-
};
|
|
8611
|
+
// First, a few helpers.
|
|
8612
|
+
const script = Object.freeze({
|
|
8613
|
+
B: 0x20EA, // Offset from ASCII B to Unicode script B
|
|
8614
|
+
E: 0x20EB,
|
|
8615
|
+
F: 0x20EB,
|
|
8616
|
+
H: 0x20C3,
|
|
8617
|
+
I: 0x20C7,
|
|
8618
|
+
L: 0x20C6,
|
|
8619
|
+
M: 0x20E6,
|
|
8620
|
+
R: 0x20C9,
|
|
8621
|
+
e: 0x20CA,
|
|
8622
|
+
g: 0x20A3,
|
|
8623
|
+
o: 0x20C5
|
|
8624
|
+
});
|
|
8576
8625
|
|
|
8577
|
-
const
|
|
8578
|
-
|
|
8579
|
-
|
|
8580
|
-
|
|
8581
|
-
|
|
8582
|
-
|
|
8626
|
+
const frak = Object.freeze({
|
|
8627
|
+
C: 0x20EA,
|
|
8628
|
+
H: 0x20C4,
|
|
8629
|
+
I: 0x20C8,
|
|
8630
|
+
R: 0x20CA,
|
|
8631
|
+
Z: 0x20CE
|
|
8632
|
+
});
|
|
8583
8633
|
|
|
8584
|
-
|
|
8585
|
-
|
|
8586
|
-
|
|
8587
|
-
|
|
8588
|
-
|
|
8589
|
-
|
|
8590
|
-
|
|
8591
|
-
|
|
8592
|
-
|
|
8593
|
-
"\\boldsymbol",
|
|
8634
|
+
const bbb = Object.freeze({
|
|
8635
|
+
C: 0x20BF, // blackboard bold
|
|
8636
|
+
H: 0x20C5,
|
|
8637
|
+
N: 0x20C7,
|
|
8638
|
+
P: 0x20C9,
|
|
8639
|
+
Q: 0x20C9,
|
|
8640
|
+
R: 0x20CB,
|
|
8641
|
+
Z: 0x20CA
|
|
8642
|
+
});
|
|
8594
8643
|
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
|
|
8644
|
+
const bold = Object.freeze({
|
|
8645
|
+
"\u03f5": 0x1D2E7, // lunate epsilon
|
|
8646
|
+
"\u03d1": 0x1D30C, // vartheta
|
|
8647
|
+
"\u03f0": 0x1D2EE, // varkappa
|
|
8648
|
+
"\u03c6": 0x1D319, // varphi
|
|
8649
|
+
"\u03f1": 0x1D2EF, // varrho
|
|
8650
|
+
"\u03d6": 0x1D30B // varpi
|
|
8651
|
+
});
|
|
8603
8652
|
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
numArgs: 1,
|
|
8612
|
-
allowedInArgument: true
|
|
8613
|
-
},
|
|
8614
|
-
handler: ({ parser, funcName }, args) => {
|
|
8615
|
-
const body = normalizeArgument(args[0]);
|
|
8616
|
-
let func = funcName;
|
|
8617
|
-
if (func in fontAliases) {
|
|
8618
|
-
func = fontAliases[func];
|
|
8619
|
-
}
|
|
8620
|
-
return {
|
|
8621
|
-
type: "font",
|
|
8622
|
-
mode: parser.mode,
|
|
8623
|
-
font: func.slice(1),
|
|
8624
|
-
body
|
|
8625
|
-
};
|
|
8626
|
-
},
|
|
8627
|
-
mathmlBuilder: mathmlBuilder$6
|
|
8653
|
+
const boldItalic = Object.freeze({
|
|
8654
|
+
"\u03f5": 0x1D35B, // lunate epsilon
|
|
8655
|
+
"\u03d1": 0x1D380, // vartheta
|
|
8656
|
+
"\u03f0": 0x1D362, // varkappa
|
|
8657
|
+
"\u03c6": 0x1D38D, // varphi
|
|
8658
|
+
"\u03f1": 0x1D363, // varrho
|
|
8659
|
+
"\u03d6": 0x1D37F // varpi
|
|
8628
8660
|
});
|
|
8629
8661
|
|
|
8630
|
-
|
|
8631
|
-
|
|
8632
|
-
|
|
8633
|
-
|
|
8634
|
-
|
|
8635
|
-
|
|
8636
|
-
|
|
8637
|
-
|
|
8638
|
-
handler: ({ parser, funcName, breakOnTokenText }, args) => {
|
|
8639
|
-
const { mode } = parser;
|
|
8640
|
-
const body = parser.parseExpression(true, breakOnTokenText, true);
|
|
8641
|
-
const fontStyle = `math${funcName.slice(1)}`;
|
|
8662
|
+
const boldsf = Object.freeze({
|
|
8663
|
+
"\u03f5": 0x1D395, // lunate epsilon
|
|
8664
|
+
"\u03d1": 0x1D3BA, // vartheta
|
|
8665
|
+
"\u03f0": 0x1D39C, // varkappa
|
|
8666
|
+
"\u03c6": 0x1D3C7, // varphi
|
|
8667
|
+
"\u03f1": 0x1D39D, // varrho
|
|
8668
|
+
"\u03d6": 0x1D3B9 // varpi
|
|
8669
|
+
});
|
|
8642
8670
|
|
|
8643
|
-
|
|
8644
|
-
|
|
8671
|
+
const bisf = Object.freeze({
|
|
8672
|
+
"\u03f5": 0x1D3CF, // lunate epsilon
|
|
8673
|
+
"\u03d1": 0x1D3F4, // vartheta
|
|
8674
|
+
"\u03f0": 0x1D3D6, // varkappa
|
|
8675
|
+
"\u03c6": 0x1D401, // varphi
|
|
8676
|
+
"\u03f1": 0x1D3D7, // varrho
|
|
8677
|
+
"\u03d6": 0x1D3F3 // varpi
|
|
8678
|
+
});
|
|
8679
|
+
|
|
8680
|
+
// Code point offsets below are derived from https://www.unicode.org/charts/PDF/U1D400.pdf
|
|
8681
|
+
const offset = Object.freeze({
|
|
8682
|
+
upperCaseLatin: { // A-Z
|
|
8683
|
+
"normal": ch => { return 0 },
|
|
8684
|
+
"bold": ch => { return 0x1D3BF },
|
|
8685
|
+
"italic": ch => { return 0x1D3F3 },
|
|
8686
|
+
"bold-italic": ch => { return 0x1D427 },
|
|
8687
|
+
"script": ch => { return script[ch] || 0x1D45B },
|
|
8688
|
+
"script-bold": ch => { return 0x1D48F },
|
|
8689
|
+
"fraktur": ch => { return frak[ch] || 0x1D4C3 },
|
|
8690
|
+
"fraktur-bold": ch => { return 0x1D52B },
|
|
8691
|
+
"double-struck": ch => { return bbb[ch] || 0x1D4F7 },
|
|
8692
|
+
"sans-serif": ch => { return 0x1D55F },
|
|
8693
|
+
"sans-serif-bold": ch => { return 0x1D593 },
|
|
8694
|
+
"sans-serif-italic": ch => { return 0x1D5C7 },
|
|
8695
|
+
"sans-serif-bold-italic": ch => { return 0x1D63C },
|
|
8696
|
+
"monospace": ch => { return 0x1D62F }
|
|
8697
|
+
},
|
|
8698
|
+
lowerCaseLatin: { // a-z
|
|
8699
|
+
"normal": ch => { return 0 },
|
|
8700
|
+
"bold": ch => { return 0x1D3B9 },
|
|
8701
|
+
"italic": ch => { return ch === "h" ? 0x20A6 : 0x1D3ED },
|
|
8702
|
+
"bold-italic": ch => { return 0x1D421 },
|
|
8703
|
+
"script": ch => { return script[ch] || 0x1D455 },
|
|
8704
|
+
"script-bold": ch => { return 0x1D489 },
|
|
8705
|
+
"fraktur": ch => { return 0x1D4BD },
|
|
8706
|
+
"fraktur-bold": ch => { return 0x1D525 },
|
|
8707
|
+
"double-struck": ch => { return 0x1D4F1 },
|
|
8708
|
+
"sans-serif": ch => { return 0x1D559 },
|
|
8709
|
+
"sans-serif-bold": ch => { return 0x1D58D },
|
|
8710
|
+
"sans-serif-italic": ch => { return 0x1D5C1 },
|
|
8711
|
+
"sans-serif-bold-italic": ch => { return 0x1D5F5 },
|
|
8712
|
+
"monospace": ch => { return 0x1D629 }
|
|
8713
|
+
},
|
|
8714
|
+
upperCaseGreek: { // A-Ω
|
|
8715
|
+
"normal": ch => { return 0 },
|
|
8716
|
+
"bold": ch => { return 0x1D317 },
|
|
8717
|
+
"italic": ch => { return 0x1D351 },
|
|
8718
|
+
// \boldsymbol actually returns upright bold for upperCaseGreek
|
|
8719
|
+
"bold-italic": ch => { return 0x1D317 },
|
|
8720
|
+
"script": ch => { return 0 },
|
|
8721
|
+
"script-bold": ch => { return 0 },
|
|
8722
|
+
"fraktur": ch => { return 0 },
|
|
8723
|
+
"fraktur-bold": ch => { return 0 },
|
|
8724
|
+
"double-struck": ch => { return 0 },
|
|
8725
|
+
// Unicode has no code points for regular-weight san-serif Greek. Use bold.
|
|
8726
|
+
"sans-serif": ch => { return 0x1D3C5 },
|
|
8727
|
+
"sans-serif-bold": ch => { return 0x1D3C5 },
|
|
8728
|
+
"sans-serif-italic": ch => { return 0 },
|
|
8729
|
+
"sans-serif-bold-italic": ch => { return 0x1D3FF },
|
|
8730
|
+
"monospace": ch => { return 0 }
|
|
8731
|
+
},
|
|
8732
|
+
lowerCaseGreek: { // α-ω
|
|
8733
|
+
"normal": ch => { return 0 },
|
|
8734
|
+
"bold": ch => { return 0x1D311 },
|
|
8735
|
+
"italic": ch => { return 0x1D34B },
|
|
8736
|
+
"bold-italic": ch => { return ch === "\u03d5" ? 0x1D37E : 0x1D385 },
|
|
8737
|
+
"script": ch => { return 0 },
|
|
8738
|
+
"script-bold": ch => { return 0 },
|
|
8739
|
+
"fraktur": ch => { return 0 },
|
|
8740
|
+
"fraktur-bold": ch => { return 0 },
|
|
8741
|
+
"double-struck": ch => { return 0 },
|
|
8742
|
+
// Unicode has no code points for regular-weight san-serif Greek. Use bold.
|
|
8743
|
+
"sans-serif": ch => { return 0x1D3BF },
|
|
8744
|
+
"sans-serif-bold": ch => { return 0x1D3BF },
|
|
8745
|
+
"sans-serif-italic": ch => { return 0 },
|
|
8746
|
+
"sans-serif-bold-italic": ch => { return 0x1D3F9 },
|
|
8747
|
+
"monospace": ch => { return 0 }
|
|
8748
|
+
},
|
|
8749
|
+
varGreek: { // \varGamma, etc
|
|
8750
|
+
"normal": ch => { return 0 },
|
|
8751
|
+
"bold": ch => { return bold[ch] || -51 },
|
|
8752
|
+
"italic": ch => { return 0 },
|
|
8753
|
+
"bold-italic": ch => { return boldItalic[ch] || 0x3A },
|
|
8754
|
+
"script": ch => { return 0 },
|
|
8755
|
+
"script-bold": ch => { return 0 },
|
|
8756
|
+
"fraktur": ch => { return 0 },
|
|
8757
|
+
"fraktur-bold": ch => { return 0 },
|
|
8758
|
+
"double-struck": ch => { return 0 },
|
|
8759
|
+
"sans-serif": ch => { return boldsf[ch] || 0x74 },
|
|
8760
|
+
"sans-serif-bold": ch => { return boldsf[ch] || 0x74 },
|
|
8761
|
+
"sans-serif-italic": ch => { return 0 },
|
|
8762
|
+
"sans-serif-bold-italic": ch => { return bisf[ch] || 0xAE },
|
|
8763
|
+
"monospace": ch => { return 0 }
|
|
8764
|
+
},
|
|
8765
|
+
numeral: { // 0-9
|
|
8766
|
+
"normal": ch => { return 0 },
|
|
8767
|
+
"bold": ch => { return 0x1D79E },
|
|
8768
|
+
"italic": ch => { return 0 },
|
|
8769
|
+
"bold-italic": ch => { return 0 },
|
|
8770
|
+
"script": ch => { return 0 },
|
|
8771
|
+
"script-bold": ch => { return 0 },
|
|
8772
|
+
"fraktur": ch => { return 0 },
|
|
8773
|
+
"fraktur-bold": ch => { return 0 },
|
|
8774
|
+
"double-struck": ch => { return 0x1D7A8 },
|
|
8775
|
+
"sans-serif": ch => { return 0x1D7B2 },
|
|
8776
|
+
"sans-serif-bold": ch => { return 0x1D7BC },
|
|
8777
|
+
"sans-serif-italic": ch => { return 0 },
|
|
8778
|
+
"sans-serif-bold-italic": ch => { return 0 },
|
|
8779
|
+
"monospace": ch => { return 0x1D7C6 }
|
|
8780
|
+
}
|
|
8781
|
+
});
|
|
8782
|
+
|
|
8783
|
+
const variantChar = (ch, variant) => {
|
|
8784
|
+
const codePoint = ch.codePointAt(0);
|
|
8785
|
+
const block = 0x40 < codePoint && codePoint < 0x5b
|
|
8786
|
+
? "upperCaseLatin"
|
|
8787
|
+
: 0x60 < codePoint && codePoint < 0x7b
|
|
8788
|
+
? "lowerCaseLatin"
|
|
8789
|
+
: (0x390 < codePoint && codePoint < 0x3AA)
|
|
8790
|
+
? "upperCaseGreek"
|
|
8791
|
+
: 0x3B0 < codePoint && codePoint < 0x3CA || ch === "\u03d5"
|
|
8792
|
+
? "lowerCaseGreek"
|
|
8793
|
+
: 0x1D6E1 < codePoint && codePoint < 0x1D6FC || bold[ch]
|
|
8794
|
+
? "varGreek"
|
|
8795
|
+
: (0x2F < codePoint && codePoint < 0x3A)
|
|
8796
|
+
? "numeral"
|
|
8797
|
+
: "other";
|
|
8798
|
+
return block === "other"
|
|
8799
|
+
? ch
|
|
8800
|
+
: String.fromCodePoint(codePoint + offset[block][variant](ch))
|
|
8801
|
+
};
|
|
8802
|
+
|
|
8803
|
+
const smallCaps = Object.freeze({
|
|
8804
|
+
a: "ᴀ",
|
|
8805
|
+
b: "ʙ",
|
|
8806
|
+
c: "ᴄ",
|
|
8807
|
+
d: "ᴅ",
|
|
8808
|
+
e: "ᴇ",
|
|
8809
|
+
f: "ꜰ",
|
|
8810
|
+
g: "ɢ",
|
|
8811
|
+
h: "ʜ",
|
|
8812
|
+
i: "ɪ",
|
|
8813
|
+
j: "ᴊ",
|
|
8814
|
+
k: "ᴋ",
|
|
8815
|
+
l: "ʟ",
|
|
8816
|
+
m: "ᴍ",
|
|
8817
|
+
n: "ɴ",
|
|
8818
|
+
o: "ᴏ",
|
|
8819
|
+
p: "ᴘ",
|
|
8820
|
+
q: "ǫ",
|
|
8821
|
+
r: "ʀ",
|
|
8822
|
+
s: "s",
|
|
8823
|
+
t: "ᴛ",
|
|
8824
|
+
u: "ᴜ",
|
|
8825
|
+
v: "ᴠ",
|
|
8826
|
+
w: "ᴡ",
|
|
8827
|
+
x: "x",
|
|
8828
|
+
y: "ʏ",
|
|
8829
|
+
z: "ᴢ"
|
|
8830
|
+
});
|
|
8831
|
+
|
|
8832
|
+
const varNameFonts = ["mathrm", "mathit"];
|
|
8833
|
+
|
|
8834
|
+
const isLongVariableName = (group, font) => {
|
|
8835
|
+
if (!varNameFonts.includes(font) || !group.body || group.body.type !== "ordgroup" ||
|
|
8836
|
+
group.body.body.length === 1) {
|
|
8837
|
+
return false
|
|
8838
|
+
}
|
|
8839
|
+
if (group.body.body[0].type !== "mathord") { return false }
|
|
8840
|
+
for (let i = 1; i < group.body.body.length; i++) {
|
|
8841
|
+
const parseNodeType = group.body.body[i].type;
|
|
8842
|
+
if (!(parseNodeType === "mathord" ||
|
|
8843
|
+
(parseNodeType === "textord" && !isNaN(group.body.body[i].text)))) {
|
|
8844
|
+
return false
|
|
8845
|
+
}
|
|
8846
|
+
}
|
|
8847
|
+
return true
|
|
8848
|
+
};
|
|
8849
|
+
|
|
8850
|
+
const mathmlBuilder$6 = (group, style) => {
|
|
8851
|
+
const font = group.font;
|
|
8852
|
+
const newStyle = style.withFont(font);
|
|
8853
|
+
const mathGroup = buildGroup$1(group.body, newStyle);
|
|
8854
|
+
|
|
8855
|
+
if (mathGroup.children.length === 0) { return mathGroup } // empty group, e.g., \mathrm{}
|
|
8856
|
+
if (font === "boldsymbol" && ["mo", "mpadded", "mrow"].includes(mathGroup.type)) {
|
|
8857
|
+
mathGroup.style.fontWeight = "bold";
|
|
8858
|
+
return mathGroup
|
|
8859
|
+
}
|
|
8860
|
+
// Check if it is possible to consolidate elements into a single <mi> element.
|
|
8861
|
+
if (isLongVariableName(group, font)) {
|
|
8862
|
+
// This is a \mathrm{…} or \mathit{…} group. It gets special treatment.
|
|
8863
|
+
const mi = mathGroup.children[0].children[0].children
|
|
8864
|
+
? mathGroup.children[0].children[0]
|
|
8865
|
+
: mathGroup.children[0];
|
|
8866
|
+
delete mi.attributes.mathvariant;
|
|
8867
|
+
for (let i = 1; i < mathGroup.children.length; i++) {
|
|
8868
|
+
mi.children[0].text += mathGroup.children[i].children[0].children
|
|
8869
|
+
? mathGroup.children[i].children[0].children[0].text
|
|
8870
|
+
: mathGroup.children[i].children[0].text;
|
|
8871
|
+
}
|
|
8872
|
+
if (font === "mathit") {
|
|
8873
|
+
// Long <mi> elements are normally rendered in upright font.
|
|
8874
|
+
// To get italic, we need to convert each character to the corresponding italic character.
|
|
8875
|
+
mi.children[0].text = mi.children[0].text.split("")
|
|
8876
|
+
.map(c => variantChar(c, "italic")).join("");
|
|
8877
|
+
return mi
|
|
8878
|
+
}
|
|
8879
|
+
// Otherwise, font is "mathrm". Wrap in a <mpadded> to prevent a Firefox spacing bug.
|
|
8880
|
+
const mpadded = new MathNode("mpadded", [mi]);
|
|
8881
|
+
mpadded.setAttribute("lspace", "0");
|
|
8882
|
+
return mpadded
|
|
8883
|
+
}
|
|
8884
|
+
let canConsolidate = mathGroup.children[0].type === "mo";
|
|
8885
|
+
for (let i = 1; i < mathGroup.children.length; i++) {
|
|
8886
|
+
if (mathGroup.children[i].type === "mo" && font === "boldsymbol") {
|
|
8887
|
+
mathGroup.children[i].style.fontWeight = "bold";
|
|
8888
|
+
}
|
|
8889
|
+
if (mathGroup.children[i].type !== "mi") { canConsolidate = false; }
|
|
8890
|
+
const localVariant = mathGroup.children[i].attributes &&
|
|
8891
|
+
mathGroup.children[i].attributes.mathvariant || "";
|
|
8892
|
+
if (localVariant !== "normal") { canConsolidate = false; }
|
|
8893
|
+
}
|
|
8894
|
+
if (!canConsolidate) { return mathGroup }
|
|
8895
|
+
// Consolidate the <mi> elements.
|
|
8896
|
+
const mi = mathGroup.children[0];
|
|
8897
|
+
for (let i = 1; i < mathGroup.children.length; i++) {
|
|
8898
|
+
mi.children.push(mathGroup.children[i].children[0]);
|
|
8899
|
+
}
|
|
8900
|
+
if (mi.attributes.mathvariant && mi.attributes.mathvariant === "normal") {
|
|
8901
|
+
// Workaround for a Firefox bug that renders spurious space around
|
|
8902
|
+
// a <mi mathvariant="normal">
|
|
8903
|
+
// Ref: https://bugs.webkit.org/show_bug.cgi?id=129097
|
|
8904
|
+
// We insert a text node that contains a zero-width space and wrap in an mrow.
|
|
8905
|
+
// TODO: Get rid of this <mi> workaround when the Firefox bug is fixed.
|
|
8906
|
+
const bogus = new MathNode("mtext", new TextNode("\u200b"));
|
|
8907
|
+
return new MathNode("mrow", [bogus, mi])
|
|
8908
|
+
}
|
|
8909
|
+
return mi
|
|
8910
|
+
};
|
|
8911
|
+
|
|
8912
|
+
const fontAliases = {
|
|
8913
|
+
"\\Bbb": "\\mathbb",
|
|
8914
|
+
"\\bold": "\\mathbf",
|
|
8915
|
+
"\\frak": "\\mathfrak",
|
|
8916
|
+
"\\bm": "\\boldsymbol"
|
|
8917
|
+
};
|
|
8918
|
+
|
|
8919
|
+
defineFunction({
|
|
8920
|
+
type: "font",
|
|
8921
|
+
names: [
|
|
8922
|
+
// styles
|
|
8923
|
+
"\\mathrm",
|
|
8924
|
+
"\\mathit",
|
|
8925
|
+
"\\mathbf",
|
|
8926
|
+
"\\mathnormal",
|
|
8927
|
+
"\\up@greek",
|
|
8928
|
+
"\\boldsymbol",
|
|
8929
|
+
|
|
8930
|
+
// families
|
|
8931
|
+
"\\mathbb",
|
|
8932
|
+
"\\mathcal",
|
|
8933
|
+
"\\mathfrak",
|
|
8934
|
+
"\\mathscr",
|
|
8935
|
+
"\\mathsf",
|
|
8936
|
+
"\\mathsfit",
|
|
8937
|
+
"\\mathtt",
|
|
8938
|
+
|
|
8939
|
+
// aliases
|
|
8940
|
+
"\\Bbb",
|
|
8941
|
+
"\\bm",
|
|
8942
|
+
"\\bold",
|
|
8943
|
+
"\\frak"
|
|
8944
|
+
],
|
|
8945
|
+
props: {
|
|
8946
|
+
numArgs: 1,
|
|
8947
|
+
allowedInArgument: true
|
|
8948
|
+
},
|
|
8949
|
+
handler: ({ parser, funcName }, args) => {
|
|
8950
|
+
const body = normalizeArgument(args[0]);
|
|
8951
|
+
let func = funcName;
|
|
8952
|
+
if (func in fontAliases) {
|
|
8953
|
+
func = fontAliases[func];
|
|
8954
|
+
}
|
|
8955
|
+
return {
|
|
8956
|
+
type: "font",
|
|
8957
|
+
mode: parser.mode,
|
|
8958
|
+
font: func.slice(1),
|
|
8959
|
+
body
|
|
8960
|
+
};
|
|
8961
|
+
},
|
|
8962
|
+
mathmlBuilder: mathmlBuilder$6
|
|
8963
|
+
});
|
|
8964
|
+
|
|
8965
|
+
// Old font changing functions
|
|
8966
|
+
defineFunction({
|
|
8967
|
+
type: "font",
|
|
8968
|
+
names: ["\\rm", "\\sf", "\\tt", "\\bf", "\\it", "\\cal"],
|
|
8969
|
+
props: {
|
|
8970
|
+
numArgs: 0,
|
|
8971
|
+
allowedInText: true
|
|
8972
|
+
},
|
|
8973
|
+
handler: ({ parser, funcName, breakOnTokenText }, args) => {
|
|
8974
|
+
const { mode } = parser;
|
|
8975
|
+
const body = parser.parseExpression(true, breakOnTokenText, true);
|
|
8976
|
+
const fontStyle = `math${funcName.slice(1)}`;
|
|
8977
|
+
|
|
8978
|
+
return {
|
|
8979
|
+
type: "font",
|
|
8645
8980
|
mode: mode,
|
|
8646
8981
|
font: fontStyle,
|
|
8647
8982
|
body: {
|
|
@@ -8657,22 +8992,37 @@ defineFunction({
|
|
|
8657
8992
|
const stylArray = ["display", "text", "script", "scriptscript"];
|
|
8658
8993
|
const scriptLevel = { auto: -1, display: 0, text: 0, script: 1, scriptscript: 2 };
|
|
8659
8994
|
|
|
8995
|
+
const adjustStyle = (functionSize, originalStyle) => {
|
|
8996
|
+
// Figure out what style this fraction should be in based on the
|
|
8997
|
+
// function used
|
|
8998
|
+
let style = originalStyle;
|
|
8999
|
+
if (functionSize === "display") { //\tfrac or \cfrac
|
|
9000
|
+
// Get display style as a default.
|
|
9001
|
+
// If incoming style is sub/sup, use style.text() to get correct size.
|
|
9002
|
+
const newSize = style.level >= StyleLevel.SCRIPT ? StyleLevel.TEXT : StyleLevel.DISPLAY;
|
|
9003
|
+
style = style.withLevel(newSize);
|
|
9004
|
+
} else if (functionSize === "text" &&
|
|
9005
|
+
style.level === StyleLevel.DISPLAY) {
|
|
9006
|
+
// We're in a \tfrac but incoming style is displaystyle, so:
|
|
9007
|
+
style = style.withLevel(StyleLevel.TEXT);
|
|
9008
|
+
} else if (functionSize === "auto") {
|
|
9009
|
+
style = style.incrementLevel();
|
|
9010
|
+
} else if (functionSize === "script") {
|
|
9011
|
+
style = style.withLevel(StyleLevel.SCRIPT);
|
|
9012
|
+
} else if (functionSize === "scriptscript") {
|
|
9013
|
+
style = style.withLevel(StyleLevel.SCRIPTSCRIPT);
|
|
9014
|
+
}
|
|
9015
|
+
return style;
|
|
9016
|
+
};
|
|
9017
|
+
|
|
8660
9018
|
const mathmlBuilder$5 = (group, style) => {
|
|
8661
|
-
|
|
8662
|
-
// We may need that info for \mathchoice or for adjusting em dimensions.
|
|
8663
|
-
const childOptions = group.scriptLevel === "auto"
|
|
8664
|
-
? style.incrementLevel()
|
|
8665
|
-
: group.scriptLevel === "display"
|
|
8666
|
-
? style.withLevel(StyleLevel.TEXT)
|
|
8667
|
-
: group.scriptLevel === "text"
|
|
8668
|
-
? style.withLevel(StyleLevel.SCRIPT)
|
|
8669
|
-
: style.withLevel(StyleLevel.SCRIPTSCRIPT);
|
|
9019
|
+
style = adjustStyle(group.scriptLevel, style);
|
|
8670
9020
|
|
|
8671
9021
|
// Chromium (wrongly) continues to shrink fractions beyond scriptscriptlevel.
|
|
8672
9022
|
// So we check for levels that Chromium shrinks too small.
|
|
8673
9023
|
// If necessary, set an explicit fraction depth.
|
|
8674
|
-
const numer = buildGroup$1(group.numer,
|
|
8675
|
-
const denom = buildGroup$1(group.denom,
|
|
9024
|
+
const numer = buildGroup$1(group.numer, style);
|
|
9025
|
+
const denom = buildGroup$1(group.denom, style);
|
|
8676
9026
|
if (style.level === 3) {
|
|
8677
9027
|
numer.style.mathDepth = "2";
|
|
8678
9028
|
numer.setAttribute("scriptlevel", "2");
|
|
@@ -8725,6 +9075,7 @@ const mathmlBuilder$5 = (group, style) => {
|
|
|
8725
9075
|
defineFunction({
|
|
8726
9076
|
type: "genfrac",
|
|
8727
9077
|
names: [
|
|
9078
|
+
"\\cfrac",
|
|
8728
9079
|
"\\dfrac",
|
|
8729
9080
|
"\\frac",
|
|
8730
9081
|
"\\tfrac",
|
|
@@ -8748,6 +9099,7 @@ defineFunction({
|
|
|
8748
9099
|
let scriptLevel = "auto";
|
|
8749
9100
|
|
|
8750
9101
|
switch (funcName) {
|
|
9102
|
+
case "\\cfrac":
|
|
8751
9103
|
case "\\dfrac":
|
|
8752
9104
|
case "\\frac":
|
|
8753
9105
|
case "\\tfrac":
|
|
@@ -8774,56 +9126,26 @@ defineFunction({
|
|
|
8774
9126
|
throw new Error("Unrecognized genfrac command");
|
|
8775
9127
|
}
|
|
8776
9128
|
|
|
8777
|
-
|
|
8778
|
-
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
|
|
8782
|
-
case "\\tfrac":
|
|
8783
|
-
case "\\tbinom":
|
|
8784
|
-
scriptLevel = "text";
|
|
8785
|
-
break;
|
|
8786
|
-
}
|
|
8787
|
-
|
|
8788
|
-
return {
|
|
8789
|
-
type: "genfrac",
|
|
8790
|
-
mode: parser.mode,
|
|
8791
|
-
continued: false,
|
|
8792
|
-
numer,
|
|
8793
|
-
denom,
|
|
8794
|
-
hasBarLine,
|
|
8795
|
-
leftDelim,
|
|
8796
|
-
rightDelim,
|
|
8797
|
-
scriptLevel,
|
|
8798
|
-
barSize: null
|
|
8799
|
-
};
|
|
8800
|
-
},
|
|
8801
|
-
mathmlBuilder: mathmlBuilder$5
|
|
8802
|
-
});
|
|
8803
|
-
|
|
8804
|
-
defineFunction({
|
|
8805
|
-
type: "genfrac",
|
|
8806
|
-
names: ["\\cfrac"],
|
|
8807
|
-
props: {
|
|
8808
|
-
numArgs: 2
|
|
8809
|
-
},
|
|
8810
|
-
handler: ({ parser, funcName }, args) => {
|
|
8811
|
-
const numer = args[0];
|
|
8812
|
-
const denom = args[1];
|
|
9129
|
+
if (funcName === "\\cfrac" || funcName.startsWith("\\d")) {
|
|
9130
|
+
scriptLevel = "display";
|
|
9131
|
+
} else if (funcName.startsWith("\\t")) {
|
|
9132
|
+
scriptLevel = "text";
|
|
9133
|
+
}
|
|
8813
9134
|
|
|
8814
9135
|
return {
|
|
8815
9136
|
type: "genfrac",
|
|
8816
9137
|
mode: parser.mode,
|
|
8817
|
-
continued:
|
|
9138
|
+
continued: false,
|
|
8818
9139
|
numer,
|
|
8819
9140
|
denom,
|
|
8820
|
-
hasBarLine
|
|
8821
|
-
leftDelim
|
|
8822
|
-
rightDelim
|
|
8823
|
-
scriptLevel
|
|
9141
|
+
hasBarLine,
|
|
9142
|
+
leftDelim,
|
|
9143
|
+
rightDelim,
|
|
9144
|
+
scriptLevel,
|
|
8824
9145
|
barSize: null
|
|
8825
9146
|
};
|
|
8826
|
-
}
|
|
9147
|
+
},
|
|
9148
|
+
mathmlBuilder: mathmlBuilder$5
|
|
8827
9149
|
});
|
|
8828
9150
|
|
|
8829
9151
|
// Infix generalized fractions -- these are not rendered directly, but replaced
|
|
@@ -9654,8 +9976,16 @@ const binrelClass = (arg) => {
|
|
|
9654
9976
|
const atom = arg.type === "ordgroup" && arg.body.length && arg.body.length === 1
|
|
9655
9977
|
? arg.body[0]
|
|
9656
9978
|
: arg;
|
|
9657
|
-
if (atom.type === "atom"
|
|
9658
|
-
|
|
9979
|
+
if (atom.type === "atom") {
|
|
9980
|
+
// BIN args are sometimes changed to OPEN, so check the original family.
|
|
9981
|
+
const family = arg.body.length > 0 && arg.body[0].text && symbols.math[arg.body[0].text]
|
|
9982
|
+
? symbols.math[arg.body[0].text].group
|
|
9983
|
+
: atom.family;
|
|
9984
|
+
if (family === "bin" || family === "rel") {
|
|
9985
|
+
return "m" + family;
|
|
9986
|
+
} else {
|
|
9987
|
+
return "mord";
|
|
9988
|
+
}
|
|
9659
9989
|
} else {
|
|
9660
9990
|
return "mord";
|
|
9661
9991
|
}
|
|
@@ -10226,6 +10556,14 @@ const mathmlBuilder$1 = (group, style) => {
|
|
|
10226
10556
|
if ((node.type === "mrow" || node.type === "mpadded") && node.children.length === 1 &&
|
|
10227
10557
|
node.children[0] instanceof MathNode) {
|
|
10228
10558
|
node = node.children[0];
|
|
10559
|
+
} else if (node.type === "mrow" && node.children.length === 2 &&
|
|
10560
|
+
node.children[0] instanceof MathNode &&
|
|
10561
|
+
node.children[1] instanceof MathNode &&
|
|
10562
|
+
node.children[1].type === "mspace" && !node.children[1].attributes.width &&
|
|
10563
|
+
node.children[1].children.length === 0) {
|
|
10564
|
+
// This is a workaround for a Firefox bug that applies spacing to
|
|
10565
|
+
// an <mi> with mathvariant="normal".
|
|
10566
|
+
node = node.children[0];
|
|
10229
10567
|
}
|
|
10230
10568
|
switch (node.type) {
|
|
10231
10569
|
case "mi":
|
|
@@ -10416,7 +10754,7 @@ defineFunction({
|
|
|
10416
10754
|
const inner = buildExpression(ordargument(group.body), style);
|
|
10417
10755
|
const phantom = new MathNode("mphantom", inner);
|
|
10418
10756
|
const node = new MathNode("mpadded", [phantom]);
|
|
10419
|
-
node.setAttribute("width", "
|
|
10757
|
+
node.setAttribute("width", "0.1px");
|
|
10420
10758
|
return node;
|
|
10421
10759
|
}
|
|
10422
10760
|
});
|
|
@@ -11233,232 +11571,6 @@ const getVariant = function(group, style) {
|
|
|
11233
11571
|
return Object.prototype.hasOwnProperty.call(fontMap, font) ? fontMap[font] : null
|
|
11234
11572
|
};
|
|
11235
11573
|
|
|
11236
|
-
// Chromium does not support the MathML `mathvariant` attribute.
|
|
11237
|
-
// Instead, we replace ASCII characters with Unicode characters that
|
|
11238
|
-
// are defined in the font as bold, italic, double-struck, etc.
|
|
11239
|
-
// This module identifies those Unicode code points.
|
|
11240
|
-
|
|
11241
|
-
// First, a few helpers.
|
|
11242
|
-
const script = Object.freeze({
|
|
11243
|
-
B: 0x20EA, // Offset from ASCII B to Unicode script B
|
|
11244
|
-
E: 0x20EB,
|
|
11245
|
-
F: 0x20EB,
|
|
11246
|
-
H: 0x20C3,
|
|
11247
|
-
I: 0x20C7,
|
|
11248
|
-
L: 0x20C6,
|
|
11249
|
-
M: 0x20E6,
|
|
11250
|
-
R: 0x20C9,
|
|
11251
|
-
e: 0x20CA,
|
|
11252
|
-
g: 0x20A3,
|
|
11253
|
-
o: 0x20C5
|
|
11254
|
-
});
|
|
11255
|
-
|
|
11256
|
-
const frak = Object.freeze({
|
|
11257
|
-
C: 0x20EA,
|
|
11258
|
-
H: 0x20C4,
|
|
11259
|
-
I: 0x20C8,
|
|
11260
|
-
R: 0x20CA,
|
|
11261
|
-
Z: 0x20CE
|
|
11262
|
-
});
|
|
11263
|
-
|
|
11264
|
-
const bbb = Object.freeze({
|
|
11265
|
-
C: 0x20BF, // blackboard bold
|
|
11266
|
-
H: 0x20C5,
|
|
11267
|
-
N: 0x20C7,
|
|
11268
|
-
P: 0x20C9,
|
|
11269
|
-
Q: 0x20C9,
|
|
11270
|
-
R: 0x20CB,
|
|
11271
|
-
Z: 0x20CA
|
|
11272
|
-
});
|
|
11273
|
-
|
|
11274
|
-
const bold = Object.freeze({
|
|
11275
|
-
"\u03f5": 0x1D2E7, // lunate epsilon
|
|
11276
|
-
"\u03d1": 0x1D30C, // vartheta
|
|
11277
|
-
"\u03f0": 0x1D2EE, // varkappa
|
|
11278
|
-
"\u03c6": 0x1D319, // varphi
|
|
11279
|
-
"\u03f1": 0x1D2EF, // varrho
|
|
11280
|
-
"\u03d6": 0x1D30B // varpi
|
|
11281
|
-
});
|
|
11282
|
-
|
|
11283
|
-
const boldItalic = Object.freeze({
|
|
11284
|
-
"\u03f5": 0x1D35B, // lunate epsilon
|
|
11285
|
-
"\u03d1": 0x1D380, // vartheta
|
|
11286
|
-
"\u03f0": 0x1D362, // varkappa
|
|
11287
|
-
"\u03c6": 0x1D38D, // varphi
|
|
11288
|
-
"\u03f1": 0x1D363, // varrho
|
|
11289
|
-
"\u03d6": 0x1D37F // varpi
|
|
11290
|
-
});
|
|
11291
|
-
|
|
11292
|
-
const boldsf = Object.freeze({
|
|
11293
|
-
"\u03f5": 0x1D395, // lunate epsilon
|
|
11294
|
-
"\u03d1": 0x1D3BA, // vartheta
|
|
11295
|
-
"\u03f0": 0x1D39C, // varkappa
|
|
11296
|
-
"\u03c6": 0x1D3C7, // varphi
|
|
11297
|
-
"\u03f1": 0x1D39D, // varrho
|
|
11298
|
-
"\u03d6": 0x1D3B9 // varpi
|
|
11299
|
-
});
|
|
11300
|
-
|
|
11301
|
-
const bisf = Object.freeze({
|
|
11302
|
-
"\u03f5": 0x1D3CF, // lunate epsilon
|
|
11303
|
-
"\u03d1": 0x1D3F4, // vartheta
|
|
11304
|
-
"\u03f0": 0x1D3D6, // varkappa
|
|
11305
|
-
"\u03c6": 0x1D401, // varphi
|
|
11306
|
-
"\u03f1": 0x1D3D7, // varrho
|
|
11307
|
-
"\u03d6": 0x1D3F3 // varpi
|
|
11308
|
-
});
|
|
11309
|
-
|
|
11310
|
-
// Code point offsets below are derived from https://www.unicode.org/charts/PDF/U1D400.pdf
|
|
11311
|
-
const offset = Object.freeze({
|
|
11312
|
-
upperCaseLatin: { // A-Z
|
|
11313
|
-
"normal": ch => { return 0 },
|
|
11314
|
-
"bold": ch => { return 0x1D3BF },
|
|
11315
|
-
"italic": ch => { return 0x1D3F3 },
|
|
11316
|
-
"bold-italic": ch => { return 0x1D427 },
|
|
11317
|
-
"script": ch => { return script[ch] || 0x1D45B },
|
|
11318
|
-
"script-bold": ch => { return 0x1D48F },
|
|
11319
|
-
"fraktur": ch => { return frak[ch] || 0x1D4C3 },
|
|
11320
|
-
"fraktur-bold": ch => { return 0x1D52B },
|
|
11321
|
-
"double-struck": ch => { return bbb[ch] || 0x1D4F7 },
|
|
11322
|
-
"sans-serif": ch => { return 0x1D55F },
|
|
11323
|
-
"sans-serif-bold": ch => { return 0x1D593 },
|
|
11324
|
-
"sans-serif-italic": ch => { return 0x1D5C7 },
|
|
11325
|
-
"sans-serif-bold-italic": ch => { return 0x1D63C },
|
|
11326
|
-
"monospace": ch => { return 0x1D62F }
|
|
11327
|
-
},
|
|
11328
|
-
lowerCaseLatin: { // a-z
|
|
11329
|
-
"normal": ch => { return 0 },
|
|
11330
|
-
"bold": ch => { return 0x1D3B9 },
|
|
11331
|
-
"italic": ch => { return ch === "h" ? 0x20A6 : 0x1D3ED },
|
|
11332
|
-
"bold-italic": ch => { return 0x1D421 },
|
|
11333
|
-
"script": ch => { return script[ch] || 0x1D455 },
|
|
11334
|
-
"script-bold": ch => { return 0x1D489 },
|
|
11335
|
-
"fraktur": ch => { return 0x1D4BD },
|
|
11336
|
-
"fraktur-bold": ch => { return 0x1D525 },
|
|
11337
|
-
"double-struck": ch => { return 0x1D4F1 },
|
|
11338
|
-
"sans-serif": ch => { return 0x1D559 },
|
|
11339
|
-
"sans-serif-bold": ch => { return 0x1D58D },
|
|
11340
|
-
"sans-serif-italic": ch => { return 0x1D5C1 },
|
|
11341
|
-
"sans-serif-bold-italic": ch => { return 0x1D5F5 },
|
|
11342
|
-
"monospace": ch => { return 0x1D629 }
|
|
11343
|
-
},
|
|
11344
|
-
upperCaseGreek: { // A-Ω
|
|
11345
|
-
"normal": ch => { return 0 },
|
|
11346
|
-
"bold": ch => { return 0x1D317 },
|
|
11347
|
-
"italic": ch => { return 0x1D351 },
|
|
11348
|
-
// \boldsymbol actually returns upright bold for upperCaseGreek
|
|
11349
|
-
"bold-italic": ch => { return 0x1D317 },
|
|
11350
|
-
"script": ch => { return 0 },
|
|
11351
|
-
"script-bold": ch => { return 0 },
|
|
11352
|
-
"fraktur": ch => { return 0 },
|
|
11353
|
-
"fraktur-bold": ch => { return 0 },
|
|
11354
|
-
"double-struck": ch => { return 0 },
|
|
11355
|
-
// Unicode has no code points for regular-weight san-serif Greek. Use bold.
|
|
11356
|
-
"sans-serif": ch => { return 0x1D3C5 },
|
|
11357
|
-
"sans-serif-bold": ch => { return 0x1D3C5 },
|
|
11358
|
-
"sans-serif-italic": ch => { return 0 },
|
|
11359
|
-
"sans-serif-bold-italic": ch => { return 0x1D3FF },
|
|
11360
|
-
"monospace": ch => { return 0 }
|
|
11361
|
-
},
|
|
11362
|
-
lowerCaseGreek: { // α-ω
|
|
11363
|
-
"normal": ch => { return 0 },
|
|
11364
|
-
"bold": ch => { return 0x1D311 },
|
|
11365
|
-
"italic": ch => { return 0x1D34B },
|
|
11366
|
-
"bold-italic": ch => { return ch === "\u03d5" ? 0x1D37E : 0x1D385 },
|
|
11367
|
-
"script": ch => { return 0 },
|
|
11368
|
-
"script-bold": ch => { return 0 },
|
|
11369
|
-
"fraktur": ch => { return 0 },
|
|
11370
|
-
"fraktur-bold": ch => { return 0 },
|
|
11371
|
-
"double-struck": ch => { return 0 },
|
|
11372
|
-
// Unicode has no code points for regular-weight san-serif Greek. Use bold.
|
|
11373
|
-
"sans-serif": ch => { return 0x1D3BF },
|
|
11374
|
-
"sans-serif-bold": ch => { return 0x1D3BF },
|
|
11375
|
-
"sans-serif-italic": ch => { return 0 },
|
|
11376
|
-
"sans-serif-bold-italic": ch => { return 0x1D3F9 },
|
|
11377
|
-
"monospace": ch => { return 0 }
|
|
11378
|
-
},
|
|
11379
|
-
varGreek: { // \varGamma, etc
|
|
11380
|
-
"normal": ch => { return 0 },
|
|
11381
|
-
"bold": ch => { return bold[ch] || -51 },
|
|
11382
|
-
"italic": ch => { return 0 },
|
|
11383
|
-
"bold-italic": ch => { return boldItalic[ch] || 0x3A },
|
|
11384
|
-
"script": ch => { return 0 },
|
|
11385
|
-
"script-bold": ch => { return 0 },
|
|
11386
|
-
"fraktur": ch => { return 0 },
|
|
11387
|
-
"fraktur-bold": ch => { return 0 },
|
|
11388
|
-
"double-struck": ch => { return 0 },
|
|
11389
|
-
"sans-serif": ch => { return boldsf[ch] || 0x74 },
|
|
11390
|
-
"sans-serif-bold": ch => { return boldsf[ch] || 0x74 },
|
|
11391
|
-
"sans-serif-italic": ch => { return 0 },
|
|
11392
|
-
"sans-serif-bold-italic": ch => { return bisf[ch] || 0xAE },
|
|
11393
|
-
"monospace": ch => { return 0 }
|
|
11394
|
-
},
|
|
11395
|
-
numeral: { // 0-9
|
|
11396
|
-
"normal": ch => { return 0 },
|
|
11397
|
-
"bold": ch => { return 0x1D79E },
|
|
11398
|
-
"italic": ch => { return 0 },
|
|
11399
|
-
"bold-italic": ch => { return 0 },
|
|
11400
|
-
"script": ch => { return 0 },
|
|
11401
|
-
"script-bold": ch => { return 0 },
|
|
11402
|
-
"fraktur": ch => { return 0 },
|
|
11403
|
-
"fraktur-bold": ch => { return 0 },
|
|
11404
|
-
"double-struck": ch => { return 0x1D7A8 },
|
|
11405
|
-
"sans-serif": ch => { return 0x1D7B2 },
|
|
11406
|
-
"sans-serif-bold": ch => { return 0x1D7BC },
|
|
11407
|
-
"sans-serif-italic": ch => { return 0 },
|
|
11408
|
-
"sans-serif-bold-italic": ch => { return 0 },
|
|
11409
|
-
"monospace": ch => { return 0x1D7C6 }
|
|
11410
|
-
}
|
|
11411
|
-
});
|
|
11412
|
-
|
|
11413
|
-
const variantChar = (ch, variant) => {
|
|
11414
|
-
const codePoint = ch.codePointAt(0);
|
|
11415
|
-
const block = 0x40 < codePoint && codePoint < 0x5b
|
|
11416
|
-
? "upperCaseLatin"
|
|
11417
|
-
: 0x60 < codePoint && codePoint < 0x7b
|
|
11418
|
-
? "lowerCaseLatin"
|
|
11419
|
-
: (0x390 < codePoint && codePoint < 0x3AA)
|
|
11420
|
-
? "upperCaseGreek"
|
|
11421
|
-
: 0x3B0 < codePoint && codePoint < 0x3CA || ch === "\u03d5"
|
|
11422
|
-
? "lowerCaseGreek"
|
|
11423
|
-
: 0x1D6E1 < codePoint && codePoint < 0x1D6FC || bold[ch]
|
|
11424
|
-
? "varGreek"
|
|
11425
|
-
: (0x2F < codePoint && codePoint < 0x3A)
|
|
11426
|
-
? "numeral"
|
|
11427
|
-
: "other";
|
|
11428
|
-
return block === "other"
|
|
11429
|
-
? ch
|
|
11430
|
-
: String.fromCodePoint(codePoint + offset[block][variant](ch))
|
|
11431
|
-
};
|
|
11432
|
-
|
|
11433
|
-
const smallCaps = Object.freeze({
|
|
11434
|
-
a: "ᴀ",
|
|
11435
|
-
b: "ʙ",
|
|
11436
|
-
c: "ᴄ",
|
|
11437
|
-
d: "ᴅ",
|
|
11438
|
-
e: "ᴇ",
|
|
11439
|
-
f: "ꜰ",
|
|
11440
|
-
g: "ɢ",
|
|
11441
|
-
h: "ʜ",
|
|
11442
|
-
i: "ɪ",
|
|
11443
|
-
j: "ᴊ",
|
|
11444
|
-
k: "ᴋ",
|
|
11445
|
-
l: "ʟ",
|
|
11446
|
-
m: "ᴍ",
|
|
11447
|
-
n: "ɴ",
|
|
11448
|
-
o: "ᴏ",
|
|
11449
|
-
p: "ᴘ",
|
|
11450
|
-
q: "ǫ",
|
|
11451
|
-
r: "ʀ",
|
|
11452
|
-
s: "s",
|
|
11453
|
-
t: "ᴛ",
|
|
11454
|
-
u: "ᴜ",
|
|
11455
|
-
v: "ᴠ",
|
|
11456
|
-
w: "ᴡ",
|
|
11457
|
-
x: "x",
|
|
11458
|
-
y: "ʏ",
|
|
11459
|
-
z: "ᴢ"
|
|
11460
|
-
});
|
|
11461
|
-
|
|
11462
11574
|
// "mathord" and "textord" ParseNodes created in Parser.js from symbol Groups in
|
|
11463
11575
|
// src/symbols.js.
|
|
11464
11576
|
|
|
@@ -11496,8 +11608,8 @@ defineFunctionBuilders({
|
|
|
11496
11608
|
node.setAttribute("mathvariant", "normal");
|
|
11497
11609
|
if (text.text.length === 1) {
|
|
11498
11610
|
// A Firefox bug will apply spacing here, but there should be none. Fix it.
|
|
11499
|
-
|
|
11500
|
-
node
|
|
11611
|
+
const mspace = new MathNode("mspace", []);
|
|
11612
|
+
node = new MathNode("mrow", [node, mspace]);
|
|
11501
11613
|
}
|
|
11502
11614
|
}
|
|
11503
11615
|
return node
|
|
@@ -12078,7 +12190,7 @@ class MacroExpander {
|
|
|
12078
12190
|
this.pushToken(new Token("EOF", end.loc));
|
|
12079
12191
|
|
|
12080
12192
|
this.pushTokens(tokens);
|
|
12081
|
-
return
|
|
12193
|
+
return new Token("", SourceLocation.range(start, end));
|
|
12082
12194
|
}
|
|
12083
12195
|
|
|
12084
12196
|
/**
|
|
@@ -13034,7 +13146,7 @@ class Parser {
|
|
|
13034
13146
|
* Parses an "expression", which is a list of atoms.
|
|
13035
13147
|
*
|
|
13036
13148
|
* `breakOnInfix`: Should the parsing stop when we hit infix nodes? This
|
|
13037
|
-
* happens when functions have higher precedence
|
|
13149
|
+
* happens when functions have higher precedence than infix
|
|
13038
13150
|
* nodes in implicit parses.
|
|
13039
13151
|
*
|
|
13040
13152
|
* `breakOnTokenText`: The text of the token that the expression should end
|
|
@@ -13642,7 +13754,7 @@ class Parser {
|
|
|
13642
13754
|
) {
|
|
13643
13755
|
const firstToken = this.fetch();
|
|
13644
13756
|
const text = firstToken.text;
|
|
13645
|
-
|
|
13757
|
+
if (name === "argument to '\\left'") { return this.parseSymbol() }
|
|
13646
13758
|
let result;
|
|
13647
13759
|
// Try to parse an open brace or \begingroup
|
|
13648
13760
|
if (text === "{" || text === "\\begingroup" || text === "\\toggle") {
|
|
@@ -13789,7 +13901,8 @@ class Parser {
|
|
|
13789
13901
|
let symbol;
|
|
13790
13902
|
if (symbols[this.mode][text]) {
|
|
13791
13903
|
let group = symbols[this.mode][text].group;
|
|
13792
|
-
if (group === "bin" &&
|
|
13904
|
+
if (group === "bin" &&
|
|
13905
|
+
(binLeftCancellers.includes(this.prevAtomType) || this.prevAtomType === "")) {
|
|
13793
13906
|
// Change from a binary operator to a unary (prefix) operator
|
|
13794
13907
|
group = "open";
|
|
13795
13908
|
}
|
|
@@ -13885,11 +13998,27 @@ const parseTree = function(toParse, settings) {
|
|
|
13885
13998
|
if (!(typeof toParse === "string" || toParse instanceof String)) {
|
|
13886
13999
|
throw new TypeError("Temml can only parse string typed expression")
|
|
13887
14000
|
}
|
|
13888
|
-
|
|
13889
|
-
|
|
13890
|
-
|
|
14001
|
+
let tree;
|
|
14002
|
+
let parser;
|
|
14003
|
+
try {
|
|
14004
|
+
parser = new Parser(toParse, settings);
|
|
14005
|
+
// Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
|
|
14006
|
+
delete parser.gullet.macros.current["\\df@tag"];
|
|
13891
14007
|
|
|
13892
|
-
|
|
14008
|
+
tree = parser.parse();
|
|
14009
|
+
} catch (error) {
|
|
14010
|
+
if (error.toString() === "ParseError: Unmatched delimiter") {
|
|
14011
|
+
// Abandon the attempt to wrap delimiter pairs in an <mrow>.
|
|
14012
|
+
// Try again, and put each delimiter into an <mo> element.
|
|
14013
|
+
settings.wrapDelimiterPairs = false;
|
|
14014
|
+
parser = new Parser(toParse, settings);
|
|
14015
|
+
// Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
|
|
14016
|
+
delete parser.gullet.macros.current["\\df@tag"];
|
|
14017
|
+
tree = parser.parse();
|
|
14018
|
+
} else {
|
|
14019
|
+
throw error;
|
|
14020
|
+
}
|
|
14021
|
+
}
|
|
13893
14022
|
|
|
13894
14023
|
// LaTeX ignores a \tag placed outside an AMS environment.
|
|
13895
14024
|
if (!(tree.length > 0 && tree[0].type && tree[0].type === "array" && tree[0].addEqnNum)) {
|
|
@@ -14066,7 +14195,7 @@ class Style {
|
|
|
14066
14195
|
* https://mit-license.org/
|
|
14067
14196
|
*/
|
|
14068
14197
|
|
|
14069
|
-
const version = "0.13.
|
|
14198
|
+
const version = "0.13.3";
|
|
14070
14199
|
|
|
14071
14200
|
function postProcess(block) {
|
|
14072
14201
|
const labelMap = {};
|