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