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