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