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