ed-mathml2tex 0.1.5 → 0.1.7
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 +411 -249
- package/lib/mathml2latex.browser.es.js +411 -249
- package/lib/mathml2latex.browser.umd.js +411 -249
- package/lib/mathml2latex.cjs.js +411 -249
- package/lib/mathml2latex.es.js +411 -249
- package/lib/mathml2latex.umd.js +411 -249
- package/package.json +1 -1
|
@@ -588,10 +588,10 @@
|
|
|
588
588
|
}
|
|
589
589
|
};
|
|
590
590
|
|
|
591
|
-
function getRender_joinSeparator(template, separator =
|
|
591
|
+
function getRender_joinSeparator(template, separator = "") {
|
|
592
592
|
return function (node, children) {
|
|
593
593
|
const parts = renderChildren(children);
|
|
594
|
-
return template.replace(
|
|
594
|
+
return template.replace("@content", parts.join(separator));
|
|
595
595
|
};
|
|
596
596
|
}
|
|
597
597
|
|
|
@@ -603,9 +603,11 @@
|
|
|
603
603
|
result = result.replace(/\\right\.\./g, "\\right."); // Loại bỏ dấu chấm trùng lặp
|
|
604
604
|
result = result.replace(/\.\s*\./g, "."); // Loại bỏ dấu chấm trùng lặp
|
|
605
605
|
|
|
606
|
-
if (
|
|
606
|
+
if (
|
|
607
|
+
mathmlHtml.includes("<munder>") &&
|
|
607
608
|
mathmlHtml.includes("<mo>→</mo>") &&
|
|
608
|
-
mathmlHtml.includes("<mrow/>")
|
|
609
|
+
mathmlHtml.includes("<mrow/>")
|
|
610
|
+
) {
|
|
609
611
|
if (result.includes("\\limits")) {
|
|
610
612
|
result = "\\underset{}{\\rightarrow}";
|
|
611
613
|
}
|
|
@@ -614,38 +616,71 @@
|
|
|
614
616
|
// Thêm xử lý cho các thẻ MathML khác
|
|
615
617
|
result = result
|
|
616
618
|
.replace(/∞/g, "\\infty") // Vô cực
|
|
617
|
-
.replace(/∑/g, "\\sum")
|
|
618
|
-
.replace(/∏/g, "\\prod")
|
|
619
|
-
.replace(/∫/g, "\\int");
|
|
619
|
+
.replace(/∑/g, "\\sum") // Tổng
|
|
620
|
+
.replace(/∏/g, "\\prod") // Tích
|
|
621
|
+
.replace(/∫/g, "\\int"); // Tích phân
|
|
620
622
|
|
|
621
623
|
return result;
|
|
622
624
|
}
|
|
623
625
|
|
|
624
626
|
function toLatex(result) {
|
|
625
627
|
// Xử lý binomial coefficients
|
|
626
|
-
result = result.replace(/\\left\(\\DELETE_BRACKET_L/g,
|
|
627
|
-
result = result.replace(/\\DELETE_BRACKET_R\\right\)/g,
|
|
628
|
-
result = result.replace(/\\DELETE_BRACKET_L/g,
|
|
629
|
-
result = result.replace(/\\DELETE_BRACKET_R/g,
|
|
628
|
+
result = result.replace(/\\left\(\\DELETE_BRACKET_L/g, "");
|
|
629
|
+
result = result.replace(/\\DELETE_BRACKET_R\\right\)/g, "");
|
|
630
|
+
result = result.replace(/\\DELETE_BRACKET_L/g, "");
|
|
631
|
+
result = result.replace(/\\DELETE_BRACKET_R/g, "");
|
|
630
632
|
|
|
631
633
|
// Xử lý các trường hợp mũi tên với giới hạn
|
|
632
634
|
result = result.replace(/→\\limits_{}/g, "\\underset{}{\\rightarrow}");
|
|
633
635
|
result = result.replace(/→\\limits_{(\s*)}/g, "\\underset{}{\\rightarrow}");
|
|
634
|
-
result = result.replace(
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
result = result.replace(
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
636
|
+
result = result.replace(
|
|
637
|
+
/\\rightarrow\\limits_{}/g,
|
|
638
|
+
"\\underset{}{\\rightarrow}"
|
|
639
|
+
);
|
|
640
|
+
result = result.replace(
|
|
641
|
+
/\\rightarrow\\limits_{(\s*)}/g,
|
|
642
|
+
"\\underset{}{\\rightarrow}"
|
|
643
|
+
);
|
|
644
|
+
|
|
645
|
+
result = result.replace(
|
|
646
|
+
/→\\limits_\{([^}]*)\}/g,
|
|
647
|
+
"\\underset{$1}{\\rightarrow}"
|
|
648
|
+
);
|
|
649
|
+
result = result.replace(
|
|
650
|
+
/\\rightarrow\\limits_\{([^}]*)\}/g,
|
|
651
|
+
"\\underset{$1}{\\rightarrow}"
|
|
652
|
+
);
|
|
653
|
+
|
|
654
|
+
result = result.replace(
|
|
655
|
+
/→\\limits_\{([^}]*)\}\^\{([^}]*)\}/g,
|
|
656
|
+
"\\overset{$2}{\\underset{$1}{\\rightarrow}}"
|
|
657
|
+
);
|
|
658
|
+
result = result.replace(
|
|
659
|
+
/\\rightarrow\\limits_\{([^}]*)\}\^\{([^}]*)\}/g,
|
|
660
|
+
"\\overset{$2}{\\underset{$1}{\\rightarrow}}"
|
|
661
|
+
);
|
|
642
662
|
|
|
643
663
|
// Xử lý vector và các ký hiệu đặc biệt
|
|
644
|
-
result = result.replace(
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
result = result.replace(
|
|
664
|
+
result = result.replace(
|
|
665
|
+
/([^{}\s]+)\^\{\\rightarrow\}/g,
|
|
666
|
+
"\\overrightarrow{$1}"
|
|
667
|
+
);
|
|
668
|
+
result = result.replace(
|
|
669
|
+
/\{([^{}]+)\}\^\{\\rightarrow\}/g,
|
|
670
|
+
"\\overrightarrow{$1}"
|
|
671
|
+
);
|
|
672
|
+
result = result.replace(
|
|
673
|
+
/([A-Za-z0-9]+)_\{([^{}]+)\}\^\{\\rightarrow\}/g,
|
|
674
|
+
"\\overrightarrow{$1_{$2}}"
|
|
675
|
+
);
|
|
676
|
+
result = result.replace(
|
|
677
|
+
/([A-Za-z0-9]+)_([0-9])\^\{\\rightarrow\}/g,
|
|
678
|
+
"\\overrightarrow{$1_$2}"
|
|
679
|
+
);
|
|
680
|
+
result = result.replace(
|
|
681
|
+
/(\([^()]+\))\^\{\\rightarrow\}/g,
|
|
682
|
+
"\\overrightarrow{$1}"
|
|
683
|
+
);
|
|
649
684
|
|
|
650
685
|
// Remove or comment out these lines in toLatex function
|
|
651
686
|
// Thêm xử lý các ký hiệu toán học phổ biến
|
|
@@ -673,7 +708,7 @@
|
|
|
673
708
|
// @see https://www.w3.org/TR/MathML3/chapter7.html
|
|
674
709
|
// Cải tiến parseLeaf để hỗ trợ thêm các ký hiệu
|
|
675
710
|
function parseLeaf(node) {
|
|
676
|
-
let r =
|
|
711
|
+
let r = "";
|
|
677
712
|
const nodeName = NodeTool.getNodeName(node);
|
|
678
713
|
|
|
679
714
|
if (nodeName === "mrow" && NodeTool.getNodeText(node).trim() === "") {
|
|
@@ -681,32 +716,32 @@
|
|
|
681
716
|
}
|
|
682
717
|
|
|
683
718
|
switch (nodeName) {
|
|
684
|
-
case
|
|
719
|
+
case "mi":
|
|
685
720
|
r = parseElementMi(node);
|
|
686
721
|
break;
|
|
687
|
-
case
|
|
722
|
+
case "mn":
|
|
688
723
|
r = parseElementMn(node);
|
|
689
724
|
break;
|
|
690
|
-
case
|
|
725
|
+
case "mo":
|
|
691
726
|
r = parseOperator(node);
|
|
692
727
|
break;
|
|
693
|
-
case
|
|
728
|
+
case "ms":
|
|
694
729
|
r = parseElementMs(node);
|
|
695
730
|
break;
|
|
696
|
-
case
|
|
731
|
+
case "mtext":
|
|
697
732
|
r = parseElementMtext(node);
|
|
698
733
|
break;
|
|
699
|
-
case
|
|
734
|
+
case "mglyph":
|
|
700
735
|
r = parseElementMglyph(node);
|
|
701
736
|
break;
|
|
702
|
-
case
|
|
703
|
-
r =
|
|
737
|
+
case "mprescripts":
|
|
738
|
+
r = "";
|
|
704
739
|
break;
|
|
705
|
-
case
|
|
740
|
+
case "mspace":
|
|
706
741
|
r = parseElementMspace();
|
|
707
742
|
break;
|
|
708
|
-
case
|
|
709
|
-
r =
|
|
743
|
+
case "none":
|
|
744
|
+
r = "\\:";
|
|
710
745
|
break;
|
|
711
746
|
default:
|
|
712
747
|
r = escapeSpecialChars(NodeTool.getNodeText(node).trim());
|
|
@@ -715,10 +750,10 @@
|
|
|
715
750
|
return r;
|
|
716
751
|
}
|
|
717
752
|
|
|
718
|
-
//
|
|
753
|
+
// --- PATCH by AI: Fix for set-builder notation and fraction output ---
|
|
754
|
+
// 1. Extend operatorMap and add π->\pi, |->\mid
|
|
719
755
|
function parseOperator(node) {
|
|
720
756
|
let it = NodeTool.getNodeText(node).trim();
|
|
721
|
-
|
|
722
757
|
const operatorMap = {
|
|
723
758
|
"→": " \\rightarrow ",
|
|
724
759
|
"←": " \\leftarrow ",
|
|
@@ -737,12 +772,14 @@
|
|
|
737
772
|
">": " > ",
|
|
738
773
|
"=": " = ",
|
|
739
774
|
",": ", ", // Dấu phẩy trong tập hợp
|
|
740
|
-
";": ";",
|
|
741
|
-
|
|
775
|
+
";": ";",
|
|
776
|
+
Ω: "\\Omega",
|
|
777
|
+
"|": " \\mid ", // PATCH: set-builder mid
|
|
778
|
+
π: " \\pi ", // PATCH: Greek letter
|
|
742
779
|
};
|
|
743
|
-
|
|
744
780
|
return operatorMap[it] || escapeSpecialChars(MathSymbol.parseOperator(it));
|
|
745
781
|
}
|
|
782
|
+
// --- END PATCH ---
|
|
746
783
|
|
|
747
784
|
// Math identifier
|
|
748
785
|
function parseElementMi(node) {
|
|
@@ -750,7 +787,7 @@
|
|
|
750
787
|
|
|
751
788
|
// Handle vectors (e.g. AB', AI)
|
|
752
789
|
if (it.includes("'")) {
|
|
753
|
-
return it;
|
|
790
|
+
return it; // Return as is to handle in mrow
|
|
754
791
|
}
|
|
755
792
|
|
|
756
793
|
// Handle subscripts (e.g. n₂)
|
|
@@ -774,27 +811,41 @@
|
|
|
774
811
|
function parseElementMs(node) {
|
|
775
812
|
const content = NodeTool.getNodeText(node).trimRight();
|
|
776
813
|
const it = escapeSpecialChars(content);
|
|
777
|
-
return ['"', it, '"'].join(
|
|
814
|
+
return ['"', it, '"'].join("");
|
|
778
815
|
}
|
|
779
816
|
|
|
780
817
|
// Math Text
|
|
781
818
|
function parseElementMtext(node) {
|
|
782
819
|
let content = NodeTool.getNodeText(node)
|
|
783
820
|
// Handle operators and spacing only
|
|
784
|
-
.replace(/\s*=\s*/g,
|
|
785
|
-
.replace(/\s*\.\s*/g,
|
|
821
|
+
.replace(/\s*=\s*/g, " = ")
|
|
822
|
+
.replace(/\s*\.\s*/g, " \\cdot ")
|
|
786
823
|
.trim();
|
|
787
824
|
|
|
825
|
+
const specialMTextMap = {
|
|
826
|
+
ℝ: "\\mathbb{R}",
|
|
827
|
+
ℤ: "\\mathbb{Z}",
|
|
828
|
+
ℕ: "\\mathbb{N}",
|
|
829
|
+
ℚ: "\\mathbb{Q}",
|
|
830
|
+
ℂ: "\\mathbb{C}",
|
|
831
|
+
"\\": "\\setminus ",
|
|
832
|
+
"|": "\\mid ",
|
|
833
|
+
" ": "",
|
|
834
|
+
};
|
|
835
|
+
if (specialMTextMap[content]) return specialMTextMap[content];
|
|
836
|
+
|
|
788
837
|
// Handle units with proper \mathrm formatting
|
|
789
|
-
if (content.includes(
|
|
838
|
+
if (content.includes("(") && content.includes(")")) {
|
|
790
839
|
const parts = content.split(/(\([^)]+\))/);
|
|
791
|
-
content = parts
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
840
|
+
content = parts
|
|
841
|
+
.map((part) => {
|
|
842
|
+
if (part.startsWith("(") && part.endsWith(")")) {
|
|
843
|
+
// Keep original characters in units
|
|
844
|
+
return `\\mathrm{${part}}`;
|
|
845
|
+
}
|
|
846
|
+
return part;
|
|
847
|
+
})
|
|
848
|
+
.join("");
|
|
798
849
|
}
|
|
799
850
|
|
|
800
851
|
return content;
|
|
@@ -802,84 +853,124 @@
|
|
|
802
853
|
|
|
803
854
|
// Math glyph (image)
|
|
804
855
|
function parseElementMglyph(node) {
|
|
805
|
-
const it = ['"', NodeTool.getAttr(node,
|
|
856
|
+
const it = ['"', NodeTool.getAttr(node, "alt", ""), '"'].join("");
|
|
806
857
|
return escapeSpecialChars(it);
|
|
807
858
|
}
|
|
808
859
|
|
|
809
860
|
// TODO need or not
|
|
810
861
|
function parseElementMspace(node) {
|
|
811
|
-
return
|
|
862
|
+
return "";
|
|
812
863
|
}
|
|
813
864
|
|
|
814
865
|
function escapeSpecialChars(text) {
|
|
866
|
+
// Don't escape pi, Greek, or just a-z0-9 or Unicode Greek, or empty
|
|
867
|
+
if (
|
|
868
|
+
/^\\?[a-zA-Z0-9]+$/.test(text) ||
|
|
869
|
+
/^\\(?:pi|alpha|beta|gamma|Omega)$/.test(text) ||
|
|
870
|
+
/^π$/.test(text) ||
|
|
871
|
+
!text
|
|
872
|
+
) {
|
|
873
|
+
return text;
|
|
874
|
+
}
|
|
875
|
+
// Otherwise escape only true reserved LaTeX
|
|
815
876
|
const specialChars = /\$|%|_|&|#|\{|\}/g;
|
|
816
|
-
text = text.replace(specialChars, char => `\\${char}`);
|
|
877
|
+
text = text.replace(specialChars, (char) => `\\${char}`);
|
|
817
878
|
return text;
|
|
818
879
|
}
|
|
819
880
|
|
|
820
|
-
|
|
821
881
|
function parseContainer(node, children) {
|
|
822
882
|
const render = getRender(node);
|
|
823
883
|
if (render) {
|
|
824
884
|
return render(node, children);
|
|
825
885
|
} else {
|
|
826
|
-
throw new Error(
|
|
886
|
+
throw new Error(
|
|
887
|
+
`Couldn't get render function for container node: ${NodeTool.getNodeName(
|
|
888
|
+
node
|
|
889
|
+
)}`
|
|
890
|
+
);
|
|
827
891
|
}
|
|
828
892
|
}
|
|
829
893
|
|
|
830
894
|
function renderChildren(children) {
|
|
831
895
|
const parts = [];
|
|
832
896
|
let lefts = [];
|
|
833
|
-
|
|
834
|
-
|
|
897
|
+
|
|
898
|
+
// PATCH: Special case for set-builder style: leading { ... trailing }
|
|
899
|
+
if (
|
|
900
|
+
children.length >= 3 &&
|
|
901
|
+
NodeTool.getNodeName(children[0]) === "mo" &&
|
|
902
|
+
NodeTool.getNodeText(children[0]).trim() === "{" &&
|
|
903
|
+
NodeTool.getNodeName(children[children.length - 1]) === "mo" &&
|
|
904
|
+
NodeTool.getNodeText(children[children.length - 1]).trim() === "}"
|
|
905
|
+
) {
|
|
906
|
+
// Render inner content
|
|
907
|
+
const innerContent = Array.prototype.slice
|
|
908
|
+
.call(children, 1, -1)
|
|
909
|
+
.map((child) => parse(child))
|
|
910
|
+
.join("");
|
|
911
|
+
return `\\left\\{${innerContent}\\right\\}`;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
Array.prototype.forEach.call(children, (node, idx) => {
|
|
915
|
+
// PATCH: Thin space between variables/numbers in mfrac numerator (k 2 π)
|
|
916
|
+
if (
|
|
917
|
+
NodeTool.getNodeName(node) === "mrow" &&
|
|
918
|
+
node.parentNode &&
|
|
919
|
+
NodeTool.getNodeName(node.parentNode) === "mfrac"
|
|
920
|
+
) {
|
|
921
|
+
const mrowKids = Array.from(NodeTool.getChildren(node));
|
|
922
|
+
if (
|
|
923
|
+
mrowKids.every((n) =>
|
|
924
|
+
["mi", "mn", "mo"].includes(NodeTool.getNodeName(n))
|
|
925
|
+
)
|
|
926
|
+
) {
|
|
927
|
+
// Only vars, nums, ops (possibly Greek); join with thin space
|
|
928
|
+
const str = mrowKids.map((k) => parse(k)).join("\\,");
|
|
929
|
+
parts.push(str);
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
// END PATCH
|
|
934
|
+
if (NodeTool.getNodeName(node) === "mo") {
|
|
835
935
|
const op = NodeTool.getNodeText(node).trim();
|
|
836
936
|
if (Brackets.contains(op)) {
|
|
837
|
-
let stretchy = NodeTool.getAttr(node,
|
|
838
|
-
stretchy = [
|
|
937
|
+
let stretchy = NodeTool.getAttr(node, "stretchy", "true");
|
|
938
|
+
stretchy = ["", "true"].indexOf(stretchy) > -1;
|
|
939
|
+
|
|
940
|
+
// Luôn escape dấu ngoặc nhọn cho LaTeX
|
|
941
|
+
let escapedOp = op;
|
|
942
|
+
if (op === "{" || op === "}") {
|
|
943
|
+
escapedOp = `\\${op}`;
|
|
944
|
+
}
|
|
839
945
|
|
|
840
946
|
if (Brackets.isRight(op)) {
|
|
841
947
|
const nearLeft = lefts[lefts.length - 1];
|
|
842
|
-
if (nearLeft) {
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
const isInPower = parentNode && (
|
|
850
|
-
NodeTool.getNodeName(parentNode) === 'msup' ||
|
|
851
|
-
(nextSibling && NodeTool.getNodeName(nextSibling) === 'msup') ||
|
|
852
|
-
(prevSibling && NodeTool.getNodeName(prevSibling) === 'msup')
|
|
853
|
-
);
|
|
854
|
-
|
|
855
|
-
if (isInPower) {
|
|
856
|
-
parts.push(op); // Không thêm \right cho ngoặc trong mũ
|
|
857
|
-
} else {
|
|
858
|
-
parts.push(op); // Chỉ thêm dấu ngoặc đơn giản
|
|
859
|
-
}
|
|
860
|
-
lefts.pop();
|
|
948
|
+
if (nearLeft && Brackets.isPair(nearLeft, op)) {
|
|
949
|
+
const parentNode = node.parentNode;
|
|
950
|
+
const isInPower =
|
|
951
|
+
parentNode && NodeTool.getNodeName(parentNode) === "msup";
|
|
952
|
+
|
|
953
|
+
if (stretchy && !isInPower) {
|
|
954
|
+
parts.push(`\\right${escapedOp}`); // Dùng escapedOp
|
|
861
955
|
} else {
|
|
862
|
-
parts.push(
|
|
956
|
+
parts.push(escapedOp); // Dùng escapedOp
|
|
863
957
|
}
|
|
958
|
+
lefts.pop();
|
|
864
959
|
} else {
|
|
865
|
-
parts.push(
|
|
960
|
+
parts.push(escapedOp); // Ngoặc phải không khớp
|
|
866
961
|
}
|
|
867
962
|
} else {
|
|
868
|
-
//
|
|
963
|
+
// Là ngoặc trái
|
|
869
964
|
const parentNode = node.parentNode;
|
|
870
|
-
const
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
);
|
|
876
|
-
|
|
877
|
-
if (isInPower) {
|
|
878
|
-
parts.push(op); // Không thêm \left cho ngoặc trong mũ
|
|
965
|
+
const isInPower =
|
|
966
|
+
parentNode && NodeTool.getNodeName(parentNode) === "msup";
|
|
967
|
+
|
|
968
|
+
if (stretchy && !isInPower) {
|
|
969
|
+
parts.push(`\\left${escapedOp}`); // Dùng escapedOp
|
|
879
970
|
} else {
|
|
880
|
-
parts.push(
|
|
971
|
+
parts.push(escapedOp); // Dùng escapedOp
|
|
881
972
|
}
|
|
882
|
-
lefts.push(op);
|
|
973
|
+
lefts.push(op); // Dùng `op` gốc để so sánh cặp
|
|
883
974
|
}
|
|
884
975
|
} else {
|
|
885
976
|
parts.push(parseOperator(node));
|
|
@@ -888,7 +979,6 @@
|
|
|
888
979
|
parts.push(parse(node));
|
|
889
980
|
}
|
|
890
981
|
});
|
|
891
|
-
|
|
892
982
|
lefts = undefined;
|
|
893
983
|
return parts;
|
|
894
984
|
}
|
|
@@ -898,41 +988,49 @@
|
|
|
898
988
|
const nodeName = NodeTool.getNodeName(node);
|
|
899
989
|
|
|
900
990
|
switch (nodeName) {
|
|
901
|
-
case
|
|
991
|
+
case "mrow":
|
|
902
992
|
render = function (node, children) {
|
|
903
993
|
const childrenArray = Array.from(children);
|
|
904
|
-
if (
|
|
905
|
-
|
|
906
|
-
NodeTool.getNodeName(childrenArray[
|
|
994
|
+
if (
|
|
995
|
+
childrenArray.length >= 2 &&
|
|
996
|
+
NodeTool.getNodeName(childrenArray[0]) === "mo" &&
|
|
997
|
+
NodeTool.getNodeName(childrenArray[childrenArray.length - 1]) === "mo"
|
|
998
|
+
) {
|
|
907
999
|
const firstOp = NodeTool.getNodeText(childrenArray[0]).trim();
|
|
908
|
-
const lastOp = NodeTool.getNodeText(
|
|
1000
|
+
const lastOp = NodeTool.getNodeText(
|
|
1001
|
+
childrenArray[childrenArray.length - 1]
|
|
1002
|
+
).trim();
|
|
909
1003
|
|
|
910
1004
|
// Xử lý đặc biệt cho dấu ngoặc nhọn chứa mtable
|
|
911
|
-
if (
|
|
912
|
-
|
|
1005
|
+
if (
|
|
1006
|
+
firstOp === "{" &&
|
|
1007
|
+
childrenArray.some(
|
|
1008
|
+
(child) => NodeTool.getNodeName(child) === "mtable"
|
|
1009
|
+
)
|
|
1010
|
+
) {
|
|
913
1011
|
const innerContent = childrenArray
|
|
914
1012
|
.slice(1, -1)
|
|
915
|
-
.map(child => parse(child))
|
|
916
|
-
.join(
|
|
1013
|
+
.map((child) => parse(child))
|
|
1014
|
+
.join("");
|
|
917
1015
|
return `\\left\\{${innerContent}\\right.`;
|
|
918
1016
|
}
|
|
919
1017
|
|
|
920
1018
|
// Xử lý cho trường hợp [a;b) và [a,b)
|
|
921
|
-
if (firstOp ===
|
|
1019
|
+
if (firstOp === "[" && lastOp === ")") {
|
|
922
1020
|
const innerContent = childrenArray
|
|
923
1021
|
.slice(1, -1)
|
|
924
|
-
.map(child => parse(child))
|
|
925
|
-
.join(
|
|
1022
|
+
.map((child) => parse(child))
|
|
1023
|
+
.join("");
|
|
926
1024
|
return `\\left[${innerContent}\\right)`;
|
|
927
1025
|
}
|
|
928
1026
|
|
|
929
1027
|
// Xử lý ngoặc nhọn bình thường
|
|
930
|
-
if (firstOp ===
|
|
1028
|
+
if (firstOp === "{" && lastOp === "}") {
|
|
931
1029
|
const innerContent = childrenArray
|
|
932
1030
|
.slice(1, -1)
|
|
933
|
-
.map(child => parse(child))
|
|
934
|
-
.join(
|
|
935
|
-
return `\\{${innerContent}\\}`;
|
|
1031
|
+
.map((child) => parse(child))
|
|
1032
|
+
.join("");
|
|
1033
|
+
return `\\left\\{${innerContent}\\right\\}`;
|
|
936
1034
|
}
|
|
937
1035
|
|
|
938
1036
|
// Bỏ qua nếu firstOp là rỗng (trường hợp <mo></mo>)
|
|
@@ -940,33 +1038,55 @@
|
|
|
940
1038
|
return getRender_joinSeparator("@content")(node, childrenArray);
|
|
941
1039
|
}
|
|
942
1040
|
|
|
1041
|
+
if (firstOp === "[" && lastOp === "]") {
|
|
1042
|
+
const innerContent = childrenArray
|
|
1043
|
+
.slice(1, -1)
|
|
1044
|
+
.map((child) => parse(child))
|
|
1045
|
+
.join("");
|
|
1046
|
+
return `[${innerContent}]`;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
943
1049
|
// Xử lý đặc biệt cho dấu ngoặc vuông chứa mtable
|
|
944
|
-
if (firstOp ===
|
|
1050
|
+
if (firstOp === "[") {
|
|
945
1051
|
const innerContent = childrenArray
|
|
946
1052
|
.slice(1, -1) // Bỏ dấu ngoặc mở và đóng
|
|
947
|
-
.map(child => {
|
|
1053
|
+
.map((child) => {
|
|
948
1054
|
const parsed = parse(child);
|
|
949
1055
|
// Nếu child là mtable, trả về nội dung đã được định dạng với \begin{array}{l} ... \end{array}
|
|
950
|
-
if (NodeTool.getNodeName(child) ===
|
|
951
|
-
const rows = Array.from(NodeTool.getChildren(child)).map(
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
1056
|
+
if (NodeTool.getNodeName(child) === "mtable") {
|
|
1057
|
+
const rows = Array.from(NodeTool.getChildren(child)).map(
|
|
1058
|
+
(row) => {
|
|
1059
|
+
const rowChildren = Array.from(NodeTool.getChildren(row));
|
|
1060
|
+
return rowChildren.map((cell) => parse(cell)).join("");
|
|
1061
|
+
}
|
|
1062
|
+
);
|
|
1063
|
+
return `\\begin{array}{l} ${rows.join(
|
|
1064
|
+
" \\\\ "
|
|
1065
|
+
)} \\end{array}`;
|
|
956
1066
|
}
|
|
957
1067
|
// Nếu child là mrow chứa mtable, xử lý tương tự
|
|
958
|
-
if (
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1068
|
+
if (
|
|
1069
|
+
NodeTool.getNodeName(child) === "mrow" &&
|
|
1070
|
+
Array.from(NodeTool.getChildren(child)).some(
|
|
1071
|
+
(c) => NodeTool.getNodeName(c) === "mtable"
|
|
1072
|
+
)
|
|
1073
|
+
) {
|
|
1074
|
+
const mtableChild = Array.from(
|
|
1075
|
+
NodeTool.getChildren(child)
|
|
1076
|
+
).find((c) => NodeTool.getNodeName(c) === "mtable");
|
|
1077
|
+
const rows = Array.from(
|
|
1078
|
+
NodeTool.getChildren(mtableChild)
|
|
1079
|
+
).map((row) => {
|
|
962
1080
|
const rowChildren = Array.from(NodeTool.getChildren(row));
|
|
963
|
-
return rowChildren.map(cell => parse(cell)).join(
|
|
1081
|
+
return rowChildren.map((cell) => parse(cell)).join("");
|
|
964
1082
|
});
|
|
965
|
-
return `\\begin{array}{l} ${rows.join(
|
|
1083
|
+
return `\\begin{array}{l} ${rows.join(
|
|
1084
|
+
" \\\\ "
|
|
1085
|
+
)} \\end{array}`;
|
|
966
1086
|
}
|
|
967
1087
|
return parsed;
|
|
968
1088
|
})
|
|
969
|
-
.join(
|
|
1089
|
+
.join("");
|
|
970
1090
|
|
|
971
1091
|
// Giữ nguyên dấu ngoặc vuông lớn
|
|
972
1092
|
return `\\left[${innerContent}\\right.`;
|
|
@@ -975,36 +1095,41 @@
|
|
|
975
1095
|
if (Brackets.isPair(firstOp, lastOp)) {
|
|
976
1096
|
const innerContent = childrenArray
|
|
977
1097
|
.slice(1, -1)
|
|
978
|
-
.map(child => parse(child))
|
|
979
|
-
.join(
|
|
1098
|
+
.map((child) => parse(child))
|
|
1099
|
+
.join("");
|
|
980
1100
|
return `\\left${firstOp}${innerContent}\\right${lastOp}`;
|
|
981
1101
|
}
|
|
982
1102
|
|
|
983
1103
|
// Giữ nguyên dấu ngoặc nhọn trong MathML
|
|
984
|
-
if (firstOp ===
|
|
1104
|
+
if (firstOp === "{" || lastOp === "}") {
|
|
985
1105
|
const innerContent = childrenArray
|
|
986
|
-
.slice(1, lastOp ===
|
|
987
|
-
.map(child => parse(child))
|
|
988
|
-
.join(
|
|
989
|
-
return `${firstOp ===
|
|
1106
|
+
.slice(1, lastOp === "}" ? -1 : undefined)
|
|
1107
|
+
.map((child) => parse(child))
|
|
1108
|
+
.join("");
|
|
1109
|
+
return `${firstOp === "{" ? "\\{" : ""}${innerContent}${
|
|
1110
|
+
lastOp === "}" ? "\\}" : ""
|
|
1111
|
+
}`;
|
|
990
1112
|
}
|
|
991
1113
|
}
|
|
992
1114
|
return getRender_joinSeparator("@content")(node, childrenArray);
|
|
993
1115
|
};
|
|
994
1116
|
break;
|
|
995
1117
|
|
|
996
|
-
case
|
|
1118
|
+
case "msub":
|
|
997
1119
|
render = function (node, children) {
|
|
998
1120
|
const childrenArray = Array.from(children);
|
|
999
|
-
if (!childrenArray || childrenArray.length < 2) return
|
|
1000
|
-
const base = parse(childrenArray[0]) ||
|
|
1121
|
+
if (!childrenArray || childrenArray.length < 2) return "";
|
|
1122
|
+
const base = parse(childrenArray[0]) || "";
|
|
1001
1123
|
const sub = childrenArray[1];
|
|
1002
1124
|
if (!sub) return base;
|
|
1003
1125
|
|
|
1004
|
-
if (
|
|
1126
|
+
if (
|
|
1127
|
+
NodeTool.getNodeName(sub) === "msub" &&
|
|
1005
1128
|
sub.firstChild &&
|
|
1006
|
-
NodeTool.getNodeName(sub.firstChild) ===
|
|
1007
|
-
(!NodeTool.getNodeText(sub.firstChild) ||
|
|
1129
|
+
NodeTool.getNodeName(sub.firstChild) === "mrow" &&
|
|
1130
|
+
(!NodeTool.getNodeText(sub.firstChild) ||
|
|
1131
|
+
NodeTool.getNodeText(sub.firstChild).trim() === "")
|
|
1132
|
+
) {
|
|
1008
1133
|
const lastChild = sub.lastChild;
|
|
1009
1134
|
return lastChild ? `${base}_${parse(lastChild)}` : base;
|
|
1010
1135
|
}
|
|
@@ -1012,52 +1137,57 @@
|
|
|
1012
1137
|
};
|
|
1013
1138
|
break;
|
|
1014
1139
|
|
|
1015
|
-
case
|
|
1140
|
+
case "msup":
|
|
1016
1141
|
render = function (node, children) {
|
|
1017
1142
|
const childrenArray = Array.from(children);
|
|
1018
|
-
if (!childrenArray || childrenArray.length < 2) return
|
|
1019
|
-
const base = parse(childrenArray[0]) ||
|
|
1020
|
-
const sup = parse(childrenArray[1]) ||
|
|
1143
|
+
if (!childrenArray || childrenArray.length < 2) return "";
|
|
1144
|
+
const base = parse(childrenArray[0]) || "";
|
|
1145
|
+
const sup = parse(childrenArray[1]) || "";
|
|
1021
1146
|
return `${base}^{${sup}}`;
|
|
1022
1147
|
};
|
|
1023
1148
|
break;
|
|
1024
1149
|
|
|
1025
|
-
case
|
|
1150
|
+
case "msubsup":
|
|
1026
1151
|
render = function (node, children) {
|
|
1027
1152
|
const childrenArray = Array.from(children);
|
|
1028
|
-
if (!childrenArray || childrenArray.length < 3) return
|
|
1153
|
+
if (!childrenArray || childrenArray.length < 3) return "";
|
|
1029
1154
|
const base = parse(childrenArray[0]);
|
|
1030
1155
|
const sub = parse(childrenArray[1]);
|
|
1031
1156
|
const sup = parse(childrenArray[2]);
|
|
1032
1157
|
|
|
1033
1158
|
const lastChild = childrenArray[0].lastElementChild;
|
|
1034
|
-
if (
|
|
1035
|
-
|
|
1159
|
+
if (
|
|
1160
|
+
lastChild &&
|
|
1161
|
+
NodeTool.getNodeName(lastChild) === "mo" &&
|
|
1162
|
+
NodeTool.getNodeText(lastChild).trim() === "|"
|
|
1163
|
+
) {
|
|
1036
1164
|
const content = Array.from(childrenArray[0].children)
|
|
1037
1165
|
.slice(0, -1)
|
|
1038
|
-
.map(child => parse(child))
|
|
1039
|
-
.join(
|
|
1166
|
+
.map((child) => parse(child))
|
|
1167
|
+
.join("");
|
|
1040
1168
|
return `\\left.${content}\\right|_{${sub}}^{${sup}}`;
|
|
1041
1169
|
}
|
|
1042
1170
|
return `${base}_{${sub}}^{${sup}}`;
|
|
1043
1171
|
};
|
|
1044
1172
|
break;
|
|
1045
1173
|
|
|
1046
|
-
case
|
|
1174
|
+
case "mover":
|
|
1047
1175
|
render = function (node, children) {
|
|
1048
1176
|
const childrenArray = Array.from(children);
|
|
1049
|
-
if (!childrenArray || childrenArray.length < 2) return
|
|
1050
|
-
const base = parse(childrenArray[0]) ||
|
|
1051
|
-
const over = parse(childrenArray[1]) ||
|
|
1052
|
-
const overText = NodeTool.getNodeText(childrenArray[1])?.trim() ||
|
|
1177
|
+
if (!childrenArray || childrenArray.length < 2) return "";
|
|
1178
|
+
const base = parse(childrenArray[0]) || "";
|
|
1179
|
+
const over = parse(childrenArray[1]) || "";
|
|
1180
|
+
const overText = NodeTool.getNodeText(childrenArray[1])?.trim() || "";
|
|
1053
1181
|
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1054
1182
|
|
|
1055
1183
|
// Handle biology notation (double overline)
|
|
1056
1184
|
if (overText === "¯") {
|
|
1057
1185
|
const parentNode = node.parentNode;
|
|
1058
1186
|
// Check if this is part of a double overline structure
|
|
1059
|
-
if (
|
|
1060
|
-
|
|
1187
|
+
if (
|
|
1188
|
+
NodeTool.getNodeName(parentNode) === "mover" &&
|
|
1189
|
+
NodeTool.getNodeText(parentNode.lastChild)?.trim() === "¯"
|
|
1190
|
+
) {
|
|
1061
1191
|
return `\\overline{${base}}`;
|
|
1062
1192
|
}
|
|
1063
1193
|
return `\\overline{${base}}`;
|
|
@@ -1069,55 +1199,68 @@
|
|
|
1069
1199
|
};
|
|
1070
1200
|
break;
|
|
1071
1201
|
|
|
1072
|
-
case
|
|
1202
|
+
case "munder":
|
|
1073
1203
|
render = function (node, children) {
|
|
1074
1204
|
const childrenArray = Array.from(children);
|
|
1075
|
-
if (!childrenArray || childrenArray.length < 2) return
|
|
1076
|
-
const base = parse(childrenArray[0]) ||
|
|
1077
|
-
const under = parse(childrenArray[1]) ||
|
|
1078
|
-
const isUnderAccent =
|
|
1205
|
+
if (!childrenArray || childrenArray.length < 2) return "";
|
|
1206
|
+
const base = parse(childrenArray[0]) || "";
|
|
1207
|
+
const under = parse(childrenArray[1]) || "";
|
|
1208
|
+
const isUnderAccent =
|
|
1209
|
+
NodeTool.getAttr(node, "accentunder", "false") === "true";
|
|
1079
1210
|
|
|
1080
1211
|
if (base === "∫") return `\\int_{${under}}`;
|
|
1081
1212
|
return `\\underset{${under}}{${base}}`;
|
|
1082
1213
|
};
|
|
1083
1214
|
break;
|
|
1084
1215
|
|
|
1085
|
-
case
|
|
1216
|
+
case "munderover":
|
|
1086
1217
|
render = function (node, children) {
|
|
1087
1218
|
const childrenArray = Array.from(children);
|
|
1088
|
-
if (!childrenArray || childrenArray.length < 3) return
|
|
1219
|
+
if (!childrenArray || childrenArray.length < 3) return "";
|
|
1089
1220
|
const base = parse(childrenArray[0]);
|
|
1090
1221
|
const under = parse(childrenArray[1]);
|
|
1091
1222
|
const over = parse(childrenArray[2]);
|
|
1092
1223
|
const baseText = NodeTool.getNodeText(childrenArray[0]).trim();
|
|
1093
1224
|
|
|
1094
|
-
|
|
1095
|
-
if (
|
|
1096
|
-
|
|
1097
|
-
|
|
1225
|
+
// Special handling for chemical reaction arrow
|
|
1226
|
+
if (
|
|
1227
|
+
baseText === "→" &&
|
|
1228
|
+
NodeTool.getNodeName(childrenArray[1]) === "msup"
|
|
1229
|
+
) {
|
|
1230
|
+
return `\\xrightarrow[${under}]{${over}}`;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
if (baseText === "∫") return `\\int_{${under}}^{${over}}`;
|
|
1234
|
+
if (baseText === "∑") return `\\sum_{${under}}^{${over}}`;
|
|
1235
|
+
if (baseText === "∏") return `\\prod_{${under}}^{${over}}`;
|
|
1236
|
+
if (baseText === "|") return `\\big|_{${under}}^{${over}}`;
|
|
1098
1237
|
return `${base}_{${under}}^{${over}}`;
|
|
1099
1238
|
};
|
|
1100
1239
|
break;
|
|
1101
1240
|
|
|
1102
|
-
case
|
|
1241
|
+
case "mmultiscripts":
|
|
1103
1242
|
render = function (node, children) {
|
|
1104
1243
|
const childrenArray = Array.from(children);
|
|
1105
|
-
if (!childrenArray || childrenArray.length < 1) return
|
|
1244
|
+
if (!childrenArray || childrenArray.length < 1) return "";
|
|
1106
1245
|
const base = parse(childrenArray[0]);
|
|
1107
|
-
let prescripts =
|
|
1108
|
-
let postscripts =
|
|
1246
|
+
let prescripts = "";
|
|
1247
|
+
let postscripts = "";
|
|
1109
1248
|
let i = 1;
|
|
1110
1249
|
|
|
1111
1250
|
while (i < childrenArray.length) {
|
|
1112
|
-
if (NodeTool.getNodeName(childrenArray[i]) ===
|
|
1251
|
+
if (NodeTool.getNodeName(childrenArray[i]) === "mprescripts") {
|
|
1113
1252
|
i++;
|
|
1114
1253
|
if (i + 1 < childrenArray.length) {
|
|
1115
|
-
prescripts = `_{${parse(childrenArray[i])}}^{${parse(
|
|
1254
|
+
prescripts = `_{${parse(childrenArray[i])}}^{${parse(
|
|
1255
|
+
childrenArray[i + 1]
|
|
1256
|
+
)}}`;
|
|
1116
1257
|
i += 2;
|
|
1117
1258
|
}
|
|
1118
1259
|
} else {
|
|
1119
1260
|
if (i + 1 < childrenArray.length) {
|
|
1120
|
-
postscripts += `_{${parse(childrenArray[i])}}^{${parse(
|
|
1261
|
+
postscripts += `_{${parse(childrenArray[i])}}^{${parse(
|
|
1262
|
+
childrenArray[i + 1]
|
|
1263
|
+
)}}`;
|
|
1121
1264
|
i += 2;
|
|
1122
1265
|
} else break;
|
|
1123
1266
|
}
|
|
@@ -1126,33 +1269,35 @@
|
|
|
1126
1269
|
};
|
|
1127
1270
|
break;
|
|
1128
1271
|
|
|
1129
|
-
case
|
|
1272
|
+
case "mlongdiv":
|
|
1130
1273
|
render = function (node, children) {
|
|
1131
1274
|
const childrenArray = Array.from(children);
|
|
1132
|
-
if (!childrenArray || childrenArray.length < 2) return
|
|
1133
|
-
return `\\longdiv{${parse(childrenArray[0])}}{${parse(
|
|
1275
|
+
if (!childrenArray || childrenArray.length < 2) return "";
|
|
1276
|
+
return `\\longdiv{${parse(childrenArray[0])}}{${parse(
|
|
1277
|
+
childrenArray[1]
|
|
1278
|
+
)}}`;
|
|
1134
1279
|
};
|
|
1135
1280
|
break;
|
|
1136
1281
|
|
|
1137
|
-
case
|
|
1282
|
+
case "mroot":
|
|
1138
1283
|
render = function (node, children) {
|
|
1139
1284
|
const childrenArray = Array.from(children);
|
|
1140
|
-
if (!childrenArray || childrenArray.length < 2) return
|
|
1285
|
+
if (!childrenArray || childrenArray.length < 2) return "";
|
|
1141
1286
|
const base = parse(childrenArray[0]);
|
|
1142
1287
|
const index = parse(childrenArray[1]);
|
|
1143
1288
|
return `\\sqrt[${index}]{${base}}`;
|
|
1144
1289
|
};
|
|
1145
1290
|
break;
|
|
1146
1291
|
|
|
1147
|
-
case
|
|
1292
|
+
case "msqrt":
|
|
1148
1293
|
render = function (node, children) {
|
|
1149
1294
|
const childrenArray = Array.from(children);
|
|
1150
|
-
const content = renderChildren(childrenArray).join(
|
|
1295
|
+
const content = renderChildren(childrenArray).join("");
|
|
1151
1296
|
return `\\sqrt{${content}}`;
|
|
1152
1297
|
};
|
|
1153
1298
|
break;
|
|
1154
1299
|
|
|
1155
|
-
case
|
|
1300
|
+
case "mtable":
|
|
1156
1301
|
render = function (node, children) {
|
|
1157
1302
|
const childrenArray = Array.from(children);
|
|
1158
1303
|
|
|
@@ -1160,7 +1305,7 @@
|
|
|
1160
1305
|
let isNestedTable = false;
|
|
1161
1306
|
let parent = node.parentNode;
|
|
1162
1307
|
while (parent) {
|
|
1163
|
-
if (NodeTool.getNodeName(parent) ===
|
|
1308
|
+
if (NodeTool.getNodeName(parent) === "mtable") {
|
|
1164
1309
|
isNestedTable = true;
|
|
1165
1310
|
break;
|
|
1166
1311
|
}
|
|
@@ -1168,25 +1313,27 @@
|
|
|
1168
1313
|
}
|
|
1169
1314
|
|
|
1170
1315
|
// Xử lý mỗi mtr như một hàng
|
|
1171
|
-
const rows = childrenArray.map(row => {
|
|
1316
|
+
const rows = childrenArray.map((row) => {
|
|
1172
1317
|
const rowChildren = Array.from(NodeTool.getChildren(row));
|
|
1173
|
-
return rowChildren.map(cell => parse(cell)).join(
|
|
1318
|
+
return rowChildren.map((cell) => parse(cell)).join("");
|
|
1174
1319
|
});
|
|
1175
1320
|
|
|
1176
1321
|
// Nếu là mtable con, chỉ trả về các hàng mà không bao bọc trong \begin{array}...\end{array}
|
|
1177
1322
|
if (isNestedTable) {
|
|
1178
|
-
return rows.join(
|
|
1323
|
+
return rows.join(" \\\\ ");
|
|
1179
1324
|
}
|
|
1180
1325
|
|
|
1181
1326
|
// Nếu mtable nằm trong mrow với dấu ngoặc vuông, sẽ được xử lý ở mrow
|
|
1182
1327
|
let isInsideSquareBrackets = false;
|
|
1183
1328
|
parent = node.parentNode;
|
|
1184
1329
|
while (parent) {
|
|
1185
|
-
if (NodeTool.getNodeName(parent) ===
|
|
1330
|
+
if (NodeTool.getNodeName(parent) === "mrow") {
|
|
1186
1331
|
const childrenOfParent = Array.from(NodeTool.getChildren(parent));
|
|
1187
|
-
if (
|
|
1188
|
-
|
|
1189
|
-
NodeTool.
|
|
1332
|
+
if (
|
|
1333
|
+
childrenOfParent.length >= 2 &&
|
|
1334
|
+
NodeTool.getNodeName(childrenOfParent[0]) === "mo" &&
|
|
1335
|
+
NodeTool.getNodeText(childrenOfParent[0]).trim() === "["
|
|
1336
|
+
) {
|
|
1190
1337
|
isInsideSquareBrackets = true;
|
|
1191
1338
|
break;
|
|
1192
1339
|
}
|
|
@@ -1195,151 +1342,166 @@
|
|
|
1195
1342
|
}
|
|
1196
1343
|
|
|
1197
1344
|
if (isInsideSquareBrackets) {
|
|
1198
|
-
return rows.join(
|
|
1345
|
+
return rows.join(" \\\\ ");
|
|
1199
1346
|
}
|
|
1200
1347
|
|
|
1201
1348
|
// Nếu là mtable chính, bao bọc trong \begin{array}...\end{array}
|
|
1202
|
-
const arrayContent = rows.join(
|
|
1349
|
+
const arrayContent = rows.join(" \\\\ ");
|
|
1203
1350
|
return `\\begin{array}{l} ${arrayContent} \\end{array}`;
|
|
1204
1351
|
};
|
|
1205
1352
|
break;
|
|
1206
1353
|
|
|
1207
|
-
case
|
|
1354
|
+
case "mtr":
|
|
1208
1355
|
render = getRender_joinSeparator("@content", " & ");
|
|
1209
1356
|
break;
|
|
1210
1357
|
|
|
1211
|
-
case
|
|
1358
|
+
case "mtd":
|
|
1212
1359
|
render = getRender_joinSeparator("@content");
|
|
1213
1360
|
break;
|
|
1214
1361
|
|
|
1215
|
-
case
|
|
1362
|
+
case "mfrac":
|
|
1216
1363
|
render = function (node, children) {
|
|
1217
1364
|
const childrenArray = Array.from(children);
|
|
1218
|
-
if (!childrenArray || childrenArray.length < 2) return
|
|
1365
|
+
if (!childrenArray || childrenArray.length < 2) return "";
|
|
1219
1366
|
const num = parse(childrenArray[0]);
|
|
1220
1367
|
const den = parse(childrenArray[1]);
|
|
1221
|
-
const linethickness = NodeTool.getAttr(node,
|
|
1222
|
-
if (linethickness ===
|
|
1368
|
+
const linethickness = NodeTool.getAttr(node, "linethickness", "medium");
|
|
1369
|
+
if (linethickness === "0") return `\\binom{${num}}{${den}}`;
|
|
1223
1370
|
return `\\frac{${num}}{${den}}`;
|
|
1224
1371
|
};
|
|
1225
1372
|
break;
|
|
1226
1373
|
|
|
1227
|
-
case
|
|
1374
|
+
case "mfenced":
|
|
1228
1375
|
render = function (node, children) {
|
|
1229
1376
|
const childrenArray = Array.from(children);
|
|
1230
|
-
const open = NodeTool.getAttr(node,
|
|
1231
|
-
const close = NodeTool.getAttr(node,
|
|
1232
|
-
const separators = NodeTool.getAttr(node,
|
|
1377
|
+
const open = NodeTool.getAttr(node, "open", "(");
|
|
1378
|
+
const close = NodeTool.getAttr(node, "close", ")");
|
|
1379
|
+
const separators = NodeTool.getAttr(node, "separators", ",").split("");
|
|
1233
1380
|
|
|
1234
1381
|
// Xử lý đặc biệt cho trường hợp dấu ngoặc đơn |
|
|
1235
|
-
if (open ===
|
|
1236
|
-
const content = childrenArray
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1382
|
+
if (open === "|") {
|
|
1383
|
+
const content = childrenArray
|
|
1384
|
+
.map((child) => {
|
|
1385
|
+
const parsed = parse(child);
|
|
1386
|
+
// Loại bỏ các dấu | thừa và các \left|, \right| không cần thiết
|
|
1387
|
+
return parsed
|
|
1388
|
+
.replace(/\\left\|/g, "")
|
|
1389
|
+
.replace(/\\right\|/g, "")
|
|
1390
|
+
.replace(/\\left\./g, "")
|
|
1391
|
+
.replace(/\|/g, "");
|
|
1392
|
+
})
|
|
1393
|
+
.join("");
|
|
1394
|
+
|
|
1246
1395
|
if (!close) {
|
|
1247
1396
|
return `\\left|${content}\\right|`;
|
|
1248
|
-
} else if (close ===
|
|
1397
|
+
} else if (close === "|") {
|
|
1249
1398
|
return `\\left|${content}\\right|`;
|
|
1250
1399
|
}
|
|
1251
1400
|
}
|
|
1252
1401
|
|
|
1253
1402
|
// Xử lý đặc biệt cho mfenced chứa mtable
|
|
1254
|
-
if (open ===
|
|
1403
|
+
if (open === "{" && !close) {
|
|
1255
1404
|
// Kiểm tra xem có phải là một phần của biểu thức mũ không
|
|
1256
|
-
const hasMtable = childrenArray.some(child => {
|
|
1405
|
+
const hasMtable = childrenArray.some((child) => {
|
|
1257
1406
|
// Kiểm tra trực tiếp mtable
|
|
1258
|
-
if (NodeTool.getNodeName(child) ===
|
|
1407
|
+
if (NodeTool.getNodeName(child) === "mtable") return true;
|
|
1259
1408
|
// Kiểm tra mtable trong mrow
|
|
1260
|
-
if (NodeTool.getNodeName(child) ===
|
|
1409
|
+
if (NodeTool.getNodeName(child) === "mrow") {
|
|
1261
1410
|
return Array.from(NodeTool.getChildren(child)).some(
|
|
1262
|
-
grandChild => NodeTool.getNodeName(grandChild) ===
|
|
1411
|
+
(grandChild) => NodeTool.getNodeName(grandChild) === "mtable"
|
|
1263
1412
|
);
|
|
1264
1413
|
}
|
|
1265
1414
|
return false;
|
|
1266
1415
|
});
|
|
1267
1416
|
|
|
1268
1417
|
if (hasMtable) {
|
|
1269
|
-
const content = childrenArray.map(child => parse(child)).join(
|
|
1418
|
+
const content = childrenArray.map((child) => parse(child)).join("");
|
|
1270
1419
|
return `\\left\\{${content}\\right.`;
|
|
1271
1420
|
}
|
|
1272
1421
|
}
|
|
1273
1422
|
|
|
1274
1423
|
// Xử lý cho trường hợp [a;b)
|
|
1275
|
-
if (open ===
|
|
1424
|
+
if (open === "[" && close === ")") {
|
|
1276
1425
|
const parts = [];
|
|
1277
1426
|
childrenArray.forEach((child, index) => {
|
|
1278
1427
|
parts.push(parse(child));
|
|
1279
|
-
if (
|
|
1428
|
+
if (
|
|
1429
|
+
index < childrenArray.length - 1 &&
|
|
1430
|
+
separators[index % separators.length]
|
|
1431
|
+
) {
|
|
1280
1432
|
parts.push(separators[index % separators.length]);
|
|
1281
1433
|
}
|
|
1282
1434
|
});
|
|
1283
|
-
return `\\left[${parts.join(
|
|
1435
|
+
return `\\left[${parts.join("")}\\right)`;
|
|
1284
1436
|
}
|
|
1285
1437
|
|
|
1286
1438
|
// Giữ nguyên xử lý cho các trường hợp khác
|
|
1287
1439
|
const parts = [];
|
|
1288
1440
|
childrenArray.forEach((child, index) => {
|
|
1289
1441
|
parts.push(parse(child));
|
|
1290
|
-
if (
|
|
1442
|
+
if (
|
|
1443
|
+
index < childrenArray.length - 1 &&
|
|
1444
|
+
separators[index % separators.length]
|
|
1445
|
+
) {
|
|
1291
1446
|
parts.push(separators[index % separators.length]);
|
|
1292
1447
|
}
|
|
1293
1448
|
});
|
|
1294
|
-
const content = parts.join(
|
|
1449
|
+
const content = parts.join("");
|
|
1295
1450
|
|
|
1296
|
-
if (open ===
|
|
1297
|
-
if (open ===
|
|
1451
|
+
if (open === "{" && close === "}") return `\\{${content}\\}`;
|
|
1452
|
+
if (open === "|" && close === "|") return `\\left|${content}\\right|`;
|
|
1298
1453
|
if (!close) return `\\left${open}${content}\\right.`;
|
|
1299
1454
|
if (!open) return `\\left.${content}\\right${close}`;
|
|
1300
1455
|
return `\\left${open}${content}\\right${close}`;
|
|
1301
1456
|
};
|
|
1302
1457
|
break;
|
|
1303
1458
|
|
|
1304
|
-
case
|
|
1459
|
+
case "menclose":
|
|
1305
1460
|
render = function (node, children) {
|
|
1306
1461
|
const childrenArray = Array.from(children);
|
|
1307
|
-
const notation = NodeTool.getAttr(node,
|
|
1308
|
-
const content = renderChildren(childrenArray).join(
|
|
1462
|
+
const notation = NodeTool.getAttr(node, "notation", "longdiv");
|
|
1463
|
+
const content = renderChildren(childrenArray).join("");
|
|
1309
1464
|
switch (notation) {
|
|
1310
|
-
case
|
|
1311
|
-
|
|
1312
|
-
case
|
|
1313
|
-
|
|
1465
|
+
case "box":
|
|
1466
|
+
return `\\boxed{${content}}`;
|
|
1467
|
+
case "circle":
|
|
1468
|
+
return `\\enclose{circle}{${content}}`;
|
|
1469
|
+
case "roundedbox":
|
|
1470
|
+
return `\\fbox{${content}}`;
|
|
1471
|
+
default:
|
|
1472
|
+
return content;
|
|
1314
1473
|
}
|
|
1315
1474
|
};
|
|
1316
1475
|
break;
|
|
1317
1476
|
|
|
1318
|
-
case
|
|
1319
|
-
case
|
|
1320
|
-
case
|
|
1321
|
-
case
|
|
1322
|
-
case
|
|
1477
|
+
case "mi":
|
|
1478
|
+
case "mn":
|
|
1479
|
+
case "mo":
|
|
1480
|
+
case "ms":
|
|
1481
|
+
case "mtext":
|
|
1323
1482
|
render = getRender_joinSeparator("@content");
|
|
1324
1483
|
break;
|
|
1325
1484
|
|
|
1326
|
-
case
|
|
1485
|
+
case "mphantom":
|
|
1327
1486
|
render = function (node, children) {
|
|
1328
1487
|
const childrenArray = Array.from(children);
|
|
1329
|
-
const content = renderChildren(childrenArray).join(
|
|
1488
|
+
const content = renderChildren(childrenArray).join("");
|
|
1330
1489
|
return `\\phantom{${content}}`;
|
|
1331
1490
|
};
|
|
1332
1491
|
break;
|
|
1333
1492
|
|
|
1334
|
-
case
|
|
1493
|
+
case "mstyle":
|
|
1335
1494
|
render = function (node, children) {
|
|
1336
1495
|
const childrenArray = Array.from(children);
|
|
1337
|
-
const mathsize = NodeTool.getAttr(node,
|
|
1338
|
-
const content = renderChildren(childrenArray).join(
|
|
1496
|
+
const mathsize = NodeTool.getAttr(node, "mathsize", "normal");
|
|
1497
|
+
const content = renderChildren(childrenArray).join("");
|
|
1339
1498
|
switch (mathsize) {
|
|
1340
|
-
case
|
|
1341
|
-
|
|
1342
|
-
|
|
1499
|
+
case "big":
|
|
1500
|
+
return `\\large{${content}}`;
|
|
1501
|
+
case "small":
|
|
1502
|
+
return `\\small{${content}}`;
|
|
1503
|
+
default:
|
|
1504
|
+
return content;
|
|
1343
1505
|
}
|
|
1344
1506
|
};
|
|
1345
1507
|
break;
|
|
@@ -1353,7 +1515,7 @@
|
|
|
1353
1515
|
|
|
1354
1516
|
// Export the convert function
|
|
1355
1517
|
var mathml2latex = {
|
|
1356
|
-
convert: convert
|
|
1518
|
+
convert: convert,
|
|
1357
1519
|
};
|
|
1358
1520
|
|
|
1359
1521
|
return mathml2latex;
|