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