ed-mathml2tex 0.1.0 → 0.1.2
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 +481 -357
- package/lib/mathml2latex.browser.es.js +481 -357
- package/lib/mathml2latex.browser.umd.js +481 -357
- package/lib/mathml2latex.cjs.js +481 -357
- package/lib/mathml2latex.es.js +481 -357
- package/lib/mathml2latex.umd.js +481 -357
- package/package.json +1 -1
|
@@ -588,74 +588,75 @@
|
|
|
588
588
|
}
|
|
589
589
|
};
|
|
590
590
|
|
|
591
|
-
function getRender_default(template) {
|
|
592
|
-
return function(node, children) {
|
|
593
|
-
const parts = renderChildren(children);
|
|
594
|
-
return renderTemplate(template, parts);
|
|
595
|
-
};
|
|
596
|
-
}
|
|
597
|
-
|
|
598
591
|
function getRender_joinSeparator(template, separator = '') {
|
|
599
|
-
return function(node, children) {
|
|
592
|
+
return function (node, children) {
|
|
600
593
|
const parts = renderChildren(children);
|
|
601
594
|
return template.replace('@content', parts.join(separator));
|
|
602
595
|
};
|
|
603
596
|
}
|
|
604
597
|
|
|
605
|
-
function convert(mathmlHtml){
|
|
598
|
+
function convert(mathmlHtml) {
|
|
606
599
|
const math = NodeTool.parseMath(mathmlHtml);
|
|
607
600
|
let result = toLatex(parse(math));
|
|
608
|
-
|
|
609
|
-
//
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
601
|
+
|
|
602
|
+
// Xử lý sau cuối cho các mẫu đặc biệt
|
|
603
|
+
result = result.replace(/\\right\.\./g, "\\right."); // Loại bỏ dấu chấm trùng lặp
|
|
604
|
+
result = result.replace(/\.\s*\./g, "."); // Loại bỏ dấu chấm trùng lặp
|
|
605
|
+
|
|
606
|
+
if (mathmlHtml.includes("<munder>") &&
|
|
607
|
+
mathmlHtml.includes("<mo>→</mo>") &&
|
|
608
|
+
mathmlHtml.includes("<mrow/>")) {
|
|
613
609
|
if (result.includes("\\limits")) {
|
|
614
610
|
result = "\\underset{}{\\rightarrow}";
|
|
615
611
|
}
|
|
616
612
|
}
|
|
617
|
-
|
|
613
|
+
|
|
614
|
+
// Thêm xử lý cho các thẻ MathML khác
|
|
615
|
+
result = result
|
|
616
|
+
.replace(/∞/g, "\\infty") // Vô cực
|
|
617
|
+
.replace(/∑/g, "\\sum") // Tổng
|
|
618
|
+
.replace(/∏/g, "\\prod") // Tích
|
|
619
|
+
.replace(/∫/g, "\\int"); // Tích phân
|
|
620
|
+
|
|
618
621
|
return result;
|
|
619
622
|
}
|
|
620
623
|
|
|
621
624
|
function toLatex(result) {
|
|
622
|
-
// binomial coefficients
|
|
625
|
+
// Xử lý binomial coefficients
|
|
623
626
|
result = result.replace(/\\left\(\\DELETE_BRACKET_L/g, '');
|
|
624
627
|
result = result.replace(/\\DELETE_BRACKET_R\\right\)/g, '');
|
|
625
628
|
result = result.replace(/\\DELETE_BRACKET_L/g, '');
|
|
626
629
|
result = result.replace(/\\DELETE_BRACKET_R/g, '');
|
|
627
|
-
|
|
628
|
-
//
|
|
629
|
-
// Case 1: munder - arrow with empty subscript
|
|
630
|
+
|
|
631
|
+
// Xử lý các trường hợp mũi tên với giới hạn
|
|
630
632
|
result = result.replace(/→\\limits_{}/g, "\\underset{}{\\rightarrow}");
|
|
631
633
|
result = result.replace(/→\\limits_{(\s*)}/g, "\\underset{}{\\rightarrow}");
|
|
632
634
|
result = result.replace(/\\rightarrow\\limits_{}/g, "\\underset{}{\\rightarrow}");
|
|
633
635
|
result = result.replace(/\\rightarrow\\limits_{(\s*)}/g, "\\underset{}{\\rightarrow}");
|
|
634
|
-
|
|
635
|
-
// Case 2: munder - arrow with non-empty subscript
|
|
636
|
+
|
|
636
637
|
result = result.replace(/→\\limits_\{([^}]*)\}/g, "\\underset{$1}{\\rightarrow}");
|
|
637
638
|
result = result.replace(/\\rightarrow\\limits_\{([^}]*)\}/g, "\\underset{$1}{\\rightarrow}");
|
|
638
|
-
|
|
639
|
-
// Case 3: munderover - arrow with both subscript and superscript
|
|
639
|
+
|
|
640
640
|
result = result.replace(/→\\limits_\{([^}]*)\}\^\{([^}]*)\}/g, "\\overset{$2}{\\underset{$1}{\\rightarrow}}");
|
|
641
641
|
result = result.replace(/\\rightarrow\\limits_\{([^}]*)\}\^\{([^}]*)\}/g, "\\overset{$2}{\\underset{$1}{\\rightarrow}}");
|
|
642
|
-
|
|
643
|
-
//
|
|
644
|
-
// Simple expression with arrow superscript: expr^{\rightarrow} → \overrightarrow{expr}
|
|
642
|
+
|
|
643
|
+
// Xử lý vector và các ký hiệu đặc biệt
|
|
645
644
|
result = result.replace(/([^{}\s]+)\^\{\\rightarrow\}/g, "\\overrightarrow{$1}");
|
|
646
645
|
result = result.replace(/\{([^{}]+)\}\^\{\\rightarrow\}/g, "\\overrightarrow{$1}");
|
|
647
|
-
|
|
648
|
-
// Complex expressions with subscripts and arrow: expr_{sub}^{\rightarrow} → \overrightarrow{expr_{sub}}
|
|
649
646
|
result = result.replace(/([A-Za-z0-9]+)_\{([^{}]+)\}\^\{\\rightarrow\}/g, "\\overrightarrow{$1_{$2}}");
|
|
650
647
|
result = result.replace(/([A-Za-z0-9]+)_([0-9])\^\{\\rightarrow\}/g, "\\overrightarrow{$1_$2}");
|
|
651
|
-
|
|
652
|
-
// Very complex expressions: (expr)^{\rightarrow} → \overrightarrow{(expr)}
|
|
653
648
|
result = result.replace(/(\([^()]+\))\^\{\\rightarrow\}/g, "\\overrightarrow{$1}");
|
|
654
|
-
|
|
655
|
-
//
|
|
656
|
-
result = result.replace(
|
|
657
|
-
result = result.replace(
|
|
658
|
-
|
|
649
|
+
|
|
650
|
+
// Thêm xử lý các ký hiệu toán học phổ biến
|
|
651
|
+
result = result.replace(/≤/g, "\\leq");
|
|
652
|
+
result = result.replace(/≥/g, "\\geq");
|
|
653
|
+
result = result.replace(/≠/g, "\\neq");
|
|
654
|
+
result = result.replace(/≈/g, "\\approx");
|
|
655
|
+
result = result.replace(/π/g, "\\pi");
|
|
656
|
+
result = result.replace(/α/g, "\\alpha");
|
|
657
|
+
result = result.replace(/β/g, "\\beta");
|
|
658
|
+
result = result.replace(/γ/g, "\\gamma");
|
|
659
|
+
|
|
659
660
|
return result;
|
|
660
661
|
}
|
|
661
662
|
|
|
@@ -669,15 +670,15 @@
|
|
|
669
670
|
}
|
|
670
671
|
|
|
671
672
|
// @see https://www.w3.org/TR/MathML3/chapter7.html
|
|
673
|
+
// Cải tiến parseLeaf để hỗ trợ thêm các ký hiệu
|
|
672
674
|
function parseLeaf(node) {
|
|
673
675
|
let r = '';
|
|
674
676
|
const nodeName = NodeTool.getNodeName(node);
|
|
675
|
-
|
|
676
|
-
// Special case for empty mrow
|
|
677
|
+
|
|
677
678
|
if (nodeName === "mrow" && NodeTool.getNodeText(node).trim() === "") {
|
|
678
679
|
return "";
|
|
679
680
|
}
|
|
680
|
-
|
|
681
|
+
|
|
681
682
|
switch (nodeName) {
|
|
682
683
|
case 'mi':
|
|
683
684
|
r = parseElementMi(node);
|
|
@@ -688,53 +689,76 @@
|
|
|
688
689
|
case 'mo':
|
|
689
690
|
r = parseOperator(node);
|
|
690
691
|
break;
|
|
691
|
-
case 'ms':
|
|
692
|
+
case 'ms':
|
|
693
|
+
r = parseElementMs(node);
|
|
692
694
|
break;
|
|
693
|
-
case 'mtext':
|
|
695
|
+
case 'mtext':
|
|
696
|
+
r = parseElementMtext(node);
|
|
694
697
|
break;
|
|
695
|
-
case 'mglyph':
|
|
698
|
+
case 'mglyph':
|
|
699
|
+
r = parseElementMglyph(node);
|
|
696
700
|
break;
|
|
697
|
-
case 'mprescripts':
|
|
701
|
+
case 'mprescripts':
|
|
702
|
+
r = '';
|
|
698
703
|
break;
|
|
699
|
-
case 'mspace':
|
|
700
|
-
|
|
701
|
-
//TODO other usecase of 'none' ?
|
|
704
|
+
case 'mspace':
|
|
705
|
+
r = parseElementMspace();
|
|
702
706
|
break;
|
|
703
|
-
|
|
707
|
+
case 'none':
|
|
708
|
+
r = '\\:';
|
|
709
|
+
break;
|
|
710
|
+
default:
|
|
711
|
+
r = escapeSpecialChars(NodeTool.getNodeText(node).trim());
|
|
704
712
|
break;
|
|
705
713
|
}
|
|
706
714
|
return r;
|
|
707
715
|
}
|
|
708
716
|
|
|
709
|
-
//
|
|
717
|
+
// Cải tiến parseOperator để hỗ trợ thêm toán tử
|
|
710
718
|
function parseOperator(node) {
|
|
711
719
|
let it = NodeTool.getNodeText(node).trim();
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
+
|
|
721
|
+
const operatorMap = {
|
|
722
|
+
"→": " \\rightarrow ",
|
|
723
|
+
"←": " \\leftarrow ",
|
|
724
|
+
"↔": " \\leftrightarrow ",
|
|
725
|
+
"⇒": " \\Rightarrow ",
|
|
726
|
+
"⇐": " \\Leftarrow ",
|
|
727
|
+
"⇔": " \\Leftrightarrow ",
|
|
728
|
+
"±": " \\pm ",
|
|
729
|
+
"×": " \\times ",
|
|
730
|
+
"÷": " \\div ",
|
|
731
|
+
"∑": " \\sum ",
|
|
732
|
+
"∏": " \\prod ",
|
|
733
|
+
"∫": " \\int ",
|
|
734
|
+
"−": "-",
|
|
735
|
+
"≠": " \\neq ",
|
|
736
|
+
">": " > ",
|
|
737
|
+
"=": " = ",
|
|
738
|
+
",": ", ", // Dấu phẩy trong tập hợp
|
|
739
|
+
";": ";", // Dấu chấm phẩy không cần khoảng trắng
|
|
740
|
+
"Ω": "\\Omega" // Thêm ký hiệu Omega
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
return operatorMap[it] || escapeSpecialChars(MathSymbol.parseOperator(it));
|
|
720
744
|
}
|
|
721
745
|
|
|
722
746
|
// Math identifier
|
|
723
747
|
function parseElementMi(node) {
|
|
724
748
|
let it = NodeTool.getNodeText(node).trim();
|
|
725
|
-
|
|
749
|
+
|
|
726
750
|
// Handle vectors (e.g. AB', AI)
|
|
727
751
|
if (it.includes("'")) {
|
|
728
752
|
return it; // Return as is to handle in mrow
|
|
729
753
|
}
|
|
730
|
-
|
|
754
|
+
|
|
731
755
|
// Handle subscripts (e.g. n₂)
|
|
732
|
-
if (it.match(/[a-zA-
|
|
756
|
+
if (it.match(/[a-zA-z]\d/)) {
|
|
733
757
|
const base = it[0];
|
|
734
758
|
const sub = it[1];
|
|
735
759
|
return `${base}_{${sub}}`;
|
|
736
760
|
}
|
|
737
|
-
|
|
761
|
+
|
|
738
762
|
it = MathSymbol.parseIdentifier(it);
|
|
739
763
|
return escapeSpecialChars(it);
|
|
740
764
|
}
|
|
@@ -746,33 +770,33 @@
|
|
|
746
770
|
}
|
|
747
771
|
|
|
748
772
|
// Math String
|
|
749
|
-
function parseElementMs(node){
|
|
773
|
+
function parseElementMs(node) {
|
|
750
774
|
const content = NodeTool.getNodeText(node).trimRight();
|
|
751
775
|
const it = escapeSpecialChars(content);
|
|
752
776
|
return ['"', it, '"'].join('');
|
|
753
777
|
}
|
|
754
778
|
|
|
755
779
|
// Math Text
|
|
756
|
-
function parseElementMtext(node){
|
|
780
|
+
function parseElementMtext(node) {
|
|
757
781
|
const content = NodeTool.getNodeText(node);
|
|
758
782
|
const it = escapeSpecialChars(content);
|
|
759
783
|
return `\\text{${it}}`;
|
|
760
784
|
}
|
|
761
785
|
|
|
762
786
|
// Math glyph (image)
|
|
763
|
-
function parseElementMglyph(node){
|
|
787
|
+
function parseElementMglyph(node) {
|
|
764
788
|
const it = ['"', NodeTool.getAttr(node, 'alt', ''), '"'].join('');
|
|
765
789
|
return escapeSpecialChars(it);
|
|
766
790
|
}
|
|
767
791
|
|
|
768
792
|
// TODO need or not
|
|
769
|
-
function parseElementMspace(node){
|
|
793
|
+
function parseElementMspace(node) {
|
|
770
794
|
return '';
|
|
771
795
|
}
|
|
772
796
|
|
|
773
797
|
function escapeSpecialChars(text) {
|
|
774
798
|
const specialChars = /\$|%|_|&|#|\{|\}/g;
|
|
775
|
-
text = text.replace(specialChars, char => `\\${
|
|
799
|
+
text = text.replace(specialChars, char => `\\${char}`);
|
|
776
800
|
return text;
|
|
777
801
|
}
|
|
778
802
|
|
|
@@ -790,26 +814,33 @@
|
|
|
790
814
|
const parts = [];
|
|
791
815
|
let lefts = [];
|
|
792
816
|
Array.prototype.forEach.call(children, (node) => {
|
|
793
|
-
if(NodeTool.getNodeName(node) === 'mo'){
|
|
817
|
+
if (NodeTool.getNodeName(node) === 'mo') {
|
|
794
818
|
const op = NodeTool.getNodeText(node).trim();
|
|
795
|
-
if(Brackets.contains(op)){
|
|
819
|
+
if (Brackets.contains(op)) {
|
|
796
820
|
let stretchy = NodeTool.getAttr(node, 'stretchy', 'true');
|
|
797
821
|
stretchy = ['', 'true'].indexOf(stretchy) > -1;
|
|
798
|
-
|
|
799
|
-
if(Brackets.isRight(op)){
|
|
822
|
+
|
|
823
|
+
if (Brackets.isRight(op)) {
|
|
800
824
|
const nearLeft = lefts[lefts.length - 1];
|
|
801
|
-
if(nearLeft){
|
|
802
|
-
if(Brackets.isPair(nearLeft, op)){
|
|
825
|
+
if (nearLeft) {
|
|
826
|
+
if (Brackets.isPair(nearLeft, op)) {
|
|
803
827
|
parts.push(Brackets.parseRight(op, stretchy));
|
|
804
828
|
lefts.pop();
|
|
805
829
|
} else {
|
|
806
830
|
parts.push(`\\right${op}`);
|
|
807
831
|
}
|
|
808
832
|
} else {
|
|
809
|
-
parts.push(
|
|
833
|
+
parts.push(op); // Chỉ thêm dấu ngoặc đóng khi đứng một mình
|
|
810
834
|
}
|
|
811
835
|
} else {
|
|
812
|
-
|
|
836
|
+
// Xử lý dấu ngoặc mở
|
|
837
|
+
if (op === '{' && node.parentNode &&
|
|
838
|
+
Array.from(NodeTool.getChildren(node.parentNode)).some(child =>
|
|
839
|
+
NodeTool.getNodeName(child) === 'mtable')) {
|
|
840
|
+
parts.push('\\left\\{');
|
|
841
|
+
} else {
|
|
842
|
+
parts.push(Brackets.parseLeft(op, stretchy));
|
|
843
|
+
}
|
|
813
844
|
lefts.push(op);
|
|
814
845
|
}
|
|
815
846
|
} else {
|
|
@@ -819,351 +850,444 @@
|
|
|
819
850
|
parts.push(parse(node));
|
|
820
851
|
}
|
|
821
852
|
});
|
|
822
|
-
|
|
823
|
-
|
|
853
|
+
|
|
854
|
+
// Chỉ thêm \right. nếu có dấu ngoặc mở chưa được đóng
|
|
855
|
+
if (lefts.length > 0 && !parts.some(p => p.includes('\\right'))) {
|
|
824
856
|
parts.push("\\right.");
|
|
825
857
|
}
|
|
826
858
|
lefts = undefined;
|
|
827
859
|
return parts;
|
|
828
860
|
}
|
|
829
861
|
|
|
830
|
-
|
|
831
862
|
function getRender(node) {
|
|
832
863
|
let render = undefined;
|
|
833
864
|
const nodeName = NodeTool.getNodeName(node);
|
|
834
|
-
|
|
865
|
+
|
|
866
|
+
switch (nodeName) {
|
|
867
|
+
case 'mrow':
|
|
868
|
+
render = function (node, children) {
|
|
869
|
+
const childrenArray = Array.from(children);
|
|
870
|
+
if (childrenArray.length >= 2 &&
|
|
871
|
+
NodeTool.getNodeName(childrenArray[0]) === 'mo' &&
|
|
872
|
+
NodeTool.getNodeName(childrenArray[childrenArray.length - 1]) === 'mo') {
|
|
873
|
+
const firstOp = NodeTool.getNodeText(childrenArray[0]).trim();
|
|
874
|
+
const lastOp = NodeTool.getNodeText(childrenArray[childrenArray.length - 1]).trim();
|
|
875
|
+
|
|
876
|
+
// Xử lý đặc biệt cho dấu ngoặc nhọn chứa mtable
|
|
877
|
+
if (firstOp === '{' && childrenArray.some(child =>
|
|
878
|
+
NodeTool.getNodeName(child) === 'mtable')) {
|
|
879
|
+
const innerContent = childrenArray
|
|
880
|
+
.slice(1, -1)
|
|
881
|
+
.map(child => parse(child))
|
|
882
|
+
.join('');
|
|
883
|
+
return `\\left\\{${innerContent}\\right.`;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// Xử lý cho trường hợp [a;b) và [a,b)
|
|
887
|
+
if (firstOp === '[' && lastOp === ')') {
|
|
888
|
+
const innerContent = childrenArray
|
|
889
|
+
.slice(1, -1)
|
|
890
|
+
.map(child => parse(child))
|
|
891
|
+
.join('');
|
|
892
|
+
return `\\left[${innerContent}\\right)`;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// Xử lý ngoặc nhọn bình thường
|
|
896
|
+
if (firstOp === '{' && lastOp === '}') {
|
|
897
|
+
const innerContent = childrenArray
|
|
898
|
+
.slice(1, -1)
|
|
899
|
+
.map(child => parse(child))
|
|
900
|
+
.join('');
|
|
901
|
+
return `\\{${innerContent}\\}`;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
// Bỏ qua nếu firstOp là rỗng (trường hợp <mo></mo>)
|
|
905
|
+
if (!firstOp && !lastOp) {
|
|
906
|
+
return getRender_joinSeparator("@content")(node, childrenArray);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// Xử lý đặc biệt cho dấu ngoặc vuông chứa mtable
|
|
910
|
+
if (firstOp === '[') {
|
|
911
|
+
const innerContent = childrenArray
|
|
912
|
+
.slice(1, -1) // Bỏ dấu ngoặc mở và đóng
|
|
913
|
+
.map(child => {
|
|
914
|
+
const parsed = parse(child);
|
|
915
|
+
// Nếu child là mtable, trả về nội dung đã được định dạng với \begin{array}{l} ... \end{array}
|
|
916
|
+
if (NodeTool.getNodeName(child) === 'mtable') {
|
|
917
|
+
const rows = Array.from(NodeTool.getChildren(child)).map(row => {
|
|
918
|
+
const rowChildren = Array.from(NodeTool.getChildren(row));
|
|
919
|
+
return rowChildren.map(cell => parse(cell)).join('');
|
|
920
|
+
});
|
|
921
|
+
return `\\begin{array}{l} ${rows.join(' \\\\ ')} \\end{array}`;
|
|
922
|
+
}
|
|
923
|
+
// Nếu child là mrow chứa mtable, xử lý tương tự
|
|
924
|
+
if (NodeTool.getNodeName(child) === 'mrow' &&
|
|
925
|
+
Array.from(NodeTool.getChildren(child)).some(c => NodeTool.getNodeName(c) === 'mtable')) {
|
|
926
|
+
const mtableChild = Array.from(NodeTool.getChildren(child)).find(c => NodeTool.getNodeName(c) === 'mtable');
|
|
927
|
+
const rows = Array.from(NodeTool.getChildren(mtableChild)).map(row => {
|
|
928
|
+
const rowChildren = Array.from(NodeTool.getChildren(row));
|
|
929
|
+
return rowChildren.map(cell => parse(cell)).join('');
|
|
930
|
+
});
|
|
931
|
+
return `\\begin{array}{l} ${rows.join(' \\\\ ')} \\end{array}`;
|
|
932
|
+
}
|
|
933
|
+
return parsed;
|
|
934
|
+
})
|
|
935
|
+
.join('');
|
|
936
|
+
|
|
937
|
+
// Giữ nguyên dấu ngoặc vuông lớn
|
|
938
|
+
return `\\left[${innerContent}\\right.`;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
if (Brackets.isPair(firstOp, lastOp)) {
|
|
942
|
+
const innerContent = childrenArray
|
|
943
|
+
.slice(1, -1)
|
|
944
|
+
.map(child => parse(child))
|
|
945
|
+
.join('');
|
|
946
|
+
return `\\left${firstOp}${innerContent}\\right${lastOp}`;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
// Giữ nguyên dấu ngoặc nhọn trong MathML
|
|
950
|
+
if (firstOp === '{' || lastOp === '}') {
|
|
951
|
+
const innerContent = childrenArray
|
|
952
|
+
.slice(1, lastOp === '}' ? -1 : undefined)
|
|
953
|
+
.map(child => parse(child))
|
|
954
|
+
.join('');
|
|
955
|
+
return `${firstOp === '{' ? '\\{' : ''}${innerContent}${lastOp === '}' ? '\\}' : ''}`;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
return getRender_joinSeparator("@content")(node, childrenArray);
|
|
959
|
+
};
|
|
960
|
+
break;
|
|
961
|
+
|
|
835
962
|
case 'msub':
|
|
836
|
-
render = function(node, children) {
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
const base = parse(
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
const sub = children[1];
|
|
963
|
+
render = function (node, children) {
|
|
964
|
+
const childrenArray = Array.from(children);
|
|
965
|
+
if (!childrenArray || childrenArray.length < 2) return '';
|
|
966
|
+
const base = parse(childrenArray[0]) || '';
|
|
967
|
+
const sub = childrenArray[1];
|
|
843
968
|
if (!sub) return base;
|
|
844
969
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
(!NodeTool.getNodeText(sub.firstChild) || NodeTool.getNodeText(sub.firstChild).trim() === '')) {
|
|
970
|
+
if (NodeTool.getNodeName(sub) === 'msub' &&
|
|
971
|
+
sub.firstChild &&
|
|
972
|
+
NodeTool.getNodeName(sub.firstChild) === 'mrow' &&
|
|
973
|
+
(!NodeTool.getNodeText(sub.firstChild) || NodeTool.getNodeText(sub.firstChild).trim() === '')) {
|
|
850
974
|
const lastChild = sub.lastChild;
|
|
851
|
-
|
|
852
|
-
return `${base}_${parse(lastChild)}`;
|
|
975
|
+
return lastChild ? `${base}_${parse(lastChild)}` : base;
|
|
853
976
|
}
|
|
854
|
-
|
|
855
|
-
// Regular subscript
|
|
856
977
|
return `${base}_{${parse(sub)}}`;
|
|
857
978
|
};
|
|
858
979
|
break;
|
|
980
|
+
|
|
859
981
|
case 'msup':
|
|
860
|
-
render =
|
|
982
|
+
render = function (node, children) {
|
|
983
|
+
const childrenArray = Array.from(children);
|
|
984
|
+
if (!childrenArray || childrenArray.length < 2) return '';
|
|
985
|
+
const base = parse(childrenArray[0]) || '';
|
|
986
|
+
const sup = parse(childrenArray[1]) || '';
|
|
987
|
+
return `${base}^{${sup}}`;
|
|
988
|
+
};
|
|
861
989
|
break;
|
|
990
|
+
|
|
862
991
|
case 'msubsup':
|
|
863
|
-
render =
|
|
992
|
+
render = function (node, children) {
|
|
993
|
+
const childrenArray = Array.from(children);
|
|
994
|
+
if (!childrenArray || childrenArray.length < 3) return '';
|
|
995
|
+
const base = parse(childrenArray[0]);
|
|
996
|
+
const sub = parse(childrenArray[1]);
|
|
997
|
+
const sup = parse(childrenArray[2]);
|
|
998
|
+
|
|
999
|
+
const lastChild = childrenArray[0].lastElementChild;
|
|
1000
|
+
if (lastChild && NodeTool.getNodeName(lastChild) === 'mo' &&
|
|
1001
|
+
NodeTool.getNodeText(lastChild).trim() === '|') {
|
|
1002
|
+
const content = Array.from(childrenArray[0].children)
|
|
1003
|
+
.slice(0, -1)
|
|
1004
|
+
.map(child => parse(child))
|
|
1005
|
+
.join('');
|
|
1006
|
+
return `\\left.${content}\\right|_{${sub}}^{${sup}}`;
|
|
1007
|
+
}
|
|
1008
|
+
return `${base}_{${sub}}^{${sup}}`;
|
|
1009
|
+
};
|
|
864
1010
|
break;
|
|
1011
|
+
|
|
865
1012
|
case 'mover':
|
|
866
|
-
render =
|
|
1013
|
+
render = function (node, children) {
|
|
1014
|
+
const childrenArray = Array.from(children);
|
|
1015
|
+
if (!childrenArray || childrenArray.length < 2) return '';
|
|
1016
|
+
const base = parse(childrenArray[0]) || '';
|
|
1017
|
+
const over = parse(childrenArray[1]) || '';
|
|
1018
|
+
const overText = NodeTool.getNodeText(childrenArray[1])?.trim() || '';
|
|
1019
|
+
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1020
|
+
|
|
1021
|
+
if (overText === "→" && isAccent) return `\\vec{${base}}`;
|
|
1022
|
+
if (overText === "¯" && isAccent) return `\\overline{${base}}`;
|
|
1023
|
+
if (overText === "^" && isAccent) return `\\hat{${base}}`;
|
|
1024
|
+
return `\\overset{${over}}{${base}}`;
|
|
1025
|
+
};
|
|
867
1026
|
break;
|
|
1027
|
+
|
|
868
1028
|
case 'munder':
|
|
869
|
-
render =
|
|
1029
|
+
render = function (node, children) {
|
|
1030
|
+
const childrenArray = Array.from(children);
|
|
1031
|
+
if (!childrenArray || childrenArray.length < 2) return '';
|
|
1032
|
+
const base = parse(childrenArray[0]) || '';
|
|
1033
|
+
const under = parse(childrenArray[1]) || '';
|
|
1034
|
+
const isUnderAccent = NodeTool.getAttr(node, "accentunder", "false") === "true";
|
|
1035
|
+
|
|
1036
|
+
if (base === "∫") return `\\int_{${under}}`;
|
|
1037
|
+
return `\\underset{${under}}{${base}}`;
|
|
1038
|
+
};
|
|
870
1039
|
break;
|
|
1040
|
+
|
|
871
1041
|
case 'munderover':
|
|
872
|
-
render =
|
|
1042
|
+
render = function (node, children) {
|
|
1043
|
+
const childrenArray = Array.from(children);
|
|
1044
|
+
if (!childrenArray || childrenArray.length < 3) return '';
|
|
1045
|
+
const base = parse(childrenArray[0]);
|
|
1046
|
+
const under = parse(childrenArray[1]);
|
|
1047
|
+
const over = parse(childrenArray[2]);
|
|
1048
|
+
const baseText = NodeTool.getNodeText(childrenArray[0]).trim();
|
|
1049
|
+
|
|
1050
|
+
if (baseText === '∫') return `\\int_{${under}}^{${over}}`;
|
|
1051
|
+
if (baseText === '∑') return `\\sum_{${under}}^{${over}}`;
|
|
1052
|
+
if (baseText === '∏') return `\\prod_{${under}}^{${over}}`;
|
|
1053
|
+
if (baseText === '|') return `\\big|_{${under}}^{${over}}`;
|
|
1054
|
+
return `${base}_{${under}}^{${over}}`;
|
|
1055
|
+
};
|
|
873
1056
|
break;
|
|
1057
|
+
|
|
874
1058
|
case 'mmultiscripts':
|
|
875
|
-
render =
|
|
1059
|
+
render = function (node, children) {
|
|
1060
|
+
const childrenArray = Array.from(children);
|
|
1061
|
+
if (!childrenArray || childrenArray.length < 1) return '';
|
|
1062
|
+
const base = parse(childrenArray[0]);
|
|
1063
|
+
let prescripts = '';
|
|
1064
|
+
let postscripts = '';
|
|
1065
|
+
let i = 1;
|
|
1066
|
+
|
|
1067
|
+
while (i < childrenArray.length) {
|
|
1068
|
+
if (NodeTool.getNodeName(childrenArray[i]) === 'mprescripts') {
|
|
1069
|
+
i++;
|
|
1070
|
+
if (i + 1 < childrenArray.length) {
|
|
1071
|
+
prescripts = `_{${parse(childrenArray[i])}}^{${parse(childrenArray[i + 1])}}`;
|
|
1072
|
+
i += 2;
|
|
1073
|
+
}
|
|
1074
|
+
} else {
|
|
1075
|
+
if (i + 1 < childrenArray.length) {
|
|
1076
|
+
postscripts += `_{${parse(childrenArray[i])}}^{${parse(childrenArray[i + 1])}}`;
|
|
1077
|
+
i += 2;
|
|
1078
|
+
} else break;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
return `${base}${prescripts}${postscripts}`;
|
|
1082
|
+
};
|
|
876
1083
|
break;
|
|
1084
|
+
|
|
1085
|
+
case 'mlongdiv':
|
|
1086
|
+
render = function (node, children) {
|
|
1087
|
+
const childrenArray = Array.from(children);
|
|
1088
|
+
if (!childrenArray || childrenArray.length < 2) return '';
|
|
1089
|
+
return `\\longdiv{${parse(childrenArray[0])}}{${parse(childrenArray[1])}}`;
|
|
1090
|
+
};
|
|
1091
|
+
break;
|
|
1092
|
+
|
|
877
1093
|
case 'mroot':
|
|
878
|
-
render =
|
|
1094
|
+
render = function (node, children) {
|
|
1095
|
+
const childrenArray = Array.from(children);
|
|
1096
|
+
if (!childrenArray || childrenArray.length < 2) return '';
|
|
1097
|
+
const base = parse(childrenArray[0]);
|
|
1098
|
+
const index = parse(childrenArray[1]);
|
|
1099
|
+
return `\\sqrt[${index}]{${base}}`;
|
|
1100
|
+
};
|
|
879
1101
|
break;
|
|
1102
|
+
|
|
880
1103
|
case 'msqrt':
|
|
881
|
-
render =
|
|
1104
|
+
render = function (node, children) {
|
|
1105
|
+
const childrenArray = Array.from(children);
|
|
1106
|
+
const content = renderChildren(childrenArray).join('');
|
|
1107
|
+
return `\\sqrt{${content}}`;
|
|
1108
|
+
};
|
|
882
1109
|
break;
|
|
1110
|
+
|
|
883
1111
|
case 'mtable':
|
|
884
|
-
render =
|
|
1112
|
+
render = function (node, children) {
|
|
1113
|
+
const childrenArray = Array.from(children);
|
|
1114
|
+
|
|
1115
|
+
// Kiểm tra xem mtable có phải là mtable con không
|
|
1116
|
+
let isNestedTable = false;
|
|
1117
|
+
let parent = node.parentNode;
|
|
1118
|
+
while (parent) {
|
|
1119
|
+
if (NodeTool.getNodeName(parent) === 'mtable') {
|
|
1120
|
+
isNestedTable = true;
|
|
1121
|
+
break;
|
|
1122
|
+
}
|
|
1123
|
+
parent = parent.parentNode;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// Xử lý mỗi mtr như một hàng
|
|
1127
|
+
const rows = childrenArray.map(row => {
|
|
1128
|
+
const rowChildren = Array.from(NodeTool.getChildren(row));
|
|
1129
|
+
return rowChildren.map(cell => parse(cell)).join('');
|
|
1130
|
+
});
|
|
1131
|
+
|
|
1132
|
+
// Nếu là mtable con, chỉ trả về các hàng mà không bao bọc trong \begin{array}...\end{array}
|
|
1133
|
+
if (isNestedTable) {
|
|
1134
|
+
return rows.join(' \\\\ ');
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// Nếu mtable nằm trong mrow với dấu ngoặc vuông, sẽ được xử lý ở mrow
|
|
1138
|
+
let isInsideSquareBrackets = false;
|
|
1139
|
+
parent = node.parentNode;
|
|
1140
|
+
while (parent) {
|
|
1141
|
+
if (NodeTool.getNodeName(parent) === 'mrow') {
|
|
1142
|
+
const childrenOfParent = Array.from(NodeTool.getChildren(parent));
|
|
1143
|
+
if (childrenOfParent.length >= 2 &&
|
|
1144
|
+
NodeTool.getNodeName(childrenOfParent[0]) === 'mo' &&
|
|
1145
|
+
NodeTool.getNodeText(childrenOfParent[0]).trim() === '[') {
|
|
1146
|
+
isInsideSquareBrackets = true;
|
|
1147
|
+
break;
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
parent = parent.parentNode;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
if (isInsideSquareBrackets) {
|
|
1154
|
+
return rows.join(' \\\\ ');
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
// Nếu là mtable chính, bao bọc trong \begin{array}...\end{array}
|
|
1158
|
+
const arrayContent = rows.join(' \\\\ ');
|
|
1159
|
+
return `\\begin{array}{l} ${arrayContent} \\end{array}`;
|
|
1160
|
+
};
|
|
885
1161
|
break;
|
|
1162
|
+
|
|
886
1163
|
case 'mtr':
|
|
887
|
-
render = getRender_joinSeparator("@content
|
|
1164
|
+
render = getRender_joinSeparator("@content", " & ");
|
|
888
1165
|
break;
|
|
1166
|
+
|
|
889
1167
|
case 'mtd':
|
|
890
1168
|
render = getRender_joinSeparator("@content");
|
|
891
1169
|
break;
|
|
1170
|
+
|
|
892
1171
|
case 'mfrac':
|
|
893
|
-
render =
|
|
1172
|
+
render = function (node, children) {
|
|
1173
|
+
const childrenArray = Array.from(children);
|
|
1174
|
+
if (!childrenArray || childrenArray.length < 2) return '';
|
|
1175
|
+
const num = parse(childrenArray[0]);
|
|
1176
|
+
const den = parse(childrenArray[1]);
|
|
1177
|
+
const linethickness = NodeTool.getAttr(node, 'linethickness', 'medium');
|
|
1178
|
+
if (linethickness === '0') return `\\binom{${num}}{${den}}`;
|
|
1179
|
+
return `\\frac{${num}}{${den}}`;
|
|
1180
|
+
};
|
|
894
1181
|
break;
|
|
1182
|
+
|
|
895
1183
|
case 'mfenced':
|
|
896
|
-
render =
|
|
1184
|
+
render = function (node, children) {
|
|
1185
|
+
const childrenArray = Array.from(children);
|
|
1186
|
+
const open = NodeTool.getAttr(node, 'open', '(');
|
|
1187
|
+
const close = NodeTool.getAttr(node, 'close', ')');
|
|
1188
|
+
const separators = NodeTool.getAttr(node, 'separators', ',').split('');
|
|
1189
|
+
|
|
1190
|
+
// Xử lý đặc biệt cho mfenced chứa mtable
|
|
1191
|
+
if (open === '{' && !close) {
|
|
1192
|
+
// Kiểm tra xem có mtable trong cấu trúc không
|
|
1193
|
+
const hasMtable = childrenArray.some(child => {
|
|
1194
|
+
// Kiểm tra trực tiếp mtable
|
|
1195
|
+
if (NodeTool.getNodeName(child) === 'mtable') return true;
|
|
1196
|
+
// Kiểm tra mtable trong mrow
|
|
1197
|
+
if (NodeTool.getNodeName(child) === 'mrow') {
|
|
1198
|
+
return Array.from(NodeTool.getChildren(child)).some(
|
|
1199
|
+
grandChild => NodeTool.getNodeName(grandChild) === 'mtable'
|
|
1200
|
+
);
|
|
1201
|
+
}
|
|
1202
|
+
return false;
|
|
1203
|
+
});
|
|
1204
|
+
|
|
1205
|
+
if (hasMtable) {
|
|
1206
|
+
const content = childrenArray.map(child => parse(child)).join('');
|
|
1207
|
+
return `\\left\\{${content}\\right.`;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
// Xử lý cho trường hợp [a;b)
|
|
1212
|
+
if (open === '[' && close === ')') {
|
|
1213
|
+
const parts = [];
|
|
1214
|
+
childrenArray.forEach((child, index) => {
|
|
1215
|
+
parts.push(parse(child));
|
|
1216
|
+
if (index < childrenArray.length - 1 && separators[index % separators.length]) {
|
|
1217
|
+
parts.push(separators[index % separators.length]);
|
|
1218
|
+
}
|
|
1219
|
+
});
|
|
1220
|
+
return `\\left[${parts.join('')}\\right)`;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
// Giữ nguyên xử lý cho các trường hợp khác
|
|
1224
|
+
const parts = [];
|
|
1225
|
+
childrenArray.forEach((child, index) => {
|
|
1226
|
+
parts.push(parse(child));
|
|
1227
|
+
if (index < childrenArray.length - 1 && separators[index % separators.length]) {
|
|
1228
|
+
parts.push(separators[index % separators.length]);
|
|
1229
|
+
}
|
|
1230
|
+
});
|
|
1231
|
+
const content = parts.join('');
|
|
1232
|
+
|
|
1233
|
+
if (open === '{' && close === '}') return `\\{${content}\\}`;
|
|
1234
|
+
if (open === '|' && close === '|') return `\\left|${content}\\right|`;
|
|
1235
|
+
if (!close) return `\\left${open}${content}\\right.`;
|
|
1236
|
+
if (!open) return `${content}\\right${close}`;
|
|
1237
|
+
return `\\left${open}${content}\\right${close}`;
|
|
1238
|
+
};
|
|
1239
|
+
break;
|
|
1240
|
+
|
|
1241
|
+
case 'menclose':
|
|
1242
|
+
render = function (node, children) {
|
|
1243
|
+
const childrenArray = Array.from(children);
|
|
1244
|
+
const notation = NodeTool.getAttr(node, 'notation', 'longdiv');
|
|
1245
|
+
const content = renderChildren(childrenArray).join('');
|
|
1246
|
+
switch (notation) {
|
|
1247
|
+
case 'box': return `\\boxed{${content}}`;
|
|
1248
|
+
case 'circle': return `\\enclose{circle}{${content}}`;
|
|
1249
|
+
case 'roundedbox': return `\\fbox{${content}}`;
|
|
1250
|
+
default: return content;
|
|
1251
|
+
}
|
|
1252
|
+
};
|
|
897
1253
|
break;
|
|
1254
|
+
|
|
898
1255
|
case 'mi':
|
|
899
1256
|
case 'mn':
|
|
900
1257
|
case 'mo':
|
|
901
1258
|
case 'ms':
|
|
902
1259
|
case 'mtext':
|
|
903
|
-
// they may contains <mglyph>
|
|
904
1260
|
render = getRender_joinSeparator("@content");
|
|
905
1261
|
break;
|
|
1262
|
+
|
|
906
1263
|
case 'mphantom':
|
|
907
|
-
render =
|
|
1264
|
+
render = function (node, children) {
|
|
1265
|
+
const childrenArray = Array.from(children);
|
|
1266
|
+
const content = renderChildren(childrenArray).join('');
|
|
1267
|
+
return `\\phantom{${content}}`;
|
|
1268
|
+
};
|
|
1269
|
+
break;
|
|
1270
|
+
|
|
1271
|
+
case 'mstyle':
|
|
1272
|
+
render = function (node, children) {
|
|
1273
|
+
const childrenArray = Array.from(children);
|
|
1274
|
+
const mathsize = NodeTool.getAttr(node, 'mathsize', 'normal');
|
|
1275
|
+
const content = renderChildren(childrenArray).join('');
|
|
1276
|
+
switch (mathsize) {
|
|
1277
|
+
case 'big': return `\\large{${content}}`;
|
|
1278
|
+
case 'small': return `\\small{${content}}`;
|
|
1279
|
+
default: return content;
|
|
1280
|
+
}
|
|
1281
|
+
};
|
|
908
1282
|
break;
|
|
1283
|
+
|
|
909
1284
|
default:
|
|
910
|
-
// math, mstyle, mrow
|
|
911
1285
|
render = getRender_joinSeparator("@content");
|
|
912
1286
|
break;
|
|
913
1287
|
}
|
|
914
1288
|
return render;
|
|
915
1289
|
}
|
|
916
1290
|
|
|
917
|
-
function renderTable(node, children) {
|
|
918
|
-
const template = "\\begin{array}{l}@content\\end{array}";
|
|
919
|
-
// Remove extra backslash and add proper spacing
|
|
920
|
-
const render = getRender_joinSeparator(template, " \\\\ ");
|
|
921
|
-
return render(node, children);
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
function renderMover(node, children) {
|
|
925
|
-
// Check if children exists and has enough elements
|
|
926
|
-
if (!children || children.length < 2) return '';
|
|
927
|
-
|
|
928
|
-
const baseNode = children[0];
|
|
929
|
-
const overNode = children[1];
|
|
930
|
-
|
|
931
|
-
// Check if nodes exist before accessing
|
|
932
|
-
if (!baseNode || !overNode) return '';
|
|
933
|
-
|
|
934
|
-
const overText = NodeTool.getNodeText(overNode)?.trim() || '';
|
|
935
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
936
|
-
|
|
937
|
-
// Handle vector notation
|
|
938
|
-
if (overText === "→" && isAccent) {
|
|
939
|
-
return `\\vec{${parse(baseNode)}}`;
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
return parse(baseNode);
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
function renderMfenced(node, children) {
|
|
946
|
-
const [open, close, separatorsStr] = [
|
|
947
|
-
NodeTool.getAttr(node, 'open', '('),
|
|
948
|
-
NodeTool.getAttr(node, 'close', ')'),
|
|
949
|
-
NodeTool.getAttr(node, 'separators', ',')
|
|
950
|
-
];
|
|
951
|
-
|
|
952
|
-
const parts = renderChildren(children);
|
|
953
|
-
const content = parts.join(separatorsStr === '|' ? ',' : separatorsStr).trim();
|
|
954
|
-
|
|
955
|
-
// Handle nested absolute value cases
|
|
956
|
-
if (open === '|' && close === '') {
|
|
957
|
-
return `\\left|${content}`;
|
|
958
|
-
}
|
|
959
|
-
if (open === '' && close === '|') {
|
|
960
|
-
return `${content}\\right|`;
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
// Handle system of equations with curly brace
|
|
964
|
-
if (open === '{') {
|
|
965
|
-
return `\\left\\{${content}${close ? '\\right\\}' : '\\right.'}`;
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
// Handle regular absolute value notation
|
|
969
|
-
if (open === '|' && close === '|') {
|
|
970
|
-
return `\\left|${content}\\right|`;
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
// Regular cases with proper closing
|
|
974
|
-
return `\\left${open}${content}\\right${close || '.'}`;
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
function renderMfrac(node, children){
|
|
978
|
-
const [linethickness, bevelled] = [
|
|
979
|
-
NodeTool.getAttr(node, 'linethickness', 'medium'),
|
|
980
|
-
NodeTool.getAttr(node, 'bevelled', 'false')
|
|
981
|
-
];
|
|
982
|
-
|
|
983
|
-
let render = null;
|
|
984
|
-
if(bevelled === 'true') {
|
|
985
|
-
render = getRender_default("{}^{@1}/_{@2}");
|
|
986
|
-
} else if(['0', '0px'].indexOf(linethickness) > -1) {
|
|
987
|
-
const [prevNode, nextNode] = [
|
|
988
|
-
NodeTool.getPrevNode(node),
|
|
989
|
-
NodeTool.getNextNode(node)
|
|
990
|
-
];
|
|
991
|
-
if((prevNode && NodeTool.getNodeText(prevNode).trim() === '(') &&
|
|
992
|
-
(nextNode && NodeTool.getNodeText(nextNode).trim() === ')')
|
|
993
|
-
) {
|
|
994
|
-
render = getRender_default("\\binom{@1}{@2}");
|
|
995
|
-
} else {
|
|
996
|
-
render = getRender_default("\\frac{@1}{@2}");
|
|
997
|
-
}
|
|
998
|
-
} else {
|
|
999
|
-
render = getRender_default("\\frac{@1}{@2}");
|
|
1000
|
-
}
|
|
1001
|
-
return render(node, children);
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
function renderMmultiscripts(node, children) {
|
|
1005
|
-
if(children.length === 0) { return '' }
|
|
1006
|
-
let sepIndex = -1;
|
|
1007
|
-
let mprescriptsNode = null;
|
|
1008
|
-
Array.prototype.forEach.call(children, (node) => {
|
|
1009
|
-
if(NodeTool.getNodeName(node) === 'mprescripts'){
|
|
1010
|
-
mprescriptsNode = node;
|
|
1011
|
-
}
|
|
1012
|
-
});
|
|
1013
|
-
if(mprescriptsNode) {
|
|
1014
|
-
sepIndex = Array.prototype.indexOf.call(children, mprescriptsNode);
|
|
1015
|
-
}
|
|
1016
|
-
const parts = renderChildren(children);
|
|
1017
|
-
|
|
1018
|
-
const splitArray = (arr, index) => {
|
|
1019
|
-
return [arr.slice(0, index), arr.slice(index + 1, arr.length)]
|
|
1020
|
-
};
|
|
1021
|
-
const renderScripts = (items) => {
|
|
1022
|
-
if(items.length > 0) {
|
|
1023
|
-
const subs = [];
|
|
1024
|
-
const sups = [];
|
|
1025
|
-
items.forEach((item, index) => {
|
|
1026
|
-
// one render as sub script, one as super script
|
|
1027
|
-
if((index + 1) % 2 === 0){
|
|
1028
|
-
sups.push(item);
|
|
1029
|
-
} else {
|
|
1030
|
-
subs.push(item);
|
|
1031
|
-
}
|
|
1032
|
-
});
|
|
1033
|
-
return [
|
|
1034
|
-
(subs.length > 0 ? `_{${subs.join(' ')}}` : ''),
|
|
1035
|
-
(sups.length > 0 ? `^{${sups.join(' ')}}` : '')
|
|
1036
|
-
].join('');
|
|
1037
|
-
} else {
|
|
1038
|
-
return '';
|
|
1039
|
-
}
|
|
1040
|
-
};
|
|
1041
|
-
const base = parts.shift();
|
|
1042
|
-
let prevScripts = [];
|
|
1043
|
-
let backScripts = [];
|
|
1044
|
-
if(sepIndex === -1){
|
|
1045
|
-
backScripts = parts;
|
|
1046
|
-
} else {
|
|
1047
|
-
[backScripts, prevScripts] = splitArray(parts, sepIndex - 1);
|
|
1048
|
-
}
|
|
1049
|
-
return [renderScripts(prevScripts), base, renderScripts(backScripts)].join('');
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
function renderMunder(node, children){
|
|
1053
|
-
const nodes = flattenNodeTreeByNodeName(node, 'munder');
|
|
1054
|
-
let result = undefined;
|
|
1055
|
-
for(let i = 0; i < nodes.length - 1; i++) {
|
|
1056
|
-
if(!result){ result = parse(nodes[i]); }
|
|
1057
|
-
|
|
1058
|
-
const underNode = nodes[i + 1];
|
|
1059
|
-
const underText = NodeTool.getNodeText(underNode).trim();
|
|
1060
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1061
|
-
|
|
1062
|
-
// Special handling for arrow accent
|
|
1063
|
-
if (underText === "→" && isAccent) {
|
|
1064
|
-
return `\\underset{${result}}{\\rightarrow}`;
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
const under = parse(underNode);
|
|
1068
|
-
const template = getMatchValueByChar({
|
|
1069
|
-
decimals: MathSymbol.underScript.decimals,
|
|
1070
|
-
values: MathSymbol.underScript.templates,
|
|
1071
|
-
judgeChar: underText,
|
|
1072
|
-
defaultValue: "@1_{@2}"
|
|
1073
|
-
});
|
|
1074
|
-
result = renderTemplate(template.replace("@v", "@1"), [result, under]);
|
|
1075
|
-
}
|
|
1076
|
-
return result;
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
function renderMunderover(node, children){
|
|
1080
|
-
const nodes = flattenNodeTreeByNodeName(node, 'munderover');
|
|
1081
|
-
let result = undefined;
|
|
1082
|
-
for(let i = 0; i < nodes.length - 1; i++) {
|
|
1083
|
-
if(!result){ result = parse(nodes[i]); }
|
|
1084
|
-
|
|
1085
|
-
const overNode = nodes[i + 1];
|
|
1086
|
-
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1087
|
-
const underNode = nodes[i + 2];
|
|
1088
|
-
const underText = NodeTool.getNodeText(underNode).trim();
|
|
1089
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1090
|
-
|
|
1091
|
-
// Special handling for arrow accent
|
|
1092
|
-
if (overText === "→" && isAccent) {
|
|
1093
|
-
return `\\overset{${result}}{\\underset{${underText}}{\\rightarrow}}`;
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
const over = parse(overNode);
|
|
1097
|
-
const under = parse(underNode);
|
|
1098
|
-
const template = getMatchValueByChar({
|
|
1099
|
-
decimals: MathSymbol.underoverScript.decimals,
|
|
1100
|
-
values: MathSymbol.underoverScript.templates,
|
|
1101
|
-
judgeChar: overText,
|
|
1102
|
-
defaultValue: "@1_{@2}^{@3}"
|
|
1103
|
-
});
|
|
1104
|
-
result = renderTemplate(template.replace("@v", "@1"), [over, under]);
|
|
1105
|
-
}
|
|
1106
|
-
return result;
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
|
-
function renderMphantom(node, children){
|
|
1110
|
-
const nodes = flattenNodeTreeByNodeName(node, 'mphantom');
|
|
1111
|
-
let result = undefined;
|
|
1112
|
-
for(let i = 0; i < nodes.length - 1; i++) {
|
|
1113
|
-
if(!result){ result = parse(nodes[i]); }
|
|
1114
|
-
|
|
1115
|
-
const phantomNode = nodes[i + 1];
|
|
1116
|
-
const phantomText = NodeTool.getNodeText(phantomNode).trim();
|
|
1117
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1118
|
-
|
|
1119
|
-
// Special handling for arrow accent
|
|
1120
|
-
if (phantomText === "→" && isAccent) {
|
|
1121
|
-
return `\\overrightarrow{${result}}`;
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
const phantom = parse(phantomNode);
|
|
1125
|
-
const template = getMatchValueByChar({
|
|
1126
|
-
decimals: MathSymbol.phantomScript.decimals,
|
|
1127
|
-
values: MathSymbol.phantomScript.templates,
|
|
1128
|
-
judgeChar: phantomText,
|
|
1129
|
-
defaultValue: "@1^{@2}"
|
|
1130
|
-
});
|
|
1131
|
-
result = renderTemplate(template.replace("@v", "@1"), [result, phantom]);
|
|
1132
|
-
}
|
|
1133
|
-
return result;
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
function renderTemplate(template, args) {
|
|
1137
|
-
return template.replace(/@(\d+)/g, (match, index) => {
|
|
1138
|
-
const arg = args[index - 1];
|
|
1139
|
-
return arg || match;
|
|
1140
|
-
});
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
function getMatchValueByChar(options) {
|
|
1144
|
-
const { decimals, values, judgeChar, defaultValue } = options;
|
|
1145
|
-
const match = values.find(value => value.judgeChar === judgeChar);
|
|
1146
|
-
return match || defaultValue;
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
|
-
function flattenNodeTreeByNodeName(node, nodeName) {
|
|
1150
|
-
const nodes = [];
|
|
1151
|
-
const children = NodeTool.getChildren(node);
|
|
1152
|
-
if (children && children.length > 0) {
|
|
1153
|
-
// Convert HTMLCollection to Array before using forEach
|
|
1154
|
-
Array.from(children).forEach(child => {
|
|
1155
|
-
if (NodeTool.getNodeName(child) === nodeName) {
|
|
1156
|
-
nodes.push(child);
|
|
1157
|
-
} else {
|
|
1158
|
-
// Recursively search in child nodes
|
|
1159
|
-
const childNodes = flattenNodeTreeByNodeName(child, nodeName);
|
|
1160
|
-
nodes.push(...childNodes);
|
|
1161
|
-
}
|
|
1162
|
-
});
|
|
1163
|
-
}
|
|
1164
|
-
return nodes;
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
1291
|
// Export the convert function
|
|
1168
1292
|
var mathml2latex = {
|
|
1169
1293
|
convert: convert
|