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