ed-mathml2tex 0.0.8 → 0.1.0
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 +70 -84
- package/lib/mathml2latex.browser.es.js +70 -84
- package/lib/mathml2latex.browser.umd.js +70 -84
- package/lib/mathml2latex.cjs.js +70 -84
- package/lib/mathml2latex.es.js +70 -84
- package/lib/mathml2latex.umd.js +70 -84
- package/package.json +1 -1
|
@@ -147,7 +147,9 @@ const NodeTool = {
|
|
|
147
147
|
return node.children;
|
|
148
148
|
},
|
|
149
149
|
getNodeName: function(node) {
|
|
150
|
-
|
|
150
|
+
if (!node) return '';
|
|
151
|
+
const localName = node.localName || node.nodeName;
|
|
152
|
+
return localName ? localName.toLowerCase() : '';
|
|
151
153
|
},
|
|
152
154
|
getNodeText: function(node) {
|
|
153
155
|
return node.textContent;
|
|
@@ -704,9 +706,9 @@ function parseLeaf(node) {
|
|
|
704
706
|
function parseOperator(node) {
|
|
705
707
|
let it = NodeTool.getNodeText(node).trim();
|
|
706
708
|
|
|
707
|
-
// Special case for arrow (→)
|
|
709
|
+
// Special case for arrow (→) with proper spacing
|
|
708
710
|
if (it === "→") {
|
|
709
|
-
return "\\rightarrow";
|
|
711
|
+
return " \\rightarrow "; // Add spaces around arrow
|
|
710
712
|
}
|
|
711
713
|
|
|
712
714
|
it = MathSymbol.parseOperator(it);
|
|
@@ -789,6 +791,7 @@ function renderChildren(children) {
|
|
|
789
791
|
if(Brackets.contains(op)){
|
|
790
792
|
let stretchy = NodeTool.getAttr(node, 'stretchy', 'true');
|
|
791
793
|
stretchy = ['', 'true'].indexOf(stretchy) > -1;
|
|
794
|
+
|
|
792
795
|
if(Brackets.isRight(op)){
|
|
793
796
|
const nearLeft = lefts[lefts.length - 1];
|
|
794
797
|
if(nearLeft){
|
|
@@ -796,16 +799,10 @@ function renderChildren(children) {
|
|
|
796
799
|
parts.push(Brackets.parseRight(op, stretchy));
|
|
797
800
|
lefts.pop();
|
|
798
801
|
} 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);
|
|
802
|
+
parts.push(`\\right${op}`);
|
|
808
803
|
}
|
|
804
|
+
} else {
|
|
805
|
+
parts.push(`\\right${op}`);
|
|
809
806
|
}
|
|
810
807
|
} else {
|
|
811
808
|
parts.push(Brackets.parseLeft(op, stretchy));
|
|
@@ -818,10 +815,9 @@ function renderChildren(children) {
|
|
|
818
815
|
parts.push(parse(node));
|
|
819
816
|
}
|
|
820
817
|
});
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
}
|
|
818
|
+
// Only add \right. if there are unmatched left brackets
|
|
819
|
+
if(lefts.length > 0 && !parts.some(p => p.includes('\\right'))) {
|
|
820
|
+
parts.push("\\right.");
|
|
825
821
|
}
|
|
826
822
|
lefts = undefined;
|
|
827
823
|
return parts;
|
|
@@ -833,7 +829,28 @@ function getRender(node) {
|
|
|
833
829
|
const nodeName = NodeTool.getNodeName(node);
|
|
834
830
|
switch(nodeName){
|
|
835
831
|
case 'msub':
|
|
836
|
-
render =
|
|
832
|
+
render = function(node, children) {
|
|
833
|
+
if (!children || children.length < 2) return '';
|
|
834
|
+
|
|
835
|
+
const base = parse(children[0]);
|
|
836
|
+
if (!base) return '';
|
|
837
|
+
|
|
838
|
+
const sub = children[1];
|
|
839
|
+
if (!sub) return base;
|
|
840
|
+
|
|
841
|
+
// Handle nested subscript with empty mrow
|
|
842
|
+
if (NodeTool.getNodeName(sub) === 'msub' &&
|
|
843
|
+
sub.firstChild &&
|
|
844
|
+
NodeTool.getNodeName(sub.firstChild) === 'mrow' &&
|
|
845
|
+
(!NodeTool.getNodeText(sub.firstChild) || NodeTool.getNodeText(sub.firstChild).trim() === '')) {
|
|
846
|
+
const lastChild = sub.lastChild;
|
|
847
|
+
if (!lastChild) return base;
|
|
848
|
+
return `${base}_${parse(lastChild)}`;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// Regular subscript
|
|
852
|
+
return `${base}_{${parse(sub)}}`;
|
|
853
|
+
};
|
|
837
854
|
break;
|
|
838
855
|
case 'msup':
|
|
839
856
|
render = getRender_default("@1^{@2}");
|
|
@@ -895,10 +912,32 @@ function getRender(node) {
|
|
|
895
912
|
|
|
896
913
|
function renderTable(node, children) {
|
|
897
914
|
const template = "\\begin{array}{l}@content\\end{array}";
|
|
898
|
-
|
|
915
|
+
// Remove extra backslash and add proper spacing
|
|
916
|
+
const render = getRender_joinSeparator(template, " \\\\ ");
|
|
899
917
|
return render(node, children);
|
|
900
918
|
}
|
|
901
919
|
|
|
920
|
+
function renderMover(node, children) {
|
|
921
|
+
// Check if children exists and has enough elements
|
|
922
|
+
if (!children || children.length < 2) return '';
|
|
923
|
+
|
|
924
|
+
const baseNode = children[0];
|
|
925
|
+
const overNode = children[1];
|
|
926
|
+
|
|
927
|
+
// Check if nodes exist before accessing
|
|
928
|
+
if (!baseNode || !overNode) return '';
|
|
929
|
+
|
|
930
|
+
const overText = NodeTool.getNodeText(overNode)?.trim() || '';
|
|
931
|
+
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
932
|
+
|
|
933
|
+
// Handle vector notation
|
|
934
|
+
if (overText === "→" && isAccent) {
|
|
935
|
+
return `\\vec{${parse(baseNode)}}`;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
return parse(baseNode);
|
|
939
|
+
}
|
|
940
|
+
|
|
902
941
|
function renderMfenced(node, children) {
|
|
903
942
|
const [open, close, separatorsStr] = [
|
|
904
943
|
NodeTool.getAttr(node, 'open', '('),
|
|
@@ -909,22 +948,25 @@ function renderMfenced(node, children) {
|
|
|
909
948
|
const parts = renderChildren(children);
|
|
910
949
|
const content = parts.join(separatorsStr === '|' ? ',' : separatorsStr).trim();
|
|
911
950
|
|
|
912
|
-
// Handle
|
|
951
|
+
// Handle nested absolute value cases
|
|
952
|
+
if (open === '|' && close === '') {
|
|
953
|
+
return `\\left|${content}`;
|
|
954
|
+
}
|
|
913
955
|
if (open === '' && close === '|') {
|
|
914
|
-
return
|
|
956
|
+
return `${content}\\right|`;
|
|
915
957
|
}
|
|
916
958
|
|
|
917
|
-
// Handle
|
|
918
|
-
if (open === '
|
|
919
|
-
return `\\left
|
|
959
|
+
// Handle system of equations with curly brace
|
|
960
|
+
if (open === '{') {
|
|
961
|
+
return `\\left\\{${content}${close ? '\\right\\}' : '\\right.'}`;
|
|
920
962
|
}
|
|
921
|
-
|
|
922
|
-
//
|
|
923
|
-
if (open === '
|
|
924
|
-
return `\\left
|
|
963
|
+
|
|
964
|
+
// Handle regular absolute value notation
|
|
965
|
+
if (open === '|' && close === '|') {
|
|
966
|
+
return `\\left|${content}\\right|`;
|
|
925
967
|
}
|
|
926
968
|
|
|
927
|
-
//
|
|
969
|
+
// Regular cases with proper closing
|
|
928
970
|
return `\\left${open}${content}\\right${close || '.'}`;
|
|
929
971
|
}
|
|
930
972
|
|
|
@@ -1003,62 +1045,6 @@ function renderMmultiscripts(node, children) {
|
|
|
1003
1045
|
return [renderScripts(prevScripts), base, renderScripts(backScripts)].join('');
|
|
1004
1046
|
}
|
|
1005
1047
|
|
|
1006
|
-
function renderMover(node, children) {
|
|
1007
|
-
const nodes = flattenNodeTreeByNodeName(node, 'mover');
|
|
1008
|
-
let result = undefined;
|
|
1009
|
-
|
|
1010
|
-
// Get the base node and check if it's a subscript or mrow
|
|
1011
|
-
const baseNode = children[0];
|
|
1012
|
-
const overNode = children[1];
|
|
1013
|
-
const nodeName = NodeTool.getNodeName(baseNode);
|
|
1014
|
-
const isSubscript = nodeName === 'msub';
|
|
1015
|
-
const isMrow = nodeName === 'mrow';
|
|
1016
|
-
|
|
1017
|
-
// Handle case where the base is an arrow and mrow is above
|
|
1018
|
-
const baseText = NodeTool.getNodeText(baseNode).trim();
|
|
1019
|
-
if (baseText === "→" && NodeTool.getNodeName(overNode) === "mrow") {
|
|
1020
|
-
return "\\rightarrow";
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
if (isSubscript) {
|
|
1024
|
-
// Handle case like n₂ with arrow
|
|
1025
|
-
const base = parse(baseNode);
|
|
1026
|
-
return `\\overrightarrow{${base}}`;
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
if (isMrow) {
|
|
1030
|
-
// Handle case like 0 with arrow
|
|
1031
|
-
const base = parse(baseNode);
|
|
1032
|
-
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1033
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1034
|
-
|
|
1035
|
-
if (overText === "→" && isAccent) {
|
|
1036
|
-
return `\\overrightarrow{${base}}`;
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
// Handle case where there is only an arrow with no base
|
|
1041
|
-
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1042
|
-
if (overText === "→" && NodeTool.getNodeText(baseNode).trim() === "") {
|
|
1043
|
-
return `\\rightarrow`; // Return just the arrow
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
for (let i = 0; i < nodes.length - 1; i++) {
|
|
1047
|
-
if (!result) {
|
|
1048
|
-
result = parse(nodes[i]);
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
const _overNode = nodes[i + 1];
|
|
1052
|
-
const overText = NodeTool.getNodeText(_overNode).trim();
|
|
1053
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1054
|
-
|
|
1055
|
-
if (overText === "→" && isAccent) {
|
|
1056
|
-
return `\\overrightarrow{${result}}`;
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
return result;
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
1048
|
function renderMunder(node, children){
|
|
1063
1049
|
const nodes = flattenNodeTreeByNodeName(node, 'munder');
|
|
1064
1050
|
let result = undefined;
|
|
@@ -145,7 +145,9 @@ const NodeTool = {
|
|
|
145
145
|
return node.children;
|
|
146
146
|
},
|
|
147
147
|
getNodeName: function(node) {
|
|
148
|
-
|
|
148
|
+
if (!node) return '';
|
|
149
|
+
const localName = node.localName || node.nodeName;
|
|
150
|
+
return localName ? localName.toLowerCase() : '';
|
|
149
151
|
},
|
|
150
152
|
getNodeText: function(node) {
|
|
151
153
|
return node.textContent;
|
|
@@ -702,9 +704,9 @@ function parseLeaf(node) {
|
|
|
702
704
|
function parseOperator(node) {
|
|
703
705
|
let it = NodeTool.getNodeText(node).trim();
|
|
704
706
|
|
|
705
|
-
// Special case for arrow (→)
|
|
707
|
+
// Special case for arrow (→) with proper spacing
|
|
706
708
|
if (it === "→") {
|
|
707
|
-
return "\\rightarrow";
|
|
709
|
+
return " \\rightarrow "; // Add spaces around arrow
|
|
708
710
|
}
|
|
709
711
|
|
|
710
712
|
it = MathSymbol.parseOperator(it);
|
|
@@ -787,6 +789,7 @@ function renderChildren(children) {
|
|
|
787
789
|
if(Brackets.contains(op)){
|
|
788
790
|
let stretchy = NodeTool.getAttr(node, 'stretchy', 'true');
|
|
789
791
|
stretchy = ['', 'true'].indexOf(stretchy) > -1;
|
|
792
|
+
|
|
790
793
|
if(Brackets.isRight(op)){
|
|
791
794
|
const nearLeft = lefts[lefts.length - 1];
|
|
792
795
|
if(nearLeft){
|
|
@@ -794,16 +797,10 @@ function renderChildren(children) {
|
|
|
794
797
|
parts.push(Brackets.parseRight(op, stretchy));
|
|
795
798
|
lefts.pop();
|
|
796
799
|
} else {
|
|
797
|
-
|
|
798
|
-
parts.push(Brackets.parseLeft(op, stretchy));
|
|
799
|
-
lefts.push(op);
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
}else {
|
|
803
|
-
if(Brackets.isLeft(op)) {
|
|
804
|
-
parts.push(Brackets.parseLeft(op, stretchy));
|
|
805
|
-
lefts.push(op);
|
|
800
|
+
parts.push(`\\right${op}`);
|
|
806
801
|
}
|
|
802
|
+
} else {
|
|
803
|
+
parts.push(`\\right${op}`);
|
|
807
804
|
}
|
|
808
805
|
} else {
|
|
809
806
|
parts.push(Brackets.parseLeft(op, stretchy));
|
|
@@ -816,10 +813,9 @@ function renderChildren(children) {
|
|
|
816
813
|
parts.push(parse(node));
|
|
817
814
|
}
|
|
818
815
|
});
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
}
|
|
816
|
+
// Only add \right. if there are unmatched left brackets
|
|
817
|
+
if(lefts.length > 0 && !parts.some(p => p.includes('\\right'))) {
|
|
818
|
+
parts.push("\\right.");
|
|
823
819
|
}
|
|
824
820
|
lefts = undefined;
|
|
825
821
|
return parts;
|
|
@@ -831,7 +827,28 @@ function getRender(node) {
|
|
|
831
827
|
const nodeName = NodeTool.getNodeName(node);
|
|
832
828
|
switch(nodeName){
|
|
833
829
|
case 'msub':
|
|
834
|
-
render =
|
|
830
|
+
render = function(node, children) {
|
|
831
|
+
if (!children || children.length < 2) return '';
|
|
832
|
+
|
|
833
|
+
const base = parse(children[0]);
|
|
834
|
+
if (!base) return '';
|
|
835
|
+
|
|
836
|
+
const sub = children[1];
|
|
837
|
+
if (!sub) return base;
|
|
838
|
+
|
|
839
|
+
// Handle nested subscript with empty mrow
|
|
840
|
+
if (NodeTool.getNodeName(sub) === 'msub' &&
|
|
841
|
+
sub.firstChild &&
|
|
842
|
+
NodeTool.getNodeName(sub.firstChild) === 'mrow' &&
|
|
843
|
+
(!NodeTool.getNodeText(sub.firstChild) || NodeTool.getNodeText(sub.firstChild).trim() === '')) {
|
|
844
|
+
const lastChild = sub.lastChild;
|
|
845
|
+
if (!lastChild) return base;
|
|
846
|
+
return `${base}_${parse(lastChild)}`;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// Regular subscript
|
|
850
|
+
return `${base}_{${parse(sub)}}`;
|
|
851
|
+
};
|
|
835
852
|
break;
|
|
836
853
|
case 'msup':
|
|
837
854
|
render = getRender_default("@1^{@2}");
|
|
@@ -893,10 +910,32 @@ function getRender(node) {
|
|
|
893
910
|
|
|
894
911
|
function renderTable(node, children) {
|
|
895
912
|
const template = "\\begin{array}{l}@content\\end{array}";
|
|
896
|
-
|
|
913
|
+
// Remove extra backslash and add proper spacing
|
|
914
|
+
const render = getRender_joinSeparator(template, " \\\\ ");
|
|
897
915
|
return render(node, children);
|
|
898
916
|
}
|
|
899
917
|
|
|
918
|
+
function renderMover(node, children) {
|
|
919
|
+
// Check if children exists and has enough elements
|
|
920
|
+
if (!children || children.length < 2) return '';
|
|
921
|
+
|
|
922
|
+
const baseNode = children[0];
|
|
923
|
+
const overNode = children[1];
|
|
924
|
+
|
|
925
|
+
// Check if nodes exist before accessing
|
|
926
|
+
if (!baseNode || !overNode) return '';
|
|
927
|
+
|
|
928
|
+
const overText = NodeTool.getNodeText(overNode)?.trim() || '';
|
|
929
|
+
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
930
|
+
|
|
931
|
+
// Handle vector notation
|
|
932
|
+
if (overText === "→" && isAccent) {
|
|
933
|
+
return `\\vec{${parse(baseNode)}}`;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return parse(baseNode);
|
|
937
|
+
}
|
|
938
|
+
|
|
900
939
|
function renderMfenced(node, children) {
|
|
901
940
|
const [open, close, separatorsStr] = [
|
|
902
941
|
NodeTool.getAttr(node, 'open', '('),
|
|
@@ -907,22 +946,25 @@ function renderMfenced(node, children) {
|
|
|
907
946
|
const parts = renderChildren(children);
|
|
908
947
|
const content = parts.join(separatorsStr === '|' ? ',' : separatorsStr).trim();
|
|
909
948
|
|
|
910
|
-
// Handle
|
|
949
|
+
// Handle nested absolute value cases
|
|
950
|
+
if (open === '|' && close === '') {
|
|
951
|
+
return `\\left|${content}`;
|
|
952
|
+
}
|
|
911
953
|
if (open === '' && close === '|') {
|
|
912
|
-
return
|
|
954
|
+
return `${content}\\right|`;
|
|
913
955
|
}
|
|
914
956
|
|
|
915
|
-
// Handle
|
|
916
|
-
if (open === '
|
|
917
|
-
return `\\left
|
|
957
|
+
// Handle system of equations with curly brace
|
|
958
|
+
if (open === '{') {
|
|
959
|
+
return `\\left\\{${content}${close ? '\\right\\}' : '\\right.'}`;
|
|
918
960
|
}
|
|
919
|
-
|
|
920
|
-
//
|
|
921
|
-
if (open === '
|
|
922
|
-
return `\\left
|
|
961
|
+
|
|
962
|
+
// Handle regular absolute value notation
|
|
963
|
+
if (open === '|' && close === '|') {
|
|
964
|
+
return `\\left|${content}\\right|`;
|
|
923
965
|
}
|
|
924
966
|
|
|
925
|
-
//
|
|
967
|
+
// Regular cases with proper closing
|
|
926
968
|
return `\\left${open}${content}\\right${close || '.'}`;
|
|
927
969
|
}
|
|
928
970
|
|
|
@@ -1001,62 +1043,6 @@ function renderMmultiscripts(node, children) {
|
|
|
1001
1043
|
return [renderScripts(prevScripts), base, renderScripts(backScripts)].join('');
|
|
1002
1044
|
}
|
|
1003
1045
|
|
|
1004
|
-
function renderMover(node, children) {
|
|
1005
|
-
const nodes = flattenNodeTreeByNodeName(node, 'mover');
|
|
1006
|
-
let result = undefined;
|
|
1007
|
-
|
|
1008
|
-
// Get the base node and check if it's a subscript or mrow
|
|
1009
|
-
const baseNode = children[0];
|
|
1010
|
-
const overNode = children[1];
|
|
1011
|
-
const nodeName = NodeTool.getNodeName(baseNode);
|
|
1012
|
-
const isSubscript = nodeName === 'msub';
|
|
1013
|
-
const isMrow = nodeName === 'mrow';
|
|
1014
|
-
|
|
1015
|
-
// Handle case where the base is an arrow and mrow is above
|
|
1016
|
-
const baseText = NodeTool.getNodeText(baseNode).trim();
|
|
1017
|
-
if (baseText === "→" && NodeTool.getNodeName(overNode) === "mrow") {
|
|
1018
|
-
return "\\rightarrow";
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
if (isSubscript) {
|
|
1022
|
-
// Handle case like n₂ with arrow
|
|
1023
|
-
const base = parse(baseNode);
|
|
1024
|
-
return `\\overrightarrow{${base}}`;
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
if (isMrow) {
|
|
1028
|
-
// Handle case like 0 with arrow
|
|
1029
|
-
const base = parse(baseNode);
|
|
1030
|
-
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1031
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1032
|
-
|
|
1033
|
-
if (overText === "→" && isAccent) {
|
|
1034
|
-
return `\\overrightarrow{${base}}`;
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
// Handle case where there is only an arrow with no base
|
|
1039
|
-
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1040
|
-
if (overText === "→" && NodeTool.getNodeText(baseNode).trim() === "") {
|
|
1041
|
-
return `\\rightarrow`; // Return just the arrow
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
for (let i = 0; i < nodes.length - 1; i++) {
|
|
1045
|
-
if (!result) {
|
|
1046
|
-
result = parse(nodes[i]);
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
const _overNode = nodes[i + 1];
|
|
1050
|
-
const overText = NodeTool.getNodeText(_overNode).trim();
|
|
1051
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1052
|
-
|
|
1053
|
-
if (overText === "→" && isAccent) {
|
|
1054
|
-
return `\\overrightarrow{${result}}`;
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
return result;
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
1046
|
function renderMunder(node, children){
|
|
1061
1047
|
const nodes = flattenNodeTreeByNodeName(node, 'munder');
|
|
1062
1048
|
let result = undefined;
|
|
@@ -151,7 +151,9 @@
|
|
|
151
151
|
return node.children;
|
|
152
152
|
},
|
|
153
153
|
getNodeName: function(node) {
|
|
154
|
-
|
|
154
|
+
if (!node) return '';
|
|
155
|
+
const localName = node.localName || node.nodeName;
|
|
156
|
+
return localName ? localName.toLowerCase() : '';
|
|
155
157
|
},
|
|
156
158
|
getNodeText: function(node) {
|
|
157
159
|
return node.textContent;
|
|
@@ -708,9 +710,9 @@
|
|
|
708
710
|
function parseOperator(node) {
|
|
709
711
|
let it = NodeTool.getNodeText(node).trim();
|
|
710
712
|
|
|
711
|
-
// Special case for arrow (→)
|
|
713
|
+
// Special case for arrow (→) with proper spacing
|
|
712
714
|
if (it === "→") {
|
|
713
|
-
return "\\rightarrow";
|
|
715
|
+
return " \\rightarrow "; // Add spaces around arrow
|
|
714
716
|
}
|
|
715
717
|
|
|
716
718
|
it = MathSymbol.parseOperator(it);
|
|
@@ -793,6 +795,7 @@
|
|
|
793
795
|
if(Brackets.contains(op)){
|
|
794
796
|
let stretchy = NodeTool.getAttr(node, 'stretchy', 'true');
|
|
795
797
|
stretchy = ['', 'true'].indexOf(stretchy) > -1;
|
|
798
|
+
|
|
796
799
|
if(Brackets.isRight(op)){
|
|
797
800
|
const nearLeft = lefts[lefts.length - 1];
|
|
798
801
|
if(nearLeft){
|
|
@@ -800,16 +803,10 @@
|
|
|
800
803
|
parts.push(Brackets.parseRight(op, stretchy));
|
|
801
804
|
lefts.pop();
|
|
802
805
|
} else {
|
|
803
|
-
|
|
804
|
-
parts.push(Brackets.parseLeft(op, stretchy));
|
|
805
|
-
lefts.push(op);
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
}else {
|
|
809
|
-
if(Brackets.isLeft(op)) {
|
|
810
|
-
parts.push(Brackets.parseLeft(op, stretchy));
|
|
811
|
-
lefts.push(op);
|
|
806
|
+
parts.push(`\\right${op}`);
|
|
812
807
|
}
|
|
808
|
+
} else {
|
|
809
|
+
parts.push(`\\right${op}`);
|
|
813
810
|
}
|
|
814
811
|
} else {
|
|
815
812
|
parts.push(Brackets.parseLeft(op, stretchy));
|
|
@@ -822,10 +819,9 @@
|
|
|
822
819
|
parts.push(parse(node));
|
|
823
820
|
}
|
|
824
821
|
});
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
}
|
|
822
|
+
// Only add \right. if there are unmatched left brackets
|
|
823
|
+
if(lefts.length > 0 && !parts.some(p => p.includes('\\right'))) {
|
|
824
|
+
parts.push("\\right.");
|
|
829
825
|
}
|
|
830
826
|
lefts = undefined;
|
|
831
827
|
return parts;
|
|
@@ -837,7 +833,28 @@
|
|
|
837
833
|
const nodeName = NodeTool.getNodeName(node);
|
|
838
834
|
switch(nodeName){
|
|
839
835
|
case 'msub':
|
|
840
|
-
render =
|
|
836
|
+
render = function(node, children) {
|
|
837
|
+
if (!children || children.length < 2) return '';
|
|
838
|
+
|
|
839
|
+
const base = parse(children[0]);
|
|
840
|
+
if (!base) return '';
|
|
841
|
+
|
|
842
|
+
const sub = children[1];
|
|
843
|
+
if (!sub) return base;
|
|
844
|
+
|
|
845
|
+
// Handle nested subscript with empty mrow
|
|
846
|
+
if (NodeTool.getNodeName(sub) === 'msub' &&
|
|
847
|
+
sub.firstChild &&
|
|
848
|
+
NodeTool.getNodeName(sub.firstChild) === 'mrow' &&
|
|
849
|
+
(!NodeTool.getNodeText(sub.firstChild) || NodeTool.getNodeText(sub.firstChild).trim() === '')) {
|
|
850
|
+
const lastChild = sub.lastChild;
|
|
851
|
+
if (!lastChild) return base;
|
|
852
|
+
return `${base}_${parse(lastChild)}`;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// Regular subscript
|
|
856
|
+
return `${base}_{${parse(sub)}}`;
|
|
857
|
+
};
|
|
841
858
|
break;
|
|
842
859
|
case 'msup':
|
|
843
860
|
render = getRender_default("@1^{@2}");
|
|
@@ -899,10 +916,32 @@
|
|
|
899
916
|
|
|
900
917
|
function renderTable(node, children) {
|
|
901
918
|
const template = "\\begin{array}{l}@content\\end{array}";
|
|
902
|
-
|
|
919
|
+
// Remove extra backslash and add proper spacing
|
|
920
|
+
const render = getRender_joinSeparator(template, " \\\\ ");
|
|
903
921
|
return render(node, children);
|
|
904
922
|
}
|
|
905
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
|
+
|
|
906
945
|
function renderMfenced(node, children) {
|
|
907
946
|
const [open, close, separatorsStr] = [
|
|
908
947
|
NodeTool.getAttr(node, 'open', '('),
|
|
@@ -913,22 +952,25 @@
|
|
|
913
952
|
const parts = renderChildren(children);
|
|
914
953
|
const content = parts.join(separatorsStr === '|' ? ',' : separatorsStr).trim();
|
|
915
954
|
|
|
916
|
-
// Handle
|
|
955
|
+
// Handle nested absolute value cases
|
|
956
|
+
if (open === '|' && close === '') {
|
|
957
|
+
return `\\left|${content}`;
|
|
958
|
+
}
|
|
917
959
|
if (open === '' && close === '|') {
|
|
918
|
-
return
|
|
960
|
+
return `${content}\\right|`;
|
|
919
961
|
}
|
|
920
962
|
|
|
921
|
-
// Handle
|
|
922
|
-
if (open === '
|
|
923
|
-
return `\\left
|
|
963
|
+
// Handle system of equations with curly brace
|
|
964
|
+
if (open === '{') {
|
|
965
|
+
return `\\left\\{${content}${close ? '\\right\\}' : '\\right.'}`;
|
|
924
966
|
}
|
|
925
|
-
|
|
926
|
-
//
|
|
927
|
-
if (open === '
|
|
928
|
-
return `\\left
|
|
967
|
+
|
|
968
|
+
// Handle regular absolute value notation
|
|
969
|
+
if (open === '|' && close === '|') {
|
|
970
|
+
return `\\left|${content}\\right|`;
|
|
929
971
|
}
|
|
930
972
|
|
|
931
|
-
//
|
|
973
|
+
// Regular cases with proper closing
|
|
932
974
|
return `\\left${open}${content}\\right${close || '.'}`;
|
|
933
975
|
}
|
|
934
976
|
|
|
@@ -1007,62 +1049,6 @@
|
|
|
1007
1049
|
return [renderScripts(prevScripts), base, renderScripts(backScripts)].join('');
|
|
1008
1050
|
}
|
|
1009
1051
|
|
|
1010
|
-
function renderMover(node, children) {
|
|
1011
|
-
const nodes = flattenNodeTreeByNodeName(node, 'mover');
|
|
1012
|
-
let result = undefined;
|
|
1013
|
-
|
|
1014
|
-
// Get the base node and check if it's a subscript or mrow
|
|
1015
|
-
const baseNode = children[0];
|
|
1016
|
-
const overNode = children[1];
|
|
1017
|
-
const nodeName = NodeTool.getNodeName(baseNode);
|
|
1018
|
-
const isSubscript = nodeName === 'msub';
|
|
1019
|
-
const isMrow = nodeName === 'mrow';
|
|
1020
|
-
|
|
1021
|
-
// Handle case where the base is an arrow and mrow is above
|
|
1022
|
-
const baseText = NodeTool.getNodeText(baseNode).trim();
|
|
1023
|
-
if (baseText === "→" && NodeTool.getNodeName(overNode) === "mrow") {
|
|
1024
|
-
return "\\rightarrow";
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
if (isSubscript) {
|
|
1028
|
-
// Handle case like n₂ with arrow
|
|
1029
|
-
const base = parse(baseNode);
|
|
1030
|
-
return `\\overrightarrow{${base}}`;
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
if (isMrow) {
|
|
1034
|
-
// Handle case like 0 with arrow
|
|
1035
|
-
const base = parse(baseNode);
|
|
1036
|
-
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1037
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1038
|
-
|
|
1039
|
-
if (overText === "→" && isAccent) {
|
|
1040
|
-
return `\\overrightarrow{${base}}`;
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
// Handle case where there is only an arrow with no base
|
|
1045
|
-
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1046
|
-
if (overText === "→" && NodeTool.getNodeText(baseNode).trim() === "") {
|
|
1047
|
-
return `\\rightarrow`; // Return just the arrow
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
for (let i = 0; i < nodes.length - 1; i++) {
|
|
1051
|
-
if (!result) {
|
|
1052
|
-
result = parse(nodes[i]);
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
|
-
const _overNode = nodes[i + 1];
|
|
1056
|
-
const overText = NodeTool.getNodeText(_overNode).trim();
|
|
1057
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1058
|
-
|
|
1059
|
-
if (overText === "→" && isAccent) {
|
|
1060
|
-
return `\\overrightarrow{${result}}`;
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
return result;
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
1052
|
function renderMunder(node, children){
|
|
1067
1053
|
const nodes = flattenNodeTreeByNodeName(node, 'munder');
|
|
1068
1054
|
let result = undefined;
|
package/lib/mathml2latex.cjs.js
CHANGED
|
@@ -147,7 +147,9 @@ const NodeTool = {
|
|
|
147
147
|
return node.children;
|
|
148
148
|
},
|
|
149
149
|
getNodeName: function(node) {
|
|
150
|
-
|
|
150
|
+
if (!node) return '';
|
|
151
|
+
const localName = node.localName || node.nodeName;
|
|
152
|
+
return localName ? localName.toLowerCase() : '';
|
|
151
153
|
},
|
|
152
154
|
getNodeText: function(node) {
|
|
153
155
|
return node.textContent;
|
|
@@ -704,9 +706,9 @@ function parseLeaf(node) {
|
|
|
704
706
|
function parseOperator(node) {
|
|
705
707
|
let it = NodeTool.getNodeText(node).trim();
|
|
706
708
|
|
|
707
|
-
// Special case for arrow (→)
|
|
709
|
+
// Special case for arrow (→) with proper spacing
|
|
708
710
|
if (it === "→") {
|
|
709
|
-
return "\\rightarrow";
|
|
711
|
+
return " \\rightarrow "; // Add spaces around arrow
|
|
710
712
|
}
|
|
711
713
|
|
|
712
714
|
it = MathSymbol.parseOperator(it);
|
|
@@ -789,6 +791,7 @@ function renderChildren(children) {
|
|
|
789
791
|
if(Brackets.contains(op)){
|
|
790
792
|
let stretchy = NodeTool.getAttr(node, 'stretchy', 'true');
|
|
791
793
|
stretchy = ['', 'true'].indexOf(stretchy) > -1;
|
|
794
|
+
|
|
792
795
|
if(Brackets.isRight(op)){
|
|
793
796
|
const nearLeft = lefts[lefts.length - 1];
|
|
794
797
|
if(nearLeft){
|
|
@@ -796,16 +799,10 @@ function renderChildren(children) {
|
|
|
796
799
|
parts.push(Brackets.parseRight(op, stretchy));
|
|
797
800
|
lefts.pop();
|
|
798
801
|
} 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);
|
|
802
|
+
parts.push(`\\right${op}`);
|
|
808
803
|
}
|
|
804
|
+
} else {
|
|
805
|
+
parts.push(`\\right${op}`);
|
|
809
806
|
}
|
|
810
807
|
} else {
|
|
811
808
|
parts.push(Brackets.parseLeft(op, stretchy));
|
|
@@ -818,10 +815,9 @@ function renderChildren(children) {
|
|
|
818
815
|
parts.push(parse(node));
|
|
819
816
|
}
|
|
820
817
|
});
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
}
|
|
818
|
+
// Only add \right. if there are unmatched left brackets
|
|
819
|
+
if(lefts.length > 0 && !parts.some(p => p.includes('\\right'))) {
|
|
820
|
+
parts.push("\\right.");
|
|
825
821
|
}
|
|
826
822
|
lefts = undefined;
|
|
827
823
|
return parts;
|
|
@@ -833,7 +829,28 @@ function getRender(node) {
|
|
|
833
829
|
const nodeName = NodeTool.getNodeName(node);
|
|
834
830
|
switch(nodeName){
|
|
835
831
|
case 'msub':
|
|
836
|
-
render =
|
|
832
|
+
render = function(node, children) {
|
|
833
|
+
if (!children || children.length < 2) return '';
|
|
834
|
+
|
|
835
|
+
const base = parse(children[0]);
|
|
836
|
+
if (!base) return '';
|
|
837
|
+
|
|
838
|
+
const sub = children[1];
|
|
839
|
+
if (!sub) return base;
|
|
840
|
+
|
|
841
|
+
// Handle nested subscript with empty mrow
|
|
842
|
+
if (NodeTool.getNodeName(sub) === 'msub' &&
|
|
843
|
+
sub.firstChild &&
|
|
844
|
+
NodeTool.getNodeName(sub.firstChild) === 'mrow' &&
|
|
845
|
+
(!NodeTool.getNodeText(sub.firstChild) || NodeTool.getNodeText(sub.firstChild).trim() === '')) {
|
|
846
|
+
const lastChild = sub.lastChild;
|
|
847
|
+
if (!lastChild) return base;
|
|
848
|
+
return `${base}_${parse(lastChild)}`;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// Regular subscript
|
|
852
|
+
return `${base}_{${parse(sub)}}`;
|
|
853
|
+
};
|
|
837
854
|
break;
|
|
838
855
|
case 'msup':
|
|
839
856
|
render = getRender_default("@1^{@2}");
|
|
@@ -895,10 +912,32 @@ function getRender(node) {
|
|
|
895
912
|
|
|
896
913
|
function renderTable(node, children) {
|
|
897
914
|
const template = "\\begin{array}{l}@content\\end{array}";
|
|
898
|
-
|
|
915
|
+
// Remove extra backslash and add proper spacing
|
|
916
|
+
const render = getRender_joinSeparator(template, " \\\\ ");
|
|
899
917
|
return render(node, children);
|
|
900
918
|
}
|
|
901
919
|
|
|
920
|
+
function renderMover(node, children) {
|
|
921
|
+
// Check if children exists and has enough elements
|
|
922
|
+
if (!children || children.length < 2) return '';
|
|
923
|
+
|
|
924
|
+
const baseNode = children[0];
|
|
925
|
+
const overNode = children[1];
|
|
926
|
+
|
|
927
|
+
// Check if nodes exist before accessing
|
|
928
|
+
if (!baseNode || !overNode) return '';
|
|
929
|
+
|
|
930
|
+
const overText = NodeTool.getNodeText(overNode)?.trim() || '';
|
|
931
|
+
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
932
|
+
|
|
933
|
+
// Handle vector notation
|
|
934
|
+
if (overText === "→" && isAccent) {
|
|
935
|
+
return `\\vec{${parse(baseNode)}}`;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
return parse(baseNode);
|
|
939
|
+
}
|
|
940
|
+
|
|
902
941
|
function renderMfenced(node, children) {
|
|
903
942
|
const [open, close, separatorsStr] = [
|
|
904
943
|
NodeTool.getAttr(node, 'open', '('),
|
|
@@ -909,22 +948,25 @@ function renderMfenced(node, children) {
|
|
|
909
948
|
const parts = renderChildren(children);
|
|
910
949
|
const content = parts.join(separatorsStr === '|' ? ',' : separatorsStr).trim();
|
|
911
950
|
|
|
912
|
-
// Handle
|
|
951
|
+
// Handle nested absolute value cases
|
|
952
|
+
if (open === '|' && close === '') {
|
|
953
|
+
return `\\left|${content}`;
|
|
954
|
+
}
|
|
913
955
|
if (open === '' && close === '|') {
|
|
914
|
-
return
|
|
956
|
+
return `${content}\\right|`;
|
|
915
957
|
}
|
|
916
958
|
|
|
917
|
-
// Handle
|
|
918
|
-
if (open === '
|
|
919
|
-
return `\\left
|
|
959
|
+
// Handle system of equations with curly brace
|
|
960
|
+
if (open === '{') {
|
|
961
|
+
return `\\left\\{${content}${close ? '\\right\\}' : '\\right.'}`;
|
|
920
962
|
}
|
|
921
|
-
|
|
922
|
-
//
|
|
923
|
-
if (open === '
|
|
924
|
-
return `\\left
|
|
963
|
+
|
|
964
|
+
// Handle regular absolute value notation
|
|
965
|
+
if (open === '|' && close === '|') {
|
|
966
|
+
return `\\left|${content}\\right|`;
|
|
925
967
|
}
|
|
926
968
|
|
|
927
|
-
//
|
|
969
|
+
// Regular cases with proper closing
|
|
928
970
|
return `\\left${open}${content}\\right${close || '.'}`;
|
|
929
971
|
}
|
|
930
972
|
|
|
@@ -1003,62 +1045,6 @@ function renderMmultiscripts(node, children) {
|
|
|
1003
1045
|
return [renderScripts(prevScripts), base, renderScripts(backScripts)].join('');
|
|
1004
1046
|
}
|
|
1005
1047
|
|
|
1006
|
-
function renderMover(node, children) {
|
|
1007
|
-
const nodes = flattenNodeTreeByNodeName(node, 'mover');
|
|
1008
|
-
let result = undefined;
|
|
1009
|
-
|
|
1010
|
-
// Get the base node and check if it's a subscript or mrow
|
|
1011
|
-
const baseNode = children[0];
|
|
1012
|
-
const overNode = children[1];
|
|
1013
|
-
const nodeName = NodeTool.getNodeName(baseNode);
|
|
1014
|
-
const isSubscript = nodeName === 'msub';
|
|
1015
|
-
const isMrow = nodeName === 'mrow';
|
|
1016
|
-
|
|
1017
|
-
// Handle case where the base is an arrow and mrow is above
|
|
1018
|
-
const baseText = NodeTool.getNodeText(baseNode).trim();
|
|
1019
|
-
if (baseText === "→" && NodeTool.getNodeName(overNode) === "mrow") {
|
|
1020
|
-
return "\\rightarrow";
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
if (isSubscript) {
|
|
1024
|
-
// Handle case like n₂ with arrow
|
|
1025
|
-
const base = parse(baseNode);
|
|
1026
|
-
return `\\overrightarrow{${base}}`;
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
if (isMrow) {
|
|
1030
|
-
// Handle case like 0 with arrow
|
|
1031
|
-
const base = parse(baseNode);
|
|
1032
|
-
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1033
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1034
|
-
|
|
1035
|
-
if (overText === "→" && isAccent) {
|
|
1036
|
-
return `\\overrightarrow{${base}}`;
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
// Handle case where there is only an arrow with no base
|
|
1041
|
-
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1042
|
-
if (overText === "→" && NodeTool.getNodeText(baseNode).trim() === "") {
|
|
1043
|
-
return `\\rightarrow`; // Return just the arrow
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
for (let i = 0; i < nodes.length - 1; i++) {
|
|
1047
|
-
if (!result) {
|
|
1048
|
-
result = parse(nodes[i]);
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
const _overNode = nodes[i + 1];
|
|
1052
|
-
const overText = NodeTool.getNodeText(_overNode).trim();
|
|
1053
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1054
|
-
|
|
1055
|
-
if (overText === "→" && isAccent) {
|
|
1056
|
-
return `\\overrightarrow{${result}}`;
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
return result;
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
1048
|
function renderMunder(node, children){
|
|
1063
1049
|
const nodes = flattenNodeTreeByNodeName(node, 'munder');
|
|
1064
1050
|
let result = undefined;
|
package/lib/mathml2latex.es.js
CHANGED
|
@@ -145,7 +145,9 @@ const NodeTool = {
|
|
|
145
145
|
return node.children;
|
|
146
146
|
},
|
|
147
147
|
getNodeName: function(node) {
|
|
148
|
-
|
|
148
|
+
if (!node) return '';
|
|
149
|
+
const localName = node.localName || node.nodeName;
|
|
150
|
+
return localName ? localName.toLowerCase() : '';
|
|
149
151
|
},
|
|
150
152
|
getNodeText: function(node) {
|
|
151
153
|
return node.textContent;
|
|
@@ -702,9 +704,9 @@ function parseLeaf(node) {
|
|
|
702
704
|
function parseOperator(node) {
|
|
703
705
|
let it = NodeTool.getNodeText(node).trim();
|
|
704
706
|
|
|
705
|
-
// Special case for arrow (→)
|
|
707
|
+
// Special case for arrow (→) with proper spacing
|
|
706
708
|
if (it === "→") {
|
|
707
|
-
return "\\rightarrow";
|
|
709
|
+
return " \\rightarrow "; // Add spaces around arrow
|
|
708
710
|
}
|
|
709
711
|
|
|
710
712
|
it = MathSymbol.parseOperator(it);
|
|
@@ -787,6 +789,7 @@ function renderChildren(children) {
|
|
|
787
789
|
if(Brackets.contains(op)){
|
|
788
790
|
let stretchy = NodeTool.getAttr(node, 'stretchy', 'true');
|
|
789
791
|
stretchy = ['', 'true'].indexOf(stretchy) > -1;
|
|
792
|
+
|
|
790
793
|
if(Brackets.isRight(op)){
|
|
791
794
|
const nearLeft = lefts[lefts.length - 1];
|
|
792
795
|
if(nearLeft){
|
|
@@ -794,16 +797,10 @@ function renderChildren(children) {
|
|
|
794
797
|
parts.push(Brackets.parseRight(op, stretchy));
|
|
795
798
|
lefts.pop();
|
|
796
799
|
} else {
|
|
797
|
-
|
|
798
|
-
parts.push(Brackets.parseLeft(op, stretchy));
|
|
799
|
-
lefts.push(op);
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
}else {
|
|
803
|
-
if(Brackets.isLeft(op)) {
|
|
804
|
-
parts.push(Brackets.parseLeft(op, stretchy));
|
|
805
|
-
lefts.push(op);
|
|
800
|
+
parts.push(`\\right${op}`);
|
|
806
801
|
}
|
|
802
|
+
} else {
|
|
803
|
+
parts.push(`\\right${op}`);
|
|
807
804
|
}
|
|
808
805
|
} else {
|
|
809
806
|
parts.push(Brackets.parseLeft(op, stretchy));
|
|
@@ -816,10 +813,9 @@ function renderChildren(children) {
|
|
|
816
813
|
parts.push(parse(node));
|
|
817
814
|
}
|
|
818
815
|
});
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
}
|
|
816
|
+
// Only add \right. if there are unmatched left brackets
|
|
817
|
+
if(lefts.length > 0 && !parts.some(p => p.includes('\\right'))) {
|
|
818
|
+
parts.push("\\right.");
|
|
823
819
|
}
|
|
824
820
|
lefts = undefined;
|
|
825
821
|
return parts;
|
|
@@ -831,7 +827,28 @@ function getRender(node) {
|
|
|
831
827
|
const nodeName = NodeTool.getNodeName(node);
|
|
832
828
|
switch(nodeName){
|
|
833
829
|
case 'msub':
|
|
834
|
-
render =
|
|
830
|
+
render = function(node, children) {
|
|
831
|
+
if (!children || children.length < 2) return '';
|
|
832
|
+
|
|
833
|
+
const base = parse(children[0]);
|
|
834
|
+
if (!base) return '';
|
|
835
|
+
|
|
836
|
+
const sub = children[1];
|
|
837
|
+
if (!sub) return base;
|
|
838
|
+
|
|
839
|
+
// Handle nested subscript with empty mrow
|
|
840
|
+
if (NodeTool.getNodeName(sub) === 'msub' &&
|
|
841
|
+
sub.firstChild &&
|
|
842
|
+
NodeTool.getNodeName(sub.firstChild) === 'mrow' &&
|
|
843
|
+
(!NodeTool.getNodeText(sub.firstChild) || NodeTool.getNodeText(sub.firstChild).trim() === '')) {
|
|
844
|
+
const lastChild = sub.lastChild;
|
|
845
|
+
if (!lastChild) return base;
|
|
846
|
+
return `${base}_${parse(lastChild)}`;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// Regular subscript
|
|
850
|
+
return `${base}_{${parse(sub)}}`;
|
|
851
|
+
};
|
|
835
852
|
break;
|
|
836
853
|
case 'msup':
|
|
837
854
|
render = getRender_default("@1^{@2}");
|
|
@@ -893,10 +910,32 @@ function getRender(node) {
|
|
|
893
910
|
|
|
894
911
|
function renderTable(node, children) {
|
|
895
912
|
const template = "\\begin{array}{l}@content\\end{array}";
|
|
896
|
-
|
|
913
|
+
// Remove extra backslash and add proper spacing
|
|
914
|
+
const render = getRender_joinSeparator(template, " \\\\ ");
|
|
897
915
|
return render(node, children);
|
|
898
916
|
}
|
|
899
917
|
|
|
918
|
+
function renderMover(node, children) {
|
|
919
|
+
// Check if children exists and has enough elements
|
|
920
|
+
if (!children || children.length < 2) return '';
|
|
921
|
+
|
|
922
|
+
const baseNode = children[0];
|
|
923
|
+
const overNode = children[1];
|
|
924
|
+
|
|
925
|
+
// Check if nodes exist before accessing
|
|
926
|
+
if (!baseNode || !overNode) return '';
|
|
927
|
+
|
|
928
|
+
const overText = NodeTool.getNodeText(overNode)?.trim() || '';
|
|
929
|
+
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
930
|
+
|
|
931
|
+
// Handle vector notation
|
|
932
|
+
if (overText === "→" && isAccent) {
|
|
933
|
+
return `\\vec{${parse(baseNode)}}`;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return parse(baseNode);
|
|
937
|
+
}
|
|
938
|
+
|
|
900
939
|
function renderMfenced(node, children) {
|
|
901
940
|
const [open, close, separatorsStr] = [
|
|
902
941
|
NodeTool.getAttr(node, 'open', '('),
|
|
@@ -907,22 +946,25 @@ function renderMfenced(node, children) {
|
|
|
907
946
|
const parts = renderChildren(children);
|
|
908
947
|
const content = parts.join(separatorsStr === '|' ? ',' : separatorsStr).trim();
|
|
909
948
|
|
|
910
|
-
// Handle
|
|
949
|
+
// Handle nested absolute value cases
|
|
950
|
+
if (open === '|' && close === '') {
|
|
951
|
+
return `\\left|${content}`;
|
|
952
|
+
}
|
|
911
953
|
if (open === '' && close === '|') {
|
|
912
|
-
return
|
|
954
|
+
return `${content}\\right|`;
|
|
913
955
|
}
|
|
914
956
|
|
|
915
|
-
// Handle
|
|
916
|
-
if (open === '
|
|
917
|
-
return `\\left
|
|
957
|
+
// Handle system of equations with curly brace
|
|
958
|
+
if (open === '{') {
|
|
959
|
+
return `\\left\\{${content}${close ? '\\right\\}' : '\\right.'}`;
|
|
918
960
|
}
|
|
919
|
-
|
|
920
|
-
//
|
|
921
|
-
if (open === '
|
|
922
|
-
return `\\left
|
|
961
|
+
|
|
962
|
+
// Handle regular absolute value notation
|
|
963
|
+
if (open === '|' && close === '|') {
|
|
964
|
+
return `\\left|${content}\\right|`;
|
|
923
965
|
}
|
|
924
966
|
|
|
925
|
-
//
|
|
967
|
+
// Regular cases with proper closing
|
|
926
968
|
return `\\left${open}${content}\\right${close || '.'}`;
|
|
927
969
|
}
|
|
928
970
|
|
|
@@ -1001,62 +1043,6 @@ function renderMmultiscripts(node, children) {
|
|
|
1001
1043
|
return [renderScripts(prevScripts), base, renderScripts(backScripts)].join('');
|
|
1002
1044
|
}
|
|
1003
1045
|
|
|
1004
|
-
function renderMover(node, children) {
|
|
1005
|
-
const nodes = flattenNodeTreeByNodeName(node, 'mover');
|
|
1006
|
-
let result = undefined;
|
|
1007
|
-
|
|
1008
|
-
// Get the base node and check if it's a subscript or mrow
|
|
1009
|
-
const baseNode = children[0];
|
|
1010
|
-
const overNode = children[1];
|
|
1011
|
-
const nodeName = NodeTool.getNodeName(baseNode);
|
|
1012
|
-
const isSubscript = nodeName === 'msub';
|
|
1013
|
-
const isMrow = nodeName === 'mrow';
|
|
1014
|
-
|
|
1015
|
-
// Handle case where the base is an arrow and mrow is above
|
|
1016
|
-
const baseText = NodeTool.getNodeText(baseNode).trim();
|
|
1017
|
-
if (baseText === "→" && NodeTool.getNodeName(overNode) === "mrow") {
|
|
1018
|
-
return "\\rightarrow";
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
if (isSubscript) {
|
|
1022
|
-
// Handle case like n₂ with arrow
|
|
1023
|
-
const base = parse(baseNode);
|
|
1024
|
-
return `\\overrightarrow{${base}}`;
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
if (isMrow) {
|
|
1028
|
-
// Handle case like 0 with arrow
|
|
1029
|
-
const base = parse(baseNode);
|
|
1030
|
-
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1031
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1032
|
-
|
|
1033
|
-
if (overText === "→" && isAccent) {
|
|
1034
|
-
return `\\overrightarrow{${base}}`;
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
// Handle case where there is only an arrow with no base
|
|
1039
|
-
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1040
|
-
if (overText === "→" && NodeTool.getNodeText(baseNode).trim() === "") {
|
|
1041
|
-
return `\\rightarrow`; // Return just the arrow
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
for (let i = 0; i < nodes.length - 1; i++) {
|
|
1045
|
-
if (!result) {
|
|
1046
|
-
result = parse(nodes[i]);
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
const _overNode = nodes[i + 1];
|
|
1050
|
-
const overText = NodeTool.getNodeText(_overNode).trim();
|
|
1051
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1052
|
-
|
|
1053
|
-
if (overText === "→" && isAccent) {
|
|
1054
|
-
return `\\overrightarrow{${result}}`;
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
return result;
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
1046
|
function renderMunder(node, children){
|
|
1061
1047
|
const nodes = flattenNodeTreeByNodeName(node, 'munder');
|
|
1062
1048
|
let result = undefined;
|
package/lib/mathml2latex.umd.js
CHANGED
|
@@ -151,7 +151,9 @@
|
|
|
151
151
|
return node.children;
|
|
152
152
|
},
|
|
153
153
|
getNodeName: function(node) {
|
|
154
|
-
|
|
154
|
+
if (!node) return '';
|
|
155
|
+
const localName = node.localName || node.nodeName;
|
|
156
|
+
return localName ? localName.toLowerCase() : '';
|
|
155
157
|
},
|
|
156
158
|
getNodeText: function(node) {
|
|
157
159
|
return node.textContent;
|
|
@@ -708,9 +710,9 @@
|
|
|
708
710
|
function parseOperator(node) {
|
|
709
711
|
let it = NodeTool.getNodeText(node).trim();
|
|
710
712
|
|
|
711
|
-
// Special case for arrow (→)
|
|
713
|
+
// Special case for arrow (→) with proper spacing
|
|
712
714
|
if (it === "→") {
|
|
713
|
-
return "\\rightarrow";
|
|
715
|
+
return " \\rightarrow "; // Add spaces around arrow
|
|
714
716
|
}
|
|
715
717
|
|
|
716
718
|
it = MathSymbol.parseOperator(it);
|
|
@@ -793,6 +795,7 @@
|
|
|
793
795
|
if(Brackets.contains(op)){
|
|
794
796
|
let stretchy = NodeTool.getAttr(node, 'stretchy', 'true');
|
|
795
797
|
stretchy = ['', 'true'].indexOf(stretchy) > -1;
|
|
798
|
+
|
|
796
799
|
if(Brackets.isRight(op)){
|
|
797
800
|
const nearLeft = lefts[lefts.length - 1];
|
|
798
801
|
if(nearLeft){
|
|
@@ -800,16 +803,10 @@
|
|
|
800
803
|
parts.push(Brackets.parseRight(op, stretchy));
|
|
801
804
|
lefts.pop();
|
|
802
805
|
} else {
|
|
803
|
-
|
|
804
|
-
parts.push(Brackets.parseLeft(op, stretchy));
|
|
805
|
-
lefts.push(op);
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
}else {
|
|
809
|
-
if(Brackets.isLeft(op)) {
|
|
810
|
-
parts.push(Brackets.parseLeft(op, stretchy));
|
|
811
|
-
lefts.push(op);
|
|
806
|
+
parts.push(`\\right${op}`);
|
|
812
807
|
}
|
|
808
|
+
} else {
|
|
809
|
+
parts.push(`\\right${op}`);
|
|
813
810
|
}
|
|
814
811
|
} else {
|
|
815
812
|
parts.push(Brackets.parseLeft(op, stretchy));
|
|
@@ -822,10 +819,9 @@
|
|
|
822
819
|
parts.push(parse(node));
|
|
823
820
|
}
|
|
824
821
|
});
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
}
|
|
822
|
+
// Only add \right. if there are unmatched left brackets
|
|
823
|
+
if(lefts.length > 0 && !parts.some(p => p.includes('\\right'))) {
|
|
824
|
+
parts.push("\\right.");
|
|
829
825
|
}
|
|
830
826
|
lefts = undefined;
|
|
831
827
|
return parts;
|
|
@@ -837,7 +833,28 @@
|
|
|
837
833
|
const nodeName = NodeTool.getNodeName(node);
|
|
838
834
|
switch(nodeName){
|
|
839
835
|
case 'msub':
|
|
840
|
-
render =
|
|
836
|
+
render = function(node, children) {
|
|
837
|
+
if (!children || children.length < 2) return '';
|
|
838
|
+
|
|
839
|
+
const base = parse(children[0]);
|
|
840
|
+
if (!base) return '';
|
|
841
|
+
|
|
842
|
+
const sub = children[1];
|
|
843
|
+
if (!sub) return base;
|
|
844
|
+
|
|
845
|
+
// Handle nested subscript with empty mrow
|
|
846
|
+
if (NodeTool.getNodeName(sub) === 'msub' &&
|
|
847
|
+
sub.firstChild &&
|
|
848
|
+
NodeTool.getNodeName(sub.firstChild) === 'mrow' &&
|
|
849
|
+
(!NodeTool.getNodeText(sub.firstChild) || NodeTool.getNodeText(sub.firstChild).trim() === '')) {
|
|
850
|
+
const lastChild = sub.lastChild;
|
|
851
|
+
if (!lastChild) return base;
|
|
852
|
+
return `${base}_${parse(lastChild)}`;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// Regular subscript
|
|
856
|
+
return `${base}_{${parse(sub)}}`;
|
|
857
|
+
};
|
|
841
858
|
break;
|
|
842
859
|
case 'msup':
|
|
843
860
|
render = getRender_default("@1^{@2}");
|
|
@@ -899,10 +916,32 @@
|
|
|
899
916
|
|
|
900
917
|
function renderTable(node, children) {
|
|
901
918
|
const template = "\\begin{array}{l}@content\\end{array}";
|
|
902
|
-
|
|
919
|
+
// Remove extra backslash and add proper spacing
|
|
920
|
+
const render = getRender_joinSeparator(template, " \\\\ ");
|
|
903
921
|
return render(node, children);
|
|
904
922
|
}
|
|
905
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
|
+
|
|
906
945
|
function renderMfenced(node, children) {
|
|
907
946
|
const [open, close, separatorsStr] = [
|
|
908
947
|
NodeTool.getAttr(node, 'open', '('),
|
|
@@ -913,22 +952,25 @@
|
|
|
913
952
|
const parts = renderChildren(children);
|
|
914
953
|
const content = parts.join(separatorsStr === '|' ? ',' : separatorsStr).trim();
|
|
915
954
|
|
|
916
|
-
// Handle
|
|
955
|
+
// Handle nested absolute value cases
|
|
956
|
+
if (open === '|' && close === '') {
|
|
957
|
+
return `\\left|${content}`;
|
|
958
|
+
}
|
|
917
959
|
if (open === '' && close === '|') {
|
|
918
|
-
return
|
|
960
|
+
return `${content}\\right|`;
|
|
919
961
|
}
|
|
920
962
|
|
|
921
|
-
// Handle
|
|
922
|
-
if (open === '
|
|
923
|
-
return `\\left
|
|
963
|
+
// Handle system of equations with curly brace
|
|
964
|
+
if (open === '{') {
|
|
965
|
+
return `\\left\\{${content}${close ? '\\right\\}' : '\\right.'}`;
|
|
924
966
|
}
|
|
925
|
-
|
|
926
|
-
//
|
|
927
|
-
if (open === '
|
|
928
|
-
return `\\left
|
|
967
|
+
|
|
968
|
+
// Handle regular absolute value notation
|
|
969
|
+
if (open === '|' && close === '|') {
|
|
970
|
+
return `\\left|${content}\\right|`;
|
|
929
971
|
}
|
|
930
972
|
|
|
931
|
-
//
|
|
973
|
+
// Regular cases with proper closing
|
|
932
974
|
return `\\left${open}${content}\\right${close || '.'}`;
|
|
933
975
|
}
|
|
934
976
|
|
|
@@ -1007,62 +1049,6 @@
|
|
|
1007
1049
|
return [renderScripts(prevScripts), base, renderScripts(backScripts)].join('');
|
|
1008
1050
|
}
|
|
1009
1051
|
|
|
1010
|
-
function renderMover(node, children) {
|
|
1011
|
-
const nodes = flattenNodeTreeByNodeName(node, 'mover');
|
|
1012
|
-
let result = undefined;
|
|
1013
|
-
|
|
1014
|
-
// Get the base node and check if it's a subscript or mrow
|
|
1015
|
-
const baseNode = children[0];
|
|
1016
|
-
const overNode = children[1];
|
|
1017
|
-
const nodeName = NodeTool.getNodeName(baseNode);
|
|
1018
|
-
const isSubscript = nodeName === 'msub';
|
|
1019
|
-
const isMrow = nodeName === 'mrow';
|
|
1020
|
-
|
|
1021
|
-
// Handle case where the base is an arrow and mrow is above
|
|
1022
|
-
const baseText = NodeTool.getNodeText(baseNode).trim();
|
|
1023
|
-
if (baseText === "→" && NodeTool.getNodeName(overNode) === "mrow") {
|
|
1024
|
-
return "\\rightarrow";
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
if (isSubscript) {
|
|
1028
|
-
// Handle case like n₂ with arrow
|
|
1029
|
-
const base = parse(baseNode);
|
|
1030
|
-
return `\\overrightarrow{${base}}`;
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
if (isMrow) {
|
|
1034
|
-
// Handle case like 0 with arrow
|
|
1035
|
-
const base = parse(baseNode);
|
|
1036
|
-
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1037
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1038
|
-
|
|
1039
|
-
if (overText === "→" && isAccent) {
|
|
1040
|
-
return `\\overrightarrow{${base}}`;
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
// Handle case where there is only an arrow with no base
|
|
1045
|
-
const overText = NodeTool.getNodeText(overNode).trim();
|
|
1046
|
-
if (overText === "→" && NodeTool.getNodeText(baseNode).trim() === "") {
|
|
1047
|
-
return `\\rightarrow`; // Return just the arrow
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
for (let i = 0; i < nodes.length - 1; i++) {
|
|
1051
|
-
if (!result) {
|
|
1052
|
-
result = parse(nodes[i]);
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
|
-
const _overNode = nodes[i + 1];
|
|
1056
|
-
const overText = NodeTool.getNodeText(_overNode).trim();
|
|
1057
|
-
const isAccent = NodeTool.getAttr(node, "accent", "false") === "true";
|
|
1058
|
-
|
|
1059
|
-
if (overText === "→" && isAccent) {
|
|
1060
|
-
return `\\overrightarrow{${result}}`;
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
return result;
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
1052
|
function renderMunder(node, children){
|
|
1067
1053
|
const nodes = flattenNodeTreeByNodeName(node, 'munder');
|
|
1068
1054
|
let result = undefined;
|