ed-mathml2tex 0.2.2 → 0.2.4
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/lib/mathml2latex.browser.cjs.js +369 -227
- package/lib/mathml2latex.browser.es.js +369 -227
- package/lib/mathml2latex.browser.umd.js +369 -227
- package/lib/mathml2latex.cjs.js +360 -227
- package/lib/mathml2latex.es.js +358 -227
- package/lib/mathml2latex.umd.js +362 -231
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const Brackets = {
|
|
2
|
-
left: ['(', '[', '{', '|', '
|
|
3
|
-
right: [')', ']', '}', '|', '
|
|
2
|
+
left: ['(', '[', '{', '|', '\u2016', '\u27E8', '\u230A', '\u2308', '\u231C'],
|
|
3
|
+
right: [')', ']', '}', '|', '\u2016', '\u27E9', '\u230B', '\u2309', '\u231D'],
|
|
4
4
|
isPair: function(l, r){
|
|
5
5
|
const idx = this.left.indexOf(l);
|
|
6
6
|
return r === this.right[idx];
|
|
@@ -22,17 +22,17 @@ const Brackets = {
|
|
|
22
22
|
case '[':
|
|
23
23
|
case '|': r = `\\left${it}`;
|
|
24
24
|
break;
|
|
25
|
-
case '
|
|
25
|
+
case '\u2016': r = '\\left\\|';
|
|
26
26
|
break;
|
|
27
27
|
case '{': r = '\\left\\{';
|
|
28
28
|
break;
|
|
29
|
-
case '
|
|
29
|
+
case '\u27E8': r = '\\left\\langle ';
|
|
30
30
|
break;
|
|
31
|
-
case '
|
|
31
|
+
case '\u230A': r = '\\left\\lfloor ';
|
|
32
32
|
break;
|
|
33
|
-
case '
|
|
33
|
+
case '\u2308': r = '\\left\\lceil ';
|
|
34
34
|
break;
|
|
35
|
-
case '
|
|
35
|
+
case '\u231C': r = '\\left\\ulcorner ';
|
|
36
36
|
break;
|
|
37
37
|
}
|
|
38
38
|
return (stretchy ? r : r.replace('\\left', ''));
|
|
@@ -46,23 +46,36 @@ const Brackets = {
|
|
|
46
46
|
case ']':
|
|
47
47
|
case '|': r = `\\right${it}`;
|
|
48
48
|
break;
|
|
49
|
-
case '
|
|
49
|
+
case '\u2016': r = '\\right\\|';
|
|
50
50
|
break;
|
|
51
51
|
case '}': r = '\\right\\}';
|
|
52
52
|
break;
|
|
53
|
-
case '
|
|
53
|
+
case '\u27E9': r = ' \\right\\rangle';
|
|
54
54
|
break;
|
|
55
|
-
case '
|
|
55
|
+
case '\u230B': r = ' \\right\\rfloor';
|
|
56
56
|
break;
|
|
57
|
-
case '
|
|
57
|
+
case '\u2309': r = ' \\right\\rceil';
|
|
58
58
|
break;
|
|
59
|
-
case '
|
|
59
|
+
case '\u231D': r = ' \\right\\urcorner';
|
|
60
60
|
break;
|
|
61
61
|
}
|
|
62
62
|
return (stretchy ? r : r.replace('\\right', ''));
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
+
var _nodeResolve_empty = {};
|
|
67
|
+
|
|
68
|
+
var _nodeResolve_empty$1 = /*#__PURE__*/Object.freeze({
|
|
69
|
+
__proto__: null,
|
|
70
|
+
'default': _nodeResolve_empty
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
function getCjsExportFromNamespace (n) {
|
|
74
|
+
return n && n['default'] || n;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
var require$$0 = getCjsExportFromNamespace(_nodeResolve_empty$1);
|
|
78
|
+
|
|
66
79
|
/*
|
|
67
80
|
* Set up window for Node.js
|
|
68
81
|
*/
|
|
@@ -92,11 +105,17 @@ function canParseHTMLNatively () {
|
|
|
92
105
|
function createHTMLParser () {
|
|
93
106
|
const Parser = function () {};
|
|
94
107
|
|
|
95
|
-
|
|
96
|
-
|
|
108
|
+
const hasDocument =
|
|
109
|
+
typeof document !== 'undefined' &&
|
|
110
|
+
document &&
|
|
111
|
+
document.implementation &&
|
|
112
|
+
typeof document.implementation.createHTMLDocument === 'function';
|
|
113
|
+
|
|
114
|
+
if (hasDocument) {
|
|
115
|
+
if (typeof process !== 'undefined' && true && shouldUseActiveX()) {
|
|
97
116
|
Parser.prototype.parseFromString = function (string) {
|
|
98
117
|
const doc = new window.ActiveXObject('htmlfile');
|
|
99
|
-
doc.designMode = 'on';
|
|
118
|
+
doc.designMode = 'on';
|
|
100
119
|
doc.open();
|
|
101
120
|
doc.write(string);
|
|
102
121
|
doc.close();
|
|
@@ -113,11 +132,9 @@ function createHTMLParser () {
|
|
|
113
132
|
}
|
|
114
133
|
} else {
|
|
115
134
|
Parser.prototype.parseFromString = function (string) {
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
doc.close();
|
|
120
|
-
return doc
|
|
135
|
+
const domino = require$$0;
|
|
136
|
+
const window = domino.createWindow(string || '');
|
|
137
|
+
return window.document
|
|
121
138
|
};
|
|
122
139
|
}
|
|
123
140
|
return Parser
|
|
@@ -135,11 +152,54 @@ function shouldUseActiveX () {
|
|
|
135
152
|
|
|
136
153
|
const HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser();
|
|
137
154
|
|
|
155
|
+
function normalizeMathMLInput(input) {
|
|
156
|
+
let s = input == null ? '' : String(input);
|
|
157
|
+
|
|
158
|
+
if (s.includes('<math') && /\\[ntr"]/.test(s)) {
|
|
159
|
+
s = s
|
|
160
|
+
.replace(/\\r\\n/g, '\n')
|
|
161
|
+
.replace(/\\n/g, '\n')
|
|
162
|
+
.replace(/\\t/g, '\t')
|
|
163
|
+
.replace(/\\"/g, '"')
|
|
164
|
+
.replace(/\\'/g, "'");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
s = s.replace(/^\s*<\?xml[\s\S]*?\?>\s*/i, '');
|
|
168
|
+
|
|
169
|
+
s = s.replace(
|
|
170
|
+
/xmlns\s*=\s*(["'])\s*`?\s*(https?:\/\/www\.w3\.org\/1998\/Math\/MathML)\s*`?\s*\1/gi,
|
|
171
|
+
'xmlns="$2"'
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
s = s.replace(/xmlns\s*=\s*(["'])\s*`?\s*http:\/\/www\.w3\.org\/1998\/Math\/MathML\\`?\s*\1/gi, 'xmlns="http://www.w3.org/1998/Math/MathML"');
|
|
175
|
+
|
|
176
|
+
if (!/<math\b/i.test(s) && /<(msub|mrow|mi|mn|mo|mfrac|msup|msubsup|munder|mover|munderover|mtable)\b/i.test(s)) {
|
|
177
|
+
s = `<math xmlns="http://www.w3.org/1998/Math/MathML">${s}</math>`;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return s;
|
|
181
|
+
}
|
|
182
|
+
|
|
138
183
|
const NodeTool = {
|
|
139
184
|
parseMath: function(html) {
|
|
185
|
+
const normalized = normalizeMathMLInput(html);
|
|
140
186
|
const parser = new HTMLParser();
|
|
141
|
-
const doc = parser.parseFromString(
|
|
142
|
-
|
|
187
|
+
const doc = parser.parseFromString(normalized, 'text/html');
|
|
188
|
+
let math = doc && doc.querySelector ? doc.querySelector('math') : null;
|
|
189
|
+
|
|
190
|
+
if (!math) {
|
|
191
|
+
const match = normalized.match(/<math\b[\s\S]*?<\/math>/i);
|
|
192
|
+
if (match) {
|
|
193
|
+
const retryDoc = parser.parseFromString(match[0], 'text/html');
|
|
194
|
+
math = retryDoc && retryDoc.querySelector ? retryDoc.querySelector('math') : null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (!math) {
|
|
199
|
+
throw new Error('Invalid MathML: missing <math> root element');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return math;
|
|
143
203
|
},
|
|
144
204
|
getChildren: function(node) {
|
|
145
205
|
return node.children;
|
|
@@ -275,24 +335,24 @@ const MathSymbol = {
|
|
|
275
335
|
bigCommand: {
|
|
276
336
|
decimals: [8721, 8719, 8720, 10753, 10754, 10752, 8899, 8898, 10756, 10758, 8897, 8896, 8747, 8750, 8748, 8749, 10764, 8747],
|
|
277
337
|
scripts: [
|
|
278
|
-
"\\sum",
|
|
279
|
-
"\\prod",
|
|
280
|
-
"\\coprod",
|
|
281
|
-
"\\bigoplus",
|
|
282
|
-
"\\bigotimes",
|
|
283
|
-
"\\bigodot",
|
|
284
|
-
"\\bigcup",
|
|
285
|
-
"\\bigcap",
|
|
286
|
-
"\\biguplus",
|
|
287
|
-
"\\bigsqcup",
|
|
288
|
-
"\\bigvee",
|
|
289
|
-
"\\bigwedge",
|
|
290
|
-
"\\int",
|
|
291
|
-
"\\oint",
|
|
292
|
-
"\\iint",
|
|
293
|
-
"\\iiint",
|
|
294
|
-
"\\iiiint",
|
|
295
|
-
"\\idotsint",
|
|
338
|
+
"\\sum ",
|
|
339
|
+
"\\prod ",
|
|
340
|
+
"\\coprod ",
|
|
341
|
+
"\\bigoplus ",
|
|
342
|
+
"\\bigotimes ",
|
|
343
|
+
"\\bigodot ",
|
|
344
|
+
"\\bigcup ",
|
|
345
|
+
"\\bigcap ",
|
|
346
|
+
"\\biguplus ",
|
|
347
|
+
"\\bigsqcup ",
|
|
348
|
+
"\\bigvee ",
|
|
349
|
+
"\\bigwedge ",
|
|
350
|
+
"\\int ",
|
|
351
|
+
"\\oint ",
|
|
352
|
+
"\\iint ",
|
|
353
|
+
"\\iiint ",
|
|
354
|
+
"\\iiiint ",
|
|
355
|
+
"\\idotsint ",
|
|
296
356
|
]
|
|
297
357
|
},
|
|
298
358
|
|
|
@@ -610,9 +670,10 @@ function convert(mathmlHtml) {
|
|
|
610
670
|
// Thêm xử lý cho các thẻ MathML khác
|
|
611
671
|
result = result
|
|
612
672
|
.replace(/∞/g, "\\infty") // Vô cực
|
|
613
|
-
.replace(
|
|
614
|
-
|
|
615
|
-
|
|
673
|
+
.replace(/∫/g, " \\int "); // Tích phân
|
|
674
|
+
|
|
675
|
+
// Đảm bảo dấu cách sau các lệnh LaTeX quan trọng để tránh dính biến (vd: \intf -> \int f)
|
|
676
|
+
result = result.replace(/\\(int|sum|prod|cos|sin|tan|cot|lim(?!its)|log|ln)([a-zA-Z0-9])/g, "\\$1 $2");
|
|
616
677
|
|
|
617
678
|
return result;
|
|
618
679
|
}
|
|
@@ -758,20 +819,24 @@ function parseOperator(node) {
|
|
|
758
819
|
"±": " \\pm ",
|
|
759
820
|
"×": " \\times ",
|
|
760
821
|
"÷": " \\div ",
|
|
761
|
-
"∑": "
|
|
762
|
-
"∏": "
|
|
763
|
-
"∫": "\\int",
|
|
822
|
+
"∑": "\\sum ",
|
|
823
|
+
"∏": "\\prod ",
|
|
824
|
+
"∫": "\\int ",
|
|
764
825
|
"−": "-",
|
|
765
826
|
"≠": " \\neq ",
|
|
766
827
|
">": " > ",
|
|
767
828
|
"=": " = ",
|
|
829
|
+
"(": "(",
|
|
830
|
+
")": ")",
|
|
768
831
|
",": ", ", // Dấu phẩy trong tập hợp
|
|
769
832
|
";": ";",
|
|
770
833
|
Ω: "\\Omega",
|
|
771
834
|
"|": " \\mid ", // PATCH: set-builder mid
|
|
772
835
|
π: " \\pi ", // PATCH: Greek letter
|
|
836
|
+
"...": "\\dots",
|
|
773
837
|
};
|
|
774
|
-
|
|
838
|
+
const res = operatorMap[it] || escapeSpecialChars(MathSymbol.parseOperator(it));
|
|
839
|
+
return res;
|
|
775
840
|
}
|
|
776
841
|
// --- END PATCH ---
|
|
777
842
|
|
|
@@ -798,6 +863,20 @@ function parseElementMi(node) {
|
|
|
798
863
|
// Math Number
|
|
799
864
|
function parseElementMn(node) {
|
|
800
865
|
let it = NodeTool.getNodeText(node).trim();
|
|
866
|
+
// Loại bỏ các ký tự điều khiển hoặc khoảng trắng lạ
|
|
867
|
+
it = it.replace(/[\u0000-\u001F\u007F-\u009F\u00A0]/g, "");
|
|
868
|
+
|
|
869
|
+
// Danh sách các hàm toán học mở rộng
|
|
870
|
+
const mathFunctions = ["cos", "sin", "tan", "cot", "arccos", "arcsin", "arctan", "arccot", "log", "ln", "lim", "sinh", "cosh", "tanh", "sec", "csc"];
|
|
871
|
+
|
|
872
|
+
if (mathFunctions.some(fn => it.toLowerCase().includes(fn))) {
|
|
873
|
+
// Tìm hàm khớp chính xác nhất
|
|
874
|
+
for (const fn of mathFunctions) {
|
|
875
|
+
if (it.toLowerCase() === fn) {
|
|
876
|
+
return "\\" + fn + " ";
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
801
880
|
return escapeSpecialChars(it);
|
|
802
881
|
}
|
|
803
882
|
|
|
@@ -831,8 +910,8 @@ function parseElementMtext(node) {
|
|
|
831
910
|
// Nếu đã là lệnh LaTeX thì giữ nguyên
|
|
832
911
|
if (content.startsWith("\\")) return content;
|
|
833
912
|
|
|
834
|
-
// Bọc token chữ/số liền nhau bằng \text{...} (hóa học: Cu, OH, NaOH,
|
|
835
|
-
if (/^[A-Za-z][A-Za-z0-9]*$/.test(content)) {
|
|
913
|
+
// Bọc token chữ/số liền nhau bằng \text{...} (hóa học: Cu, OH, NaOH, ..., k times)
|
|
914
|
+
if (/^[A-Za-z][A-Za-z0-9\s]*$/.test(content)) {
|
|
836
915
|
return `\\text{${content}}`;
|
|
837
916
|
}
|
|
838
917
|
|
|
@@ -887,6 +966,22 @@ function escapeSpecialChars(text) {
|
|
|
887
966
|
return text;
|
|
888
967
|
}
|
|
889
968
|
|
|
969
|
+
function wrapBaseForScript(base) {
|
|
970
|
+
const t = (base ?? "").trim();
|
|
971
|
+
if (!t) return "";
|
|
972
|
+
if (t.startsWith("{") && t.endsWith("}")) return t;
|
|
973
|
+
if (/^\\[a-zA-Z]+$/.test(t)) return t;
|
|
974
|
+
const needsWrap =
|
|
975
|
+
t.includes("_") ||
|
|
976
|
+
t.includes("^") ||
|
|
977
|
+
/\s/.test(t) ||
|
|
978
|
+
t.startsWith("\\left") ||
|
|
979
|
+
t.startsWith("\\right") ||
|
|
980
|
+
/\\[a-zA-Z]+/.test(t) ||
|
|
981
|
+
/[{}]/.test(t);
|
|
982
|
+
return needsWrap ? `{${t}}` : t;
|
|
983
|
+
}
|
|
984
|
+
|
|
890
985
|
function parseContainer(node, children) {
|
|
891
986
|
const render = getRender(node);
|
|
892
987
|
if (render) {
|
|
@@ -905,22 +1000,6 @@ function renderChildren(children) {
|
|
|
905
1000
|
// lefts là mảng object: { op: "(", index: 5 }
|
|
906
1001
|
let lefts = [];
|
|
907
1002
|
|
|
908
|
-
if (
|
|
909
|
-
children.length >= 3 &&
|
|
910
|
-
NodeTool.getNodeName(children[0]) === "mo" &&
|
|
911
|
-
NodeTool.getNodeText(children[0]).trim() === "{" &&
|
|
912
|
-
NodeTool.getNodeName(children[children.length - 1]) === "mo" &&
|
|
913
|
-
NodeTool.getNodeText(children[children.length - 1]).trim() === "}"
|
|
914
|
-
) {
|
|
915
|
-
// Render inner content
|
|
916
|
-
const innerContent = Array.prototype.slice
|
|
917
|
-
.call(children, 1, -1)
|
|
918
|
-
.map((child) => parse(child))
|
|
919
|
-
.join(""); // Chỉ trả về nếu nội dung không rỗng
|
|
920
|
-
const result = `\\left\\{${innerContent}\\right\\}`;
|
|
921
|
-
return result;
|
|
922
|
-
}
|
|
923
|
-
|
|
924
1003
|
Array.prototype.forEach.call(children, (node, idx) => {
|
|
925
1004
|
// PATCH: Thin space between variables/numbers in mfrac numerator (k 2 π)
|
|
926
1005
|
if (
|
|
@@ -948,55 +1027,59 @@ function renderChildren(children) {
|
|
|
948
1027
|
if (Brackets.contains(op)) {
|
|
949
1028
|
let stretchy = NodeTool.getAttr(node, "stretchy", "true");
|
|
950
1029
|
stretchy = ["", "true"].indexOf(stretchy) > -1;
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
if (
|
|
954
|
-
|
|
1030
|
+
const parentNode = node.parentNode;
|
|
1031
|
+
const isInPower = parentNode && NodeTool.getNodeName(parentNode) === "msup";
|
|
1032
|
+
if (isInPower) {
|
|
1033
|
+
stretchy = false;
|
|
955
1034
|
}
|
|
956
1035
|
|
|
957
1036
|
if (Brackets.isRight(op)) {
|
|
958
1037
|
const nearLeftObj = lefts[lefts.length - 1];
|
|
959
|
-
if (nearLeftObj) {
|
|
960
|
-
const
|
|
961
|
-
const
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
parts.
|
|
1038
|
+
if (nearLeftObj && Brackets.isPair(nearLeftObj.op, op)) {
|
|
1039
|
+
const leftIdx = nearLeftObj.index;
|
|
1040
|
+
const leftRendered =
|
|
1041
|
+
typeof leftIdx === "number" ? String(parts[leftIdx] ?? "") : "";
|
|
1042
|
+
let rightRendered = Brackets.parseRight(op, stretchy);
|
|
1043
|
+
|
|
1044
|
+
const leftRenderedTrimmed = leftRendered.trim();
|
|
1045
|
+
const rightRenderedTrimmed = String(rightRendered).trim();
|
|
1046
|
+
|
|
1047
|
+
if (
|
|
1048
|
+
leftRenderedTrimmed.startsWith("\\left") &&
|
|
1049
|
+
!rightRenderedTrimmed.startsWith("\\right")
|
|
1050
|
+
) {
|
|
1051
|
+
parts[leftIdx] = leftRendered.replace("\\left", "");
|
|
1052
|
+
} else if (
|
|
1053
|
+
!leftRenderedTrimmed.startsWith("\\left") &&
|
|
1054
|
+
rightRenderedTrimmed.startsWith("\\right")
|
|
1055
|
+
) {
|
|
1056
|
+
rightRendered = String(rightRendered).replace("\\right", "");
|
|
973
1057
|
}
|
|
974
|
-
|
|
1058
|
+
|
|
1059
|
+
if (rightRendered) parts.push(rightRendered);
|
|
975
1060
|
lefts.pop();
|
|
1061
|
+
} else if (Brackets.isLeft(op)) {
|
|
1062
|
+
// If it's a Right bracket but doesn't match the current Left,
|
|
1063
|
+
// AND it is also a Left bracket (e.g. '|'), treat it as a new Left.
|
|
1064
|
+
const partToPush = Brackets.parseLeft(op, stretchy);
|
|
1065
|
+
if (partToPush) parts.push(partToPush);
|
|
1066
|
+
lefts.push({ op: op, index: parts.length - 1 });
|
|
976
1067
|
} else {
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1068
|
+
// Unmatched right bracket
|
|
1069
|
+
let rightRendered = Brackets.parseRight(op, stretchy);
|
|
1070
|
+
rightRendered = String(rightRendered).replace("\\right", "");
|
|
1071
|
+
if (rightRendered) parts.push(rightRendered);
|
|
981
1072
|
}
|
|
982
1073
|
} else {
|
|
983
|
-
//
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
let partToPush = "";
|
|
989
|
-
if (stretchy && !isInPower) {
|
|
990
|
-
partToPush = `\\left${escapedOp}`;
|
|
1074
|
+
// Must be Left bracket (or only Left)
|
|
1075
|
+
if (Brackets.isLeft(op)) {
|
|
1076
|
+
const partToPush = Brackets.parseLeft(op, stretchy);
|
|
1077
|
+
if (partToPush) parts.push(partToPush);
|
|
1078
|
+
lefts.push({ op: op, index: parts.length - 1 });
|
|
991
1079
|
} else {
|
|
992
|
-
|
|
1080
|
+
// Should not happen if Brackets.contains is correct
|
|
1081
|
+
if (op) parts.push(op);
|
|
993
1082
|
}
|
|
994
|
-
if (partToPush) {
|
|
995
|
-
// CHỈ PUSH NẾU KHÔNG RỖNG
|
|
996
|
-
parts.push(partToPush);
|
|
997
|
-
}
|
|
998
|
-
// Lưu vị trí token left vừa push để có thể xử lý nếu không có right
|
|
999
|
-
lefts.push({ op: op, index: parts.length - 1 });
|
|
1000
1083
|
}
|
|
1001
1084
|
} else {
|
|
1002
1085
|
const parsedOperator = parseOperator(node);
|
|
@@ -1005,45 +1088,6 @@ function renderChildren(children) {
|
|
|
1005
1088
|
parts.push(parsedOperator);
|
|
1006
1089
|
}
|
|
1007
1090
|
}
|
|
1008
|
-
|
|
1009
|
-
// --- START PATCH V6 (Giữ nguyên logic V5) ---
|
|
1010
|
-
} else if (NodeTool.getNodeName(node) === "msub") {
|
|
1011
|
-
const subChildren = Array.from(NodeTool.getChildren(node));
|
|
1012
|
-
if (
|
|
1013
|
-
subChildren.length === 2 &&
|
|
1014
|
-
NodeTool.getNodeName(subChildren[0]) === "mo" &&
|
|
1015
|
-
NodeTool.getNodeText(subChildren[0]).trim() === ")"
|
|
1016
|
-
) {
|
|
1017
|
-
// ĐÚNG LÀ NGOẠI LỆ
|
|
1018
|
-
|
|
1019
|
-
const sub = parse(subChildren[1]);
|
|
1020
|
-
// Mảng 'parts' lúc này "sạch" và là: ["\text{Cu}", "\left(", "\text{OH}"]
|
|
1021
|
-
const lastPart = parts.pop(); // lastPart = "\text{OH}"
|
|
1022
|
-
// Mảng 'parts' lúc này là: ["\text{Cu}", "\left("]
|
|
1023
|
-
for (let i = parts.length - 1; i >= 0; i--) {
|
|
1024
|
-
if (parts[i] && parts[i].trim() === "\\left(") {
|
|
1025
|
-
parts.splice(i, 1); // Xóa "\left("
|
|
1026
|
-
break;
|
|
1027
|
-
}
|
|
1028
|
-
_;
|
|
1029
|
-
} // Mảng 'parts' lúc này là: ["\text{Cu}"]
|
|
1030
|
-
|
|
1031
|
-
parts.push(`${lastPart}_{${sub}}`); // Push "\text{OH}_{2}"
|
|
1032
|
-
// Mảng 'parts' lúc này là: ["\text{Cu}", "\text{OH}_{2}"]
|
|
1033
|
-
|
|
1034
|
-
const nearLeftObj = lefts[lefts.length - 1];
|
|
1035
|
-
if (nearLeftObj) {
|
|
1036
|
-
lefts.pop();
|
|
1037
|
-
}
|
|
1038
|
-
} else {
|
|
1039
|
-
// <msub> bình thường
|
|
1040
|
-
const parsed = parse(node);
|
|
1041
|
-
if (parsed) {
|
|
1042
|
-
// CHỈ PUSH NẾU KHÔNG RỖNG
|
|
1043
|
-
parts.push(parsed);
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
// --- END PATCH V6 ---
|
|
1047
1091
|
} else {
|
|
1048
1092
|
// Các node khác như <mtext>, #text, v.v.
|
|
1049
1093
|
const parsed = parse(node);
|
|
@@ -1055,40 +1099,13 @@ function renderChildren(children) {
|
|
|
1055
1099
|
});
|
|
1056
1100
|
|
|
1057
1101
|
// Nếu còn lefts (ngoặc trái) chưa được đóng, chỉ chuyển '\leftX' thành 'X'
|
|
1058
|
-
//
|
|
1102
|
+
// để tránh sinh LaTeX không hợp lệ (\left mà không có \right)
|
|
1059
1103
|
if (lefts && lefts.length > 0) {
|
|
1060
|
-
const rightForLeft = (left) => {
|
|
1061
|
-
switch (left) {
|
|
1062
|
-
case "(":
|
|
1063
|
-
return ")";
|
|
1064
|
-
case "[":
|
|
1065
|
-
return "]";
|
|
1066
|
-
case "{":
|
|
1067
|
-
return "}";
|
|
1068
|
-
case "|":
|
|
1069
|
-
return "|";
|
|
1070
|
-
default:
|
|
1071
|
-
return ".";
|
|
1072
|
-
}
|
|
1073
|
-
};
|
|
1074
|
-
|
|
1075
1104
|
lefts.forEach((leftObj) => {
|
|
1076
1105
|
const idx = leftObj && leftObj.index;
|
|
1077
1106
|
if (typeof idx !== "number" || !parts[idx]) return;
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
const right = rightForLeft(left);
|
|
1081
|
-
|
|
1082
|
-
// Kiểm tra phần tử sau vị trí left có chứa \right hoặc ký tự đóng tương ứng hay không
|
|
1083
|
-
const tail = parts.slice(idx + 1).map(String).join(" ");
|
|
1084
|
-
const hasMatchingRight =
|
|
1085
|
-
(/\\right/.test(tail)) || (right !== "." && tail.indexOf(right) !== -1);
|
|
1086
|
-
|
|
1087
|
-
if (!hasMatchingRight) {
|
|
1088
|
-
// Không có đóng tương ứng: bỏ prefix '\left' để chỉ còn ký tự mở bình thường
|
|
1089
|
-
parts[idx] = String(parts[idx]).replace(/^\\left/, "");
|
|
1090
|
-
}
|
|
1091
|
-
// Nếu có đóng tương ứng thì giữ nguyên '\left...' để không sinh \right thừa
|
|
1107
|
+
// Use regex with whitespace support and global flag just in case
|
|
1108
|
+
parts[idx] = String(parts[idx]).replace(/\\left/g, "");
|
|
1092
1109
|
});
|
|
1093
1110
|
}
|
|
1094
1111
|
|
|
@@ -1096,6 +1113,44 @@ function renderChildren(children) {
|
|
|
1096
1113
|
return parts;
|
|
1097
1114
|
}
|
|
1098
1115
|
|
|
1116
|
+
function isLimitOperator(base) {
|
|
1117
|
+
const t = (base || "").trim();
|
|
1118
|
+
const ops = [
|
|
1119
|
+
"\\sum",
|
|
1120
|
+
"\\prod",
|
|
1121
|
+
"\\coprod",
|
|
1122
|
+
"\\int",
|
|
1123
|
+
"\\oint",
|
|
1124
|
+
"\\bigcap",
|
|
1125
|
+
"\\bigcup",
|
|
1126
|
+
"\\bigsqcup",
|
|
1127
|
+
"\\bigvee",
|
|
1128
|
+
"\\bigwedge",
|
|
1129
|
+
"\\bigodot",
|
|
1130
|
+
"\\bigotimes",
|
|
1131
|
+
"\\bigoplus",
|
|
1132
|
+
"\\biguplus",
|
|
1133
|
+
"\\lim",
|
|
1134
|
+
"\\max",
|
|
1135
|
+
"\\min",
|
|
1136
|
+
"\\sup",
|
|
1137
|
+
"\\inf",
|
|
1138
|
+
"\\det",
|
|
1139
|
+
"\\gcd",
|
|
1140
|
+
"\\Pr",
|
|
1141
|
+
"\\limsup",
|
|
1142
|
+
"\\liminf",
|
|
1143
|
+
];
|
|
1144
|
+
return ops.some(
|
|
1145
|
+
(op) =>
|
|
1146
|
+
t === op ||
|
|
1147
|
+
t.startsWith(op + " ") ||
|
|
1148
|
+
t.startsWith(op + "\\") ||
|
|
1149
|
+
t.startsWith(op + "^") ||
|
|
1150
|
+
t.startsWith(op + "_")
|
|
1151
|
+
);
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1099
1154
|
function getRender(node) {
|
|
1100
1155
|
let render = undefined;
|
|
1101
1156
|
const nodeName = NodeTool.getNodeName(node);
|
|
@@ -1244,9 +1299,11 @@ function getRender(node) {
|
|
|
1244
1299
|
NodeTool.getNodeText(sub.firstChild).trim() === "")
|
|
1245
1300
|
) {
|
|
1246
1301
|
const lastChild = sub.lastChild;
|
|
1247
|
-
return lastChild
|
|
1302
|
+
return lastChild
|
|
1303
|
+
? `${wrapBaseForScript(base)}_{${parse(lastChild)}}`
|
|
1304
|
+
: base;
|
|
1248
1305
|
}
|
|
1249
|
-
return `${base}_{${parse(sub)}}`;
|
|
1306
|
+
return `${wrapBaseForScript(base)}_{${parse(sub)}}`;
|
|
1250
1307
|
};
|
|
1251
1308
|
break;
|
|
1252
1309
|
|
|
@@ -1254,22 +1311,9 @@ function getRender(node) {
|
|
|
1254
1311
|
render = function (node, children) {
|
|
1255
1312
|
const childrenArray = Array.from(children);
|
|
1256
1313
|
if (!childrenArray || childrenArray.length < 2) return "";
|
|
1257
|
-
|
|
1258
|
-
const baseNode = childrenArray[0];
|
|
1259
|
-
let base = parse(baseNode) || "";
|
|
1260
|
-
if (NodeTool.getNodeName(baseNode) === "mo") {
|
|
1261
|
-
const op = NodeTool.getNodeText(baseNode).trim();
|
|
1262
|
-
if (Brackets.isRight(op)) {
|
|
1263
|
-
// Escape brace characters
|
|
1264
|
-
if (op === "}" || op === "{") {
|
|
1265
|
-
base = `\\right\\${op}`;
|
|
1266
|
-
} else {
|
|
1267
|
-
base = `\\right${op}`;
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1314
|
+
const base = parse(childrenArray[0]) || "";
|
|
1271
1315
|
const sup = parse(childrenArray[1]) || "";
|
|
1272
|
-
return `${base}^{${sup}}`;
|
|
1316
|
+
return `${wrapBaseForScript(base)}^{${sup}}`;
|
|
1273
1317
|
};
|
|
1274
1318
|
break;
|
|
1275
1319
|
|
|
@@ -1293,7 +1337,7 @@ function getRender(node) {
|
|
|
1293
1337
|
.join("");
|
|
1294
1338
|
return `\\left.${content}\\right|_{${sub}}^{${sup}}`;
|
|
1295
1339
|
}
|
|
1296
|
-
return `${base}_{${sub}}^{${sup}}`;
|
|
1340
|
+
return `${wrapBaseForScript(base)}_{${sub}}^{${sup}}`;
|
|
1297
1341
|
};
|
|
1298
1342
|
break;
|
|
1299
1343
|
|
|
@@ -1303,9 +1347,15 @@ function getRender(node) {
|
|
|
1303
1347
|
if (!childrenArray || childrenArray.length < 2) return "";
|
|
1304
1348
|
const base = parse(childrenArray[0]) || "";
|
|
1305
1349
|
const over = parse(childrenArray[1]) || "";
|
|
1306
|
-
const
|
|
1350
|
+
const overNode = childrenArray[1];
|
|
1351
|
+
const baseText = NodeTool.getNodeText(childrenArray[0])?.trim() || "";
|
|
1352
|
+
const overText = NodeTool.getNodeText(overNode)?.trim() || "";
|
|
1307
1353
|
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1308
1354
|
|
|
1355
|
+
// Handle arrows with extensible commands
|
|
1356
|
+
if (baseText === "→" || baseText === "⟶") return `\\xrightarrow{${over}}`;
|
|
1357
|
+
if (baseText === "←" || baseText === "⟵") return `\\xleftarrow{${over}}`;
|
|
1358
|
+
|
|
1309
1359
|
// Handle biology notation (double overline)
|
|
1310
1360
|
if (overText === "¯") {
|
|
1311
1361
|
const parentNode = node.parentNode;
|
|
@@ -1321,6 +1371,27 @@ function getRender(node) {
|
|
|
1321
1371
|
|
|
1322
1372
|
if (overText === "→" && isAccent) return `\\vec{${base}}`;
|
|
1323
1373
|
if (overText === "^" && isAccent) return `\\hat{${base}}`;
|
|
1374
|
+
if (overText === "\u23DE") return `\\overbrace{${base}}`;
|
|
1375
|
+
|
|
1376
|
+
// Check for nested overbrace (layer-2)
|
|
1377
|
+
if (NodeTool.getNodeName(overNode) === "mover") {
|
|
1378
|
+
const innerChildren = Array.from(NodeTool.getChildren(overNode));
|
|
1379
|
+
if (innerChildren.length >= 2) {
|
|
1380
|
+
const innerBaseText = NodeTool.getNodeText(innerChildren[0]).trim();
|
|
1381
|
+
if (innerBaseText === "\u23DE") {
|
|
1382
|
+
const label = parse(innerChildren[1]);
|
|
1383
|
+
return `\\overbrace{${base}}\\limits^{${label}}`;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
if (base.startsWith("\\overbrace") || base.startsWith("\\underbrace")) {
|
|
1389
|
+
return `${base}\\limits^{${over}}`;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
if (isLimitOperator(base)) {
|
|
1393
|
+
return `${base}\\limits^{${over}}`;
|
|
1394
|
+
}
|
|
1324
1395
|
return `\\overset{${over}}{${base}}`;
|
|
1325
1396
|
};
|
|
1326
1397
|
break;
|
|
@@ -1331,10 +1402,21 @@ function getRender(node) {
|
|
|
1331
1402
|
if (!childrenArray || childrenArray.length < 2) return "";
|
|
1332
1403
|
const base = parse(childrenArray[0]) || "";
|
|
1333
1404
|
const under = parse(childrenArray[1]) || "";
|
|
1405
|
+
const baseText = NodeTool.getNodeText(childrenArray[0])?.trim() || "";
|
|
1406
|
+
const underText = NodeTool.getNodeText(childrenArray[1])?.trim() || "";
|
|
1334
1407
|
const isUnderAccent =
|
|
1335
1408
|
NodeTool.getAttr(node, "accentunder", "false") === "true";
|
|
1336
1409
|
|
|
1410
|
+
// Handle arrows with extensible commands
|
|
1411
|
+
if (baseText === "→" || baseText === "⟶") return `\\xrightarrow[${under}]{}`;
|
|
1412
|
+
if (baseText === "←" || baseText === "⟵") return `\\xleftarrow[${under}]{}`;
|
|
1413
|
+
|
|
1337
1414
|
if (base === "∫") return `\\int_{${under}}`;
|
|
1415
|
+
if (underText === "\u23DF") return `\\underbrace{${base}}`;
|
|
1416
|
+
|
|
1417
|
+
if (isLimitOperator(base)) {
|
|
1418
|
+
return `${base}\\limits_{${under}}`;
|
|
1419
|
+
}
|
|
1338
1420
|
return `\\underset{${under}}{${base}}`;
|
|
1339
1421
|
};
|
|
1340
1422
|
break;
|
|
@@ -1348,19 +1430,19 @@ function getRender(node) {
|
|
|
1348
1430
|
const over = parse(childrenArray[2]);
|
|
1349
1431
|
const baseText = NodeTool.getNodeText(childrenArray[0]).trim();
|
|
1350
1432
|
|
|
1351
|
-
// Special handling for chemical reaction arrow
|
|
1352
|
-
if (
|
|
1353
|
-
|
|
1354
|
-
NodeTool.getNodeName(childrenArray[1]) === "msup"
|
|
1355
|
-
) {
|
|
1356
|
-
return `\\xrightarrow[${under}]{${over}}`;
|
|
1357
|
-
}
|
|
1433
|
+
// Special handling for chemical reaction arrow and other arrows
|
|
1434
|
+
if (baseText === "→" || baseText === "⟶") return `\\xrightarrow[${under}]{${over}}`;
|
|
1435
|
+
if (baseText === "←" || baseText === "⟵") return `\\xleftarrow[${under}]{${over}}`;
|
|
1358
1436
|
|
|
1359
1437
|
if (baseText === "∫") return `\\int_{${under}}^{${over}}`;
|
|
1360
1438
|
if (baseText === "∑") return `\\sum_{${under}}^{${over}}`;
|
|
1361
1439
|
if (baseText === "∏") return `\\prod_{${under}}^{${over}}`;
|
|
1362
1440
|
if (baseText === "|") return `\\big|_{${under}}^{${over}}`;
|
|
1363
|
-
|
|
1441
|
+
|
|
1442
|
+
if (isLimitOperator(base)) {
|
|
1443
|
+
return `${base}\\limits_{${under}}^{${over}}`;
|
|
1444
|
+
}
|
|
1445
|
+
return `\\underset{${under}}{\\overset{${over}}{${base}}}`;
|
|
1364
1446
|
};
|
|
1365
1447
|
break;
|
|
1366
1448
|
|
|
@@ -1368,30 +1450,56 @@ function getRender(node) {
|
|
|
1368
1450
|
render = function (node, children) {
|
|
1369
1451
|
const childrenArray = Array.from(children);
|
|
1370
1452
|
if (!childrenArray || childrenArray.length < 1) return "";
|
|
1371
|
-
const base = parse(childrenArray[0]);
|
|
1372
|
-
|
|
1373
|
-
|
|
1453
|
+
const base = parse(childrenArray[0]) || "";
|
|
1454
|
+
|
|
1455
|
+
const postSub = [];
|
|
1456
|
+
const postSup = [];
|
|
1457
|
+
const preSub = [];
|
|
1458
|
+
const preSup = [];
|
|
1459
|
+
|
|
1374
1460
|
let i = 1;
|
|
1461
|
+
let inPrescripts = false;
|
|
1375
1462
|
|
|
1376
1463
|
while (i < childrenArray.length) {
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1464
|
+
const name = NodeTool.getNodeName(childrenArray[i]);
|
|
1465
|
+
if (name === "mprescripts") {
|
|
1466
|
+
inPrescripts = true;
|
|
1467
|
+
i += 1;
|
|
1468
|
+
continue;
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
const subNode = childrenArray[i];
|
|
1472
|
+
const supNode = childrenArray[i + 1];
|
|
1473
|
+
if (!subNode || !supNode) break;
|
|
1474
|
+
|
|
1475
|
+
const sub = parse(subNode) || "";
|
|
1476
|
+
const sup = parse(supNode) || "";
|
|
1477
|
+
|
|
1478
|
+
if (inPrescripts) {
|
|
1479
|
+
if (sub) preSub.push(sub);
|
|
1480
|
+
if (sup) preSup.push(sup);
|
|
1385
1481
|
} else {
|
|
1386
|
-
if (
|
|
1387
|
-
|
|
1388
|
-
childrenArray[i + 1]
|
|
1389
|
-
)}}`;
|
|
1390
|
-
i += 2;
|
|
1391
|
-
} else break;
|
|
1482
|
+
if (sub) postSub.push(sub);
|
|
1483
|
+
if (sup) postSup.push(sup);
|
|
1392
1484
|
}
|
|
1485
|
+
|
|
1486
|
+
i += 2;
|
|
1393
1487
|
}
|
|
1394
|
-
|
|
1488
|
+
|
|
1489
|
+
const preSubStr = preSub.join(" ");
|
|
1490
|
+
const preSupStr = preSup.join(" ");
|
|
1491
|
+
const postSubStr = postSub.join(" ");
|
|
1492
|
+
const postSupStr = postSup.join(" ");
|
|
1493
|
+
|
|
1494
|
+
let pre = "";
|
|
1495
|
+
if (preSubStr) pre += `_{${preSubStr}}`;
|
|
1496
|
+
if (preSupStr) pre += `^{${preSupStr}}`;
|
|
1497
|
+
|
|
1498
|
+
let post = "";
|
|
1499
|
+
if (postSubStr) post += `_{${postSubStr}}`;
|
|
1500
|
+
if (postSupStr) post += `^{${postSupStr}}`;
|
|
1501
|
+
|
|
1502
|
+
return `${pre}${wrapBaseForScript(base)}${post}`;
|
|
1395
1503
|
};
|
|
1396
1504
|
break;
|
|
1397
1505
|
|
|
@@ -1492,7 +1600,28 @@ function getRender(node) {
|
|
|
1492
1600
|
const num = parse(childrenArray[0]);
|
|
1493
1601
|
const den = parse(childrenArray[1]);
|
|
1494
1602
|
const linethickness = NodeTool.getAttr(node, "linethickness", "medium");
|
|
1495
|
-
|
|
1603
|
+
const bevelled = NodeTool.getAttr(node, "bevelled", "false");
|
|
1604
|
+
|
|
1605
|
+
if (bevelled === "true") {
|
|
1606
|
+
return `{}^{${num}}/_{${den}}`;
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
if (["0", "0px"].indexOf(linethickness) > -1) {
|
|
1610
|
+
const prevNode = NodeTool.getPrevNode(node);
|
|
1611
|
+
const nextNode = NodeTool.getNextNode(node);
|
|
1612
|
+
if (
|
|
1613
|
+
prevNode &&
|
|
1614
|
+
NodeTool.getNodeName(prevNode) === "mo" &&
|
|
1615
|
+
NodeTool.getNodeText(prevNode).trim() === "(" &&
|
|
1616
|
+
nextNode &&
|
|
1617
|
+
NodeTool.getNodeName(nextNode) === "mo" &&
|
|
1618
|
+
NodeTool.getNodeText(nextNode).trim() === ")"
|
|
1619
|
+
) {
|
|
1620
|
+
return `\\DELETE_BRACKET_L\\binom{${num}}{${den}}\\DELETE_BRACKET_R`;
|
|
1621
|
+
}
|
|
1622
|
+
return `{}_{${den}}^{${num}}`;
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1496
1625
|
return `\\frac{${num}}{${den}}`;
|
|
1497
1626
|
};
|
|
1498
1627
|
break;
|
|
@@ -1502,7 +1631,10 @@ function getRender(node) {
|
|
|
1502
1631
|
const childrenArray = Array.from(children);
|
|
1503
1632
|
const open = NodeTool.getAttr(node, "open", "(");
|
|
1504
1633
|
const close = NodeTool.getAttr(node, "close", ")");
|
|
1505
|
-
const
|
|
1634
|
+
const separatorsStr = NodeTool.getAttr(node, "separators", ",");
|
|
1635
|
+
const separators = separatorsStr
|
|
1636
|
+
.split("")
|
|
1637
|
+
.filter((c) => c.trim().length === 1);
|
|
1506
1638
|
|
|
1507
1639
|
// Xử lý đặc biệt cho trường hợp dấu ngoặc đơn |
|
|
1508
1640
|
if (open === "|") {
|
|
@@ -1553,9 +1685,10 @@ function getRender(node) {
|
|
|
1553
1685
|
parts.push(parse(child));
|
|
1554
1686
|
if (
|
|
1555
1687
|
index < childrenArray.length - 1 &&
|
|
1556
|
-
separators
|
|
1688
|
+
separators.length > 0
|
|
1557
1689
|
) {
|
|
1558
|
-
|
|
1690
|
+
const sep = separators[index] ?? separators[separators.length - 1];
|
|
1691
|
+
if (sep) parts.push(sep);
|
|
1559
1692
|
}
|
|
1560
1693
|
});
|
|
1561
1694
|
return `\\left[${parts.join("")}\\right)`;
|
|
@@ -1567,18 +1700,20 @@ function getRender(node) {
|
|
|
1567
1700
|
parts.push(parse(child));
|
|
1568
1701
|
if (
|
|
1569
1702
|
index < childrenArray.length - 1 &&
|
|
1570
|
-
separators
|
|
1703
|
+
separators.length > 0
|
|
1571
1704
|
) {
|
|
1572
|
-
|
|
1705
|
+
const sep = separators[index] ?? separators[separators.length - 1];
|
|
1706
|
+
if (sep) parts.push(sep);
|
|
1573
1707
|
}
|
|
1574
1708
|
});
|
|
1575
1709
|
const content = parts.join("");
|
|
1576
1710
|
|
|
1577
1711
|
if (open === "{" && close === "}") return `\\{${content}\\}`;
|
|
1578
1712
|
if (open === "|" && close === "|") return `\\left|${content}\\right|`;
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
return
|
|
1713
|
+
const left = open ? Brackets.parseLeft(open) : "";
|
|
1714
|
+
const right = close ? Brackets.parseRight(close) : "";
|
|
1715
|
+
if (!close && open) return `${left}${content}\\right.`;
|
|
1716
|
+
return `${left}${content}${right}`;
|
|
1582
1717
|
};
|
|
1583
1718
|
break;
|
|
1584
1719
|
|
|
@@ -1604,10 +1739,17 @@ function getRender(node) {
|
|
|
1604
1739
|
case "mn":
|
|
1605
1740
|
case "mo":
|
|
1606
1741
|
case "ms":
|
|
1607
|
-
case "mtext":
|
|
1608
1742
|
render = getRender_joinSeparator("@content");
|
|
1609
1743
|
break;
|
|
1610
1744
|
|
|
1745
|
+
case "mtext":
|
|
1746
|
+
render = function (node, children) {
|
|
1747
|
+
const childrenArray = Array.from(children);
|
|
1748
|
+
const content = renderChildren(childrenArray).join("");
|
|
1749
|
+
return `\\text{${content}}`;
|
|
1750
|
+
};
|
|
1751
|
+
break;
|
|
1752
|
+
|
|
1611
1753
|
case "mphantom":
|
|
1612
1754
|
render = function (node, children) {
|
|
1613
1755
|
const childrenArray = Array.from(children);
|