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
|
@@ -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
|
+
// Luôn escape dấu ngoặc nhọn cho LaTeX
|
|
937
|
+
let escapedOp = op;
|
|
938
|
+
if (op === "{" || op === "}") {
|
|
939
|
+
escapedOp = `\\${op}`;
|
|
940
|
+
}
|
|
835
941
|
|
|
836
942
|
if (Brackets.isRight(op)) {
|
|
837
943
|
const nearLeft = lefts[lefts.length - 1];
|
|
838
|
-
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();
|
|
944
|
+
if (nearLeft && Brackets.isPair(nearLeft, op)) {
|
|
945
|
+
const parentNode = node.parentNode;
|
|
946
|
+
const isInPower =
|
|
947
|
+
parentNode && NodeTool.getNodeName(parentNode) === "msup";
|
|
948
|
+
|
|
949
|
+
if (stretchy && !isInPower) {
|
|
950
|
+
parts.push(`\\right${escapedOp}`); // Dùng escapedOp
|
|
857
951
|
} else {
|
|
858
|
-
parts.push(
|
|
952
|
+
parts.push(escapedOp); // Dùng escapedOp
|
|
859
953
|
}
|
|
954
|
+
lefts.pop();
|
|
860
955
|
} else {
|
|
861
|
-
parts.push(
|
|
956
|
+
parts.push(escapedOp); // Ngoặc phải không khớp
|
|
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}`); // Dùng escapedOp
|
|
875
966
|
} else {
|
|
876
|
-
parts.push(
|
|
967
|
+
parts.push(escapedOp); // Dùng escapedOp
|
|
877
968
|
}
|
|
878
|
-
lefts.push(op);
|
|
969
|
+
lefts.push(op); // Dùng `op` gốc để so sánh cặp
|
|
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,33 +1034,55 @@ function getRender(node) {
|
|
|
936
1034
|
return getRender_joinSeparator("@content")(node, childrenArray);
|
|
937
1035
|
}
|
|
938
1036
|
|
|
1037
|
+
if (firstOp === "[" && lastOp === "]") {
|
|
1038
|
+
const innerContent = childrenArray
|
|
1039
|
+
.slice(1, -1)
|
|
1040
|
+
.map((child) => parse(child))
|
|
1041
|
+
.join("");
|
|
1042
|
+
return `[${innerContent}]`;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
939
1045
|
// Xử lý đặc biệt cho dấu ngoặc vuông chứa mtable
|
|
940
|
-
if (firstOp ===
|
|
1046
|
+
if (firstOp === "[") {
|
|
941
1047
|
const innerContent = childrenArray
|
|
942
1048
|
.slice(1, -1) // Bỏ dấu ngoặc mở và đóng
|
|
943
|
-
.map(child => {
|
|
1049
|
+
.map((child) => {
|
|
944
1050
|
const parsed = parse(child);
|
|
945
1051
|
// Nếu child là mtable, trả về nội dung đã được định dạng với \begin{array}{l} ... \end{array}
|
|
946
|
-
if (NodeTool.getNodeName(child) ===
|
|
947
|
-
const rows = Array.from(NodeTool.getChildren(child)).map(
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
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}`;
|
|
952
1062
|
}
|
|
953
1063
|
// Nếu child là mrow chứa mtable, xử lý tương tự
|
|
954
|
-
if (
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
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) => {
|
|
958
1076
|
const rowChildren = Array.from(NodeTool.getChildren(row));
|
|
959
|
-
return rowChildren.map(cell => parse(cell)).join(
|
|
1077
|
+
return rowChildren.map((cell) => parse(cell)).join("");
|
|
960
1078
|
});
|
|
961
|
-
return `\\begin{array}{l} ${rows.join(
|
|
1079
|
+
return `\\begin{array}{l} ${rows.join(
|
|
1080
|
+
" \\\\ "
|
|
1081
|
+
)} \\end{array}`;
|
|
962
1082
|
}
|
|
963
1083
|
return parsed;
|
|
964
1084
|
})
|
|
965
|
-
.join(
|
|
1085
|
+
.join("");
|
|
966
1086
|
|
|
967
1087
|
// Giữ nguyên dấu ngoặc vuông lớn
|
|
968
1088
|
return `\\left[${innerContent}\\right.`;
|
|
@@ -971,36 +1091,41 @@ function getRender(node) {
|
|
|
971
1091
|
if (Brackets.isPair(firstOp, lastOp)) {
|
|
972
1092
|
const innerContent = childrenArray
|
|
973
1093
|
.slice(1, -1)
|
|
974
|
-
.map(child => parse(child))
|
|
975
|
-
.join(
|
|
1094
|
+
.map((child) => parse(child))
|
|
1095
|
+
.join("");
|
|
976
1096
|
return `\\left${firstOp}${innerContent}\\right${lastOp}`;
|
|
977
1097
|
}
|
|
978
1098
|
|
|
979
1099
|
// Giữ nguyên dấu ngoặc nhọn trong MathML
|
|
980
|
-
if (firstOp ===
|
|
1100
|
+
if (firstOp === "{" || lastOp === "}") {
|
|
981
1101
|
const innerContent = childrenArray
|
|
982
|
-
.slice(1, lastOp ===
|
|
983
|
-
.map(child => parse(child))
|
|
984
|
-
.join(
|
|
985
|
-
return `${firstOp ===
|
|
1102
|
+
.slice(1, lastOp === "}" ? -1 : undefined)
|
|
1103
|
+
.map((child) => parse(child))
|
|
1104
|
+
.join("");
|
|
1105
|
+
return `${firstOp === "{" ? "\\{" : ""}${innerContent}${
|
|
1106
|
+
lastOp === "}" ? "\\}" : ""
|
|
1107
|
+
}`;
|
|
986
1108
|
}
|
|
987
1109
|
}
|
|
988
1110
|
return getRender_joinSeparator("@content")(node, childrenArray);
|
|
989
1111
|
};
|
|
990
1112
|
break;
|
|
991
1113
|
|
|
992
|
-
case
|
|
1114
|
+
case "msub":
|
|
993
1115
|
render = function (node, children) {
|
|
994
1116
|
const childrenArray = Array.from(children);
|
|
995
|
-
if (!childrenArray || childrenArray.length < 2) return
|
|
996
|
-
const base = parse(childrenArray[0]) ||
|
|
1117
|
+
if (!childrenArray || childrenArray.length < 2) return "";
|
|
1118
|
+
const base = parse(childrenArray[0]) || "";
|
|
997
1119
|
const sub = childrenArray[1];
|
|
998
1120
|
if (!sub) return base;
|
|
999
1121
|
|
|
1000
|
-
if (
|
|
1122
|
+
if (
|
|
1123
|
+
NodeTool.getNodeName(sub) === "msub" &&
|
|
1001
1124
|
sub.firstChild &&
|
|
1002
|
-
NodeTool.getNodeName(sub.firstChild) ===
|
|
1003
|
-
(!NodeTool.getNodeText(sub.firstChild) ||
|
|
1125
|
+
NodeTool.getNodeName(sub.firstChild) === "mrow" &&
|
|
1126
|
+
(!NodeTool.getNodeText(sub.firstChild) ||
|
|
1127
|
+
NodeTool.getNodeText(sub.firstChild).trim() === "")
|
|
1128
|
+
) {
|
|
1004
1129
|
const lastChild = sub.lastChild;
|
|
1005
1130
|
return lastChild ? `${base}_${parse(lastChild)}` : base;
|
|
1006
1131
|
}
|
|
@@ -1008,52 +1133,57 @@ function getRender(node) {
|
|
|
1008
1133
|
};
|
|
1009
1134
|
break;
|
|
1010
1135
|
|
|
1011
|
-
case
|
|
1136
|
+
case "msup":
|
|
1012
1137
|
render = function (node, children) {
|
|
1013
1138
|
const childrenArray = Array.from(children);
|
|
1014
|
-
if (!childrenArray || childrenArray.length < 2) return
|
|
1015
|
-
const base = parse(childrenArray[0]) ||
|
|
1016
|
-
const sup = parse(childrenArray[1]) ||
|
|
1139
|
+
if (!childrenArray || childrenArray.length < 2) return "";
|
|
1140
|
+
const base = parse(childrenArray[0]) || "";
|
|
1141
|
+
const sup = parse(childrenArray[1]) || "";
|
|
1017
1142
|
return `${base}^{${sup}}`;
|
|
1018
1143
|
};
|
|
1019
1144
|
break;
|
|
1020
1145
|
|
|
1021
|
-
case
|
|
1146
|
+
case "msubsup":
|
|
1022
1147
|
render = function (node, children) {
|
|
1023
1148
|
const childrenArray = Array.from(children);
|
|
1024
|
-
if (!childrenArray || childrenArray.length < 3) return
|
|
1149
|
+
if (!childrenArray || childrenArray.length < 3) return "";
|
|
1025
1150
|
const base = parse(childrenArray[0]);
|
|
1026
1151
|
const sub = parse(childrenArray[1]);
|
|
1027
1152
|
const sup = parse(childrenArray[2]);
|
|
1028
1153
|
|
|
1029
1154
|
const lastChild = childrenArray[0].lastElementChild;
|
|
1030
|
-
if (
|
|
1031
|
-
|
|
1155
|
+
if (
|
|
1156
|
+
lastChild &&
|
|
1157
|
+
NodeTool.getNodeName(lastChild) === "mo" &&
|
|
1158
|
+
NodeTool.getNodeText(lastChild).trim() === "|"
|
|
1159
|
+
) {
|
|
1032
1160
|
const content = Array.from(childrenArray[0].children)
|
|
1033
1161
|
.slice(0, -1)
|
|
1034
|
-
.map(child => parse(child))
|
|
1035
|
-
.join(
|
|
1162
|
+
.map((child) => parse(child))
|
|
1163
|
+
.join("");
|
|
1036
1164
|
return `\\left.${content}\\right|_{${sub}}^{${sup}}`;
|
|
1037
1165
|
}
|
|
1038
1166
|
return `${base}_{${sub}}^{${sup}}`;
|
|
1039
1167
|
};
|
|
1040
1168
|
break;
|
|
1041
1169
|
|
|
1042
|
-
case
|
|
1170
|
+
case "mover":
|
|
1043
1171
|
render = function (node, children) {
|
|
1044
1172
|
const childrenArray = Array.from(children);
|
|
1045
|
-
if (!childrenArray || childrenArray.length < 2) return
|
|
1046
|
-
const base = parse(childrenArray[0]) ||
|
|
1047
|
-
const over = parse(childrenArray[1]) ||
|
|
1048
|
-
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() || "";
|
|
1049
1177
|
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1050
1178
|
|
|
1051
1179
|
// Handle biology notation (double overline)
|
|
1052
1180
|
if (overText === "¯") {
|
|
1053
1181
|
const parentNode = node.parentNode;
|
|
1054
1182
|
// Check if this is part of a double overline structure
|
|
1055
|
-
if (
|
|
1056
|
-
|
|
1183
|
+
if (
|
|
1184
|
+
NodeTool.getNodeName(parentNode) === "mover" &&
|
|
1185
|
+
NodeTool.getNodeText(parentNode.lastChild)?.trim() === "¯"
|
|
1186
|
+
) {
|
|
1057
1187
|
return `\\overline{${base}}`;
|
|
1058
1188
|
}
|
|
1059
1189
|
return `\\overline{${base}}`;
|
|
@@ -1065,55 +1195,68 @@ function getRender(node) {
|
|
|
1065
1195
|
};
|
|
1066
1196
|
break;
|
|
1067
1197
|
|
|
1068
|
-
case
|
|
1198
|
+
case "munder":
|
|
1069
1199
|
render = function (node, children) {
|
|
1070
1200
|
const childrenArray = Array.from(children);
|
|
1071
|
-
if (!childrenArray || childrenArray.length < 2) return
|
|
1072
|
-
const base = parse(childrenArray[0]) ||
|
|
1073
|
-
const under = parse(childrenArray[1]) ||
|
|
1074
|
-
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";
|
|
1075
1206
|
|
|
1076
1207
|
if (base === "∫") return `\\int_{${under}}`;
|
|
1077
1208
|
return `\\underset{${under}}{${base}}`;
|
|
1078
1209
|
};
|
|
1079
1210
|
break;
|
|
1080
1211
|
|
|
1081
|
-
case
|
|
1212
|
+
case "munderover":
|
|
1082
1213
|
render = function (node, children) {
|
|
1083
1214
|
const childrenArray = Array.from(children);
|
|
1084
|
-
if (!childrenArray || childrenArray.length < 3) return
|
|
1215
|
+
if (!childrenArray || childrenArray.length < 3) return "";
|
|
1085
1216
|
const base = parse(childrenArray[0]);
|
|
1086
1217
|
const under = parse(childrenArray[1]);
|
|
1087
1218
|
const over = parse(childrenArray[2]);
|
|
1088
1219
|
const baseText = NodeTool.getNodeText(childrenArray[0]).trim();
|
|
1089
1220
|
|
|
1090
|
-
|
|
1091
|
-
if (
|
|
1092
|
-
|
|
1093
|
-
|
|
1221
|
+
// Special handling for chemical reaction arrow
|
|
1222
|
+
if (
|
|
1223
|
+
baseText === "→" &&
|
|
1224
|
+
NodeTool.getNodeName(childrenArray[1]) === "msup"
|
|
1225
|
+
) {
|
|
1226
|
+
return `\\xrightarrow[${under}]{${over}}`;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
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}}`;
|
|
1094
1233
|
return `${base}_{${under}}^{${over}}`;
|
|
1095
1234
|
};
|
|
1096
1235
|
break;
|
|
1097
1236
|
|
|
1098
|
-
case
|
|
1237
|
+
case "mmultiscripts":
|
|
1099
1238
|
render = function (node, children) {
|
|
1100
1239
|
const childrenArray = Array.from(children);
|
|
1101
|
-
if (!childrenArray || childrenArray.length < 1) return
|
|
1240
|
+
if (!childrenArray || childrenArray.length < 1) return "";
|
|
1102
1241
|
const base = parse(childrenArray[0]);
|
|
1103
|
-
let prescripts =
|
|
1104
|
-
let postscripts =
|
|
1242
|
+
let prescripts = "";
|
|
1243
|
+
let postscripts = "";
|
|
1105
1244
|
let i = 1;
|
|
1106
1245
|
|
|
1107
1246
|
while (i < childrenArray.length) {
|
|
1108
|
-
if (NodeTool.getNodeName(childrenArray[i]) ===
|
|
1247
|
+
if (NodeTool.getNodeName(childrenArray[i]) === "mprescripts") {
|
|
1109
1248
|
i++;
|
|
1110
1249
|
if (i + 1 < childrenArray.length) {
|
|
1111
|
-
prescripts = `_{${parse(childrenArray[i])}}^{${parse(
|
|
1250
|
+
prescripts = `_{${parse(childrenArray[i])}}^{${parse(
|
|
1251
|
+
childrenArray[i + 1]
|
|
1252
|
+
)}}`;
|
|
1112
1253
|
i += 2;
|
|
1113
1254
|
}
|
|
1114
1255
|
} else {
|
|
1115
1256
|
if (i + 1 < childrenArray.length) {
|
|
1116
|
-
postscripts += `_{${parse(childrenArray[i])}}^{${parse(
|
|
1257
|
+
postscripts += `_{${parse(childrenArray[i])}}^{${parse(
|
|
1258
|
+
childrenArray[i + 1]
|
|
1259
|
+
)}}`;
|
|
1117
1260
|
i += 2;
|
|
1118
1261
|
} else break;
|
|
1119
1262
|
}
|
|
@@ -1122,33 +1265,35 @@ function getRender(node) {
|
|
|
1122
1265
|
};
|
|
1123
1266
|
break;
|
|
1124
1267
|
|
|
1125
|
-
case
|
|
1268
|
+
case "mlongdiv":
|
|
1126
1269
|
render = function (node, children) {
|
|
1127
1270
|
const childrenArray = Array.from(children);
|
|
1128
|
-
if (!childrenArray || childrenArray.length < 2) return
|
|
1129
|
-
return `\\longdiv{${parse(childrenArray[0])}}{${parse(
|
|
1271
|
+
if (!childrenArray || childrenArray.length < 2) return "";
|
|
1272
|
+
return `\\longdiv{${parse(childrenArray[0])}}{${parse(
|
|
1273
|
+
childrenArray[1]
|
|
1274
|
+
)}}`;
|
|
1130
1275
|
};
|
|
1131
1276
|
break;
|
|
1132
1277
|
|
|
1133
|
-
case
|
|
1278
|
+
case "mroot":
|
|
1134
1279
|
render = function (node, children) {
|
|
1135
1280
|
const childrenArray = Array.from(children);
|
|
1136
|
-
if (!childrenArray || childrenArray.length < 2) return
|
|
1281
|
+
if (!childrenArray || childrenArray.length < 2) return "";
|
|
1137
1282
|
const base = parse(childrenArray[0]);
|
|
1138
1283
|
const index = parse(childrenArray[1]);
|
|
1139
1284
|
return `\\sqrt[${index}]{${base}}`;
|
|
1140
1285
|
};
|
|
1141
1286
|
break;
|
|
1142
1287
|
|
|
1143
|
-
case
|
|
1288
|
+
case "msqrt":
|
|
1144
1289
|
render = function (node, children) {
|
|
1145
1290
|
const childrenArray = Array.from(children);
|
|
1146
|
-
const content = renderChildren(childrenArray).join(
|
|
1291
|
+
const content = renderChildren(childrenArray).join("");
|
|
1147
1292
|
return `\\sqrt{${content}}`;
|
|
1148
1293
|
};
|
|
1149
1294
|
break;
|
|
1150
1295
|
|
|
1151
|
-
case
|
|
1296
|
+
case "mtable":
|
|
1152
1297
|
render = function (node, children) {
|
|
1153
1298
|
const childrenArray = Array.from(children);
|
|
1154
1299
|
|
|
@@ -1156,7 +1301,7 @@ function getRender(node) {
|
|
|
1156
1301
|
let isNestedTable = false;
|
|
1157
1302
|
let parent = node.parentNode;
|
|
1158
1303
|
while (parent) {
|
|
1159
|
-
if (NodeTool.getNodeName(parent) ===
|
|
1304
|
+
if (NodeTool.getNodeName(parent) === "mtable") {
|
|
1160
1305
|
isNestedTable = true;
|
|
1161
1306
|
break;
|
|
1162
1307
|
}
|
|
@@ -1164,25 +1309,27 @@ function getRender(node) {
|
|
|
1164
1309
|
}
|
|
1165
1310
|
|
|
1166
1311
|
// Xử lý mỗi mtr như một hàng
|
|
1167
|
-
const rows = childrenArray.map(row => {
|
|
1312
|
+
const rows = childrenArray.map((row) => {
|
|
1168
1313
|
const rowChildren = Array.from(NodeTool.getChildren(row));
|
|
1169
|
-
return rowChildren.map(cell => parse(cell)).join(
|
|
1314
|
+
return rowChildren.map((cell) => parse(cell)).join("");
|
|
1170
1315
|
});
|
|
1171
1316
|
|
|
1172
1317
|
// Nếu là mtable con, chỉ trả về các hàng mà không bao bọc trong \begin{array}...\end{array}
|
|
1173
1318
|
if (isNestedTable) {
|
|
1174
|
-
return rows.join(
|
|
1319
|
+
return rows.join(" \\\\ ");
|
|
1175
1320
|
}
|
|
1176
1321
|
|
|
1177
1322
|
// Nếu mtable nằm trong mrow với dấu ngoặc vuông, sẽ được xử lý ở mrow
|
|
1178
1323
|
let isInsideSquareBrackets = false;
|
|
1179
1324
|
parent = node.parentNode;
|
|
1180
1325
|
while (parent) {
|
|
1181
|
-
if (NodeTool.getNodeName(parent) ===
|
|
1326
|
+
if (NodeTool.getNodeName(parent) === "mrow") {
|
|
1182
1327
|
const childrenOfParent = Array.from(NodeTool.getChildren(parent));
|
|
1183
|
-
if (
|
|
1184
|
-
|
|
1185
|
-
NodeTool.
|
|
1328
|
+
if (
|
|
1329
|
+
childrenOfParent.length >= 2 &&
|
|
1330
|
+
NodeTool.getNodeName(childrenOfParent[0]) === "mo" &&
|
|
1331
|
+
NodeTool.getNodeText(childrenOfParent[0]).trim() === "["
|
|
1332
|
+
) {
|
|
1186
1333
|
isInsideSquareBrackets = true;
|
|
1187
1334
|
break;
|
|
1188
1335
|
}
|
|
@@ -1191,151 +1338,166 @@ function getRender(node) {
|
|
|
1191
1338
|
}
|
|
1192
1339
|
|
|
1193
1340
|
if (isInsideSquareBrackets) {
|
|
1194
|
-
return rows.join(
|
|
1341
|
+
return rows.join(" \\\\ ");
|
|
1195
1342
|
}
|
|
1196
1343
|
|
|
1197
1344
|
// Nếu là mtable chính, bao bọc trong \begin{array}...\end{array}
|
|
1198
|
-
const arrayContent = rows.join(
|
|
1345
|
+
const arrayContent = rows.join(" \\\\ ");
|
|
1199
1346
|
return `\\begin{array}{l} ${arrayContent} \\end{array}`;
|
|
1200
1347
|
};
|
|
1201
1348
|
break;
|
|
1202
1349
|
|
|
1203
|
-
case
|
|
1350
|
+
case "mtr":
|
|
1204
1351
|
render = getRender_joinSeparator("@content", " & ");
|
|
1205
1352
|
break;
|
|
1206
1353
|
|
|
1207
|
-
case
|
|
1354
|
+
case "mtd":
|
|
1208
1355
|
render = getRender_joinSeparator("@content");
|
|
1209
1356
|
break;
|
|
1210
1357
|
|
|
1211
|
-
case
|
|
1358
|
+
case "mfrac":
|
|
1212
1359
|
render = function (node, children) {
|
|
1213
1360
|
const childrenArray = Array.from(children);
|
|
1214
|
-
if (!childrenArray || childrenArray.length < 2) return
|
|
1361
|
+
if (!childrenArray || childrenArray.length < 2) return "";
|
|
1215
1362
|
const num = parse(childrenArray[0]);
|
|
1216
1363
|
const den = parse(childrenArray[1]);
|
|
1217
|
-
const linethickness = NodeTool.getAttr(node,
|
|
1218
|
-
if (linethickness ===
|
|
1364
|
+
const linethickness = NodeTool.getAttr(node, "linethickness", "medium");
|
|
1365
|
+
if (linethickness === "0") return `\\binom{${num}}{${den}}`;
|
|
1219
1366
|
return `\\frac{${num}}{${den}}`;
|
|
1220
1367
|
};
|
|
1221
1368
|
break;
|
|
1222
1369
|
|
|
1223
|
-
case
|
|
1370
|
+
case "mfenced":
|
|
1224
1371
|
render = function (node, children) {
|
|
1225
1372
|
const childrenArray = Array.from(children);
|
|
1226
|
-
const open = NodeTool.getAttr(node,
|
|
1227
|
-
const close = NodeTool.getAttr(node,
|
|
1228
|
-
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("");
|
|
1229
1376
|
|
|
1230
1377
|
// Xử lý đặc biệt cho trường hợp dấu ngoặc đơn |
|
|
1231
|
-
if (open ===
|
|
1232
|
-
const content = childrenArray
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
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
|
+
|
|
1242
1391
|
if (!close) {
|
|
1243
1392
|
return `\\left|${content}\\right|`;
|
|
1244
|
-
} else if (close ===
|
|
1393
|
+
} else if (close === "|") {
|
|
1245
1394
|
return `\\left|${content}\\right|`;
|
|
1246
1395
|
}
|
|
1247
1396
|
}
|
|
1248
1397
|
|
|
1249
1398
|
// Xử lý đặc biệt cho mfenced chứa mtable
|
|
1250
|
-
if (open ===
|
|
1399
|
+
if (open === "{" && !close) {
|
|
1251
1400
|
// Kiểm tra xem có phải là một phần của biểu thức mũ không
|
|
1252
|
-
const hasMtable = childrenArray.some(child => {
|
|
1401
|
+
const hasMtable = childrenArray.some((child) => {
|
|
1253
1402
|
// Kiểm tra trực tiếp mtable
|
|
1254
|
-
if (NodeTool.getNodeName(child) ===
|
|
1403
|
+
if (NodeTool.getNodeName(child) === "mtable") return true;
|
|
1255
1404
|
// Kiểm tra mtable trong mrow
|
|
1256
|
-
if (NodeTool.getNodeName(child) ===
|
|
1405
|
+
if (NodeTool.getNodeName(child) === "mrow") {
|
|
1257
1406
|
return Array.from(NodeTool.getChildren(child)).some(
|
|
1258
|
-
grandChild => NodeTool.getNodeName(grandChild) ===
|
|
1407
|
+
(grandChild) => NodeTool.getNodeName(grandChild) === "mtable"
|
|
1259
1408
|
);
|
|
1260
1409
|
}
|
|
1261
1410
|
return false;
|
|
1262
1411
|
});
|
|
1263
1412
|
|
|
1264
1413
|
if (hasMtable) {
|
|
1265
|
-
const content = childrenArray.map(child => parse(child)).join(
|
|
1414
|
+
const content = childrenArray.map((child) => parse(child)).join("");
|
|
1266
1415
|
return `\\left\\{${content}\\right.`;
|
|
1267
1416
|
}
|
|
1268
1417
|
}
|
|
1269
1418
|
|
|
1270
1419
|
// Xử lý cho trường hợp [a;b)
|
|
1271
|
-
if (open ===
|
|
1420
|
+
if (open === "[" && close === ")") {
|
|
1272
1421
|
const parts = [];
|
|
1273
1422
|
childrenArray.forEach((child, index) => {
|
|
1274
1423
|
parts.push(parse(child));
|
|
1275
|
-
if (
|
|
1424
|
+
if (
|
|
1425
|
+
index < childrenArray.length - 1 &&
|
|
1426
|
+
separators[index % separators.length]
|
|
1427
|
+
) {
|
|
1276
1428
|
parts.push(separators[index % separators.length]);
|
|
1277
1429
|
}
|
|
1278
1430
|
});
|
|
1279
|
-
return `\\left[${parts.join(
|
|
1431
|
+
return `\\left[${parts.join("")}\\right)`;
|
|
1280
1432
|
}
|
|
1281
1433
|
|
|
1282
1434
|
// Giữ nguyên xử lý cho các trường hợp khác
|
|
1283
1435
|
const parts = [];
|
|
1284
1436
|
childrenArray.forEach((child, index) => {
|
|
1285
1437
|
parts.push(parse(child));
|
|
1286
|
-
if (
|
|
1438
|
+
if (
|
|
1439
|
+
index < childrenArray.length - 1 &&
|
|
1440
|
+
separators[index % separators.length]
|
|
1441
|
+
) {
|
|
1287
1442
|
parts.push(separators[index % separators.length]);
|
|
1288
1443
|
}
|
|
1289
1444
|
});
|
|
1290
|
-
const content = parts.join(
|
|
1445
|
+
const content = parts.join("");
|
|
1291
1446
|
|
|
1292
|
-
if (open ===
|
|
1293
|
-
if (open ===
|
|
1447
|
+
if (open === "{" && close === "}") return `\\{${content}\\}`;
|
|
1448
|
+
if (open === "|" && close === "|") return `\\left|${content}\\right|`;
|
|
1294
1449
|
if (!close) return `\\left${open}${content}\\right.`;
|
|
1295
1450
|
if (!open) return `\\left.${content}\\right${close}`;
|
|
1296
1451
|
return `\\left${open}${content}\\right${close}`;
|
|
1297
1452
|
};
|
|
1298
1453
|
break;
|
|
1299
1454
|
|
|
1300
|
-
case
|
|
1455
|
+
case "menclose":
|
|
1301
1456
|
render = function (node, children) {
|
|
1302
1457
|
const childrenArray = Array.from(children);
|
|
1303
|
-
const notation = NodeTool.getAttr(node,
|
|
1304
|
-
const content = renderChildren(childrenArray).join(
|
|
1458
|
+
const notation = NodeTool.getAttr(node, "notation", "longdiv");
|
|
1459
|
+
const content = renderChildren(childrenArray).join("");
|
|
1305
1460
|
switch (notation) {
|
|
1306
|
-
case
|
|
1307
|
-
|
|
1308
|
-
case
|
|
1309
|
-
|
|
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;
|
|
1310
1469
|
}
|
|
1311
1470
|
};
|
|
1312
1471
|
break;
|
|
1313
1472
|
|
|
1314
|
-
case
|
|
1315
|
-
case
|
|
1316
|
-
case
|
|
1317
|
-
case
|
|
1318
|
-
case
|
|
1473
|
+
case "mi":
|
|
1474
|
+
case "mn":
|
|
1475
|
+
case "mo":
|
|
1476
|
+
case "ms":
|
|
1477
|
+
case "mtext":
|
|
1319
1478
|
render = getRender_joinSeparator("@content");
|
|
1320
1479
|
break;
|
|
1321
1480
|
|
|
1322
|
-
case
|
|
1481
|
+
case "mphantom":
|
|
1323
1482
|
render = function (node, children) {
|
|
1324
1483
|
const childrenArray = Array.from(children);
|
|
1325
|
-
const content = renderChildren(childrenArray).join(
|
|
1484
|
+
const content = renderChildren(childrenArray).join("");
|
|
1326
1485
|
return `\\phantom{${content}}`;
|
|
1327
1486
|
};
|
|
1328
1487
|
break;
|
|
1329
1488
|
|
|
1330
|
-
case
|
|
1489
|
+
case "mstyle":
|
|
1331
1490
|
render = function (node, children) {
|
|
1332
1491
|
const childrenArray = Array.from(children);
|
|
1333
|
-
const mathsize = NodeTool.getAttr(node,
|
|
1334
|
-
const content = renderChildren(childrenArray).join(
|
|
1492
|
+
const mathsize = NodeTool.getAttr(node, "mathsize", "normal");
|
|
1493
|
+
const content = renderChildren(childrenArray).join("");
|
|
1335
1494
|
switch (mathsize) {
|
|
1336
|
-
case
|
|
1337
|
-
|
|
1338
|
-
|
|
1495
|
+
case "big":
|
|
1496
|
+
return `\\large{${content}}`;
|
|
1497
|
+
case "small":
|
|
1498
|
+
return `\\small{${content}}`;
|
|
1499
|
+
default:
|
|
1500
|
+
return content;
|
|
1339
1501
|
}
|
|
1340
1502
|
};
|
|
1341
1503
|
break;
|
|
@@ -1349,7 +1511,7 @@ function getRender(node) {
|
|
|
1349
1511
|
|
|
1350
1512
|
// Export the convert function
|
|
1351
1513
|
var mathml2latex = {
|
|
1352
|
-
convert: convert
|
|
1514
|
+
convert: convert,
|
|
1353
1515
|
};
|
|
1354
1516
|
|
|
1355
1517
|
module.exports = mathml2latex;
|