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