@drghaliasri/butex 5.5.5 → 5.6.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/README.md +1 -1
- package/dist/document.js +36 -0
- package/dist/document.js.map +1 -1
- package/dist/document.mjs +36 -0
- package/dist/document.mjs.map +1 -1
- package/dist/document2.d.mts +4 -2
- package/dist/document2.d.ts +4 -2
- package/dist/document2.js +173 -20
- package/dist/document2.js.map +1 -1
- package/dist/document2.mjs +173 -20
- package/dist/document2.mjs.map +1 -1
- package/dist/index.d.mts +39 -1
- package/dist/index.d.ts +39 -1
- package/dist/index.global.js +79 -14
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +79 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +79 -14
- package/dist/index.mjs.map +1 -1
- package/dist/react-document.js +254 -7
- package/dist/react-document.js.map +1 -1
- package/dist/react-document.mjs +254 -7
- package/dist/react-document.mjs.map +1 -1
- package/dist/react-document2.d.mts +5 -3
- package/dist/react-document2.d.ts +5 -3
- package/dist/react-document2.js +375 -33
- package/dist/react-document2.js.map +1 -1
- package/dist/react-document2.mjs +375 -33
- package/dist/react-document2.mjs.map +1 -1
- package/dist/react.d.mts +35 -0
- package/dist/react.d.ts +35 -0
- package/dist/react.js +1277 -7
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +1277 -7
- package/dist/react.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react.mjs
CHANGED
|
@@ -127,6 +127,81 @@ function cloneEditorSession(session) {
|
|
|
127
127
|
debugLog: session.debugLog.slice()
|
|
128
128
|
};
|
|
129
129
|
}
|
|
130
|
+
function collectNodeIds(chain, ids) {
|
|
131
|
+
for (const node of chain.nodes) {
|
|
132
|
+
ids.push(node.id);
|
|
133
|
+
if (node.superscript) {
|
|
134
|
+
collectNodeIds(node.superscript, ids);
|
|
135
|
+
}
|
|
136
|
+
if (node.subscript) {
|
|
137
|
+
collectNodeIds(node.subscript, ids);
|
|
138
|
+
}
|
|
139
|
+
if (node.innerExpr) {
|
|
140
|
+
collectNodeIds(node.innerExpr, ids);
|
|
141
|
+
}
|
|
142
|
+
if (node.numerator) {
|
|
143
|
+
collectNodeIds(node.numerator, ids);
|
|
144
|
+
}
|
|
145
|
+
if (node.denominator) {
|
|
146
|
+
collectNodeIds(node.denominator, ids);
|
|
147
|
+
}
|
|
148
|
+
if (node.rootIndex) {
|
|
149
|
+
collectNodeIds(node.rootIndex, ids);
|
|
150
|
+
}
|
|
151
|
+
if (node.radicand) {
|
|
152
|
+
collectNodeIds(node.radicand, ids);
|
|
153
|
+
}
|
|
154
|
+
if (node.overExpr) {
|
|
155
|
+
collectNodeIds(node.overExpr, ids);
|
|
156
|
+
}
|
|
157
|
+
if (node.underExpr) {
|
|
158
|
+
collectNodeIds(node.underExpr, ids);
|
|
159
|
+
}
|
|
160
|
+
if (node.baseExpr) {
|
|
161
|
+
collectNodeIds(node.baseExpr, ids);
|
|
162
|
+
}
|
|
163
|
+
if (node.matrixRows) {
|
|
164
|
+
for (const row of node.matrixRows) {
|
|
165
|
+
for (const cell of row) {
|
|
166
|
+
collectNodeIds(cell, ids);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function buildInitialSyncMap(englishTree, arabicTree) {
|
|
173
|
+
const englishIds = [];
|
|
174
|
+
const arabicIds = [];
|
|
175
|
+
collectNodeIds(englishTree, englishIds);
|
|
176
|
+
collectNodeIds(arabicTree, arabicIds);
|
|
177
|
+
const all = /* @__PURE__ */ new Set([...englishIds, ...arabicIds]);
|
|
178
|
+
const sync = {};
|
|
179
|
+
for (const nodeId of all) {
|
|
180
|
+
sync[nodeId] = { expr: "synced" };
|
|
181
|
+
}
|
|
182
|
+
return sync;
|
|
183
|
+
}
|
|
184
|
+
function createEditorSession(englishTree, arabicTree, activeSide = "arabic") {
|
|
185
|
+
return {
|
|
186
|
+
englishTree,
|
|
187
|
+
arabicTree,
|
|
188
|
+
activeSide,
|
|
189
|
+
splitLeafTyping: false,
|
|
190
|
+
forceSplitNextLeaf: false,
|
|
191
|
+
arabicReverseNumberTyping: true,
|
|
192
|
+
currentCharacterFont: "default",
|
|
193
|
+
currentDigitForm: "western",
|
|
194
|
+
caret: {
|
|
195
|
+
chainId: englishTree.id,
|
|
196
|
+
index: 0
|
|
197
|
+
},
|
|
198
|
+
selection: null,
|
|
199
|
+
selectedNodeId: null,
|
|
200
|
+
selectedStructureNodeId: null,
|
|
201
|
+
sync: buildInitialSyncMap(englishTree, arabicTree),
|
|
202
|
+
debugLog: []
|
|
203
|
+
};
|
|
204
|
+
}
|
|
130
205
|
|
|
131
206
|
// src/editor/accentCommands.ts
|
|
132
207
|
var ACCENT_COMMANDS = {
|
|
@@ -265,6 +340,20 @@ function accentCommandSpec(id) {
|
|
|
265
340
|
function accentCommandsList() {
|
|
266
341
|
return Object.values(ACCENT_COMMANDS);
|
|
267
342
|
}
|
|
343
|
+
function accentCommandIdFromTex(tex) {
|
|
344
|
+
const normalized = tex.startsWith("\\") ? tex : `\\${tex}`;
|
|
345
|
+
for (const spec of Object.values(ACCENT_COMMANDS)) {
|
|
346
|
+
if (spec.englishTex === normalized) {
|
|
347
|
+
return spec.id;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
for (const spec of Object.values(ACCENT_COMMANDS)) {
|
|
351
|
+
if (spec.arabicTex === normalized) {
|
|
352
|
+
return spec.id;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
268
357
|
|
|
269
358
|
// src/editor/atomicCommands.ts
|
|
270
359
|
var ATOMIC_COMMANDS = {
|
|
@@ -687,6 +776,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
687
776
|
category: "operators1",
|
|
688
777
|
Tex: "\\neq",
|
|
689
778
|
mirror: true,
|
|
779
|
+
compileMirror: true,
|
|
690
780
|
Label: "\u2260",
|
|
691
781
|
title: "\u0644\u0627 \u064A\u0633\u0627\u0648\u064A",
|
|
692
782
|
svg_path: null
|
|
@@ -726,6 +816,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
726
816
|
Tex: "\\leq",
|
|
727
817
|
mirror: true,
|
|
728
818
|
displayMirror: false,
|
|
819
|
+
compileMirror: true,
|
|
729
820
|
Label: "\u2264",
|
|
730
821
|
title: "\u0623\u0635\u063A\u0631 \u0645\u0646 \u0623\u0648 \u064A\u0633\u0627\u0648\u064A",
|
|
731
822
|
svg_path: null
|
|
@@ -736,6 +827,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
736
827
|
Tex: "\\geq",
|
|
737
828
|
mirror: true,
|
|
738
829
|
displayMirror: false,
|
|
830
|
+
compileMirror: true,
|
|
739
831
|
Label: "\u2265",
|
|
740
832
|
title: "\u0623\u0643\u0628\u0631 \u0645\u0646 \u0623\u0648 \u064A\u0633\u0627\u0648\u064A",
|
|
741
833
|
svg_path: null
|
|
@@ -746,6 +838,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
746
838
|
Tex: "\\coloneqq",
|
|
747
839
|
mirror: true,
|
|
748
840
|
displayMirror: false,
|
|
841
|
+
compileMirror: true,
|
|
749
842
|
Label: "\u2254",
|
|
750
843
|
title: "\u064A\u0639\u0631\u0641 \u0628\u0623\u0646\u0647 \u064A\u0633\u0627\u0648\u064A",
|
|
751
844
|
svg_path: null
|
|
@@ -756,6 +849,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
756
849
|
Tex: "\\eqqcolon",
|
|
757
850
|
mirror: true,
|
|
758
851
|
displayMirror: false,
|
|
852
|
+
compileMirror: true,
|
|
759
853
|
Label: "\u2255",
|
|
760
854
|
title: "\u064A\u0633\u0627\u0648\u064A \u0628\u0627\u0644\u062A\u0639\u0631\u064A\u0641",
|
|
761
855
|
svg_path: null
|
|
@@ -767,6 +861,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
767
861
|
Tex: "\\propto",
|
|
768
862
|
mirror: true,
|
|
769
863
|
displayMirror: false,
|
|
864
|
+
compileMirror: true,
|
|
770
865
|
Label: "\u221D",
|
|
771
866
|
title: "\u064A\u062A\u0646\u0627\u0633\u0628 \u0645\u0639",
|
|
772
867
|
svg_path: null
|
|
@@ -777,6 +872,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
777
872
|
Tex: "\\in",
|
|
778
873
|
mirror: true,
|
|
779
874
|
displayMirror: false,
|
|
875
|
+
compileMirror: true,
|
|
780
876
|
Label: "\u2208",
|
|
781
877
|
title: "\u064A\u0646\u062A\u0645\u064A \u0625\u0644\u0649",
|
|
782
878
|
svg_path: null
|
|
@@ -797,6 +893,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
797
893
|
Tex: "\\subset",
|
|
798
894
|
mirror: true,
|
|
799
895
|
displayMirror: false,
|
|
896
|
+
compileMirror: true,
|
|
800
897
|
Label: "\u2282",
|
|
801
898
|
title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u062C\u0632\u0626\u064A\u0629 \u0645\u0646",
|
|
802
899
|
svg_path: null
|
|
@@ -807,6 +904,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
807
904
|
Tex: "\\supset",
|
|
808
905
|
mirror: true,
|
|
809
906
|
displayMirror: false,
|
|
907
|
+
compileMirror: true,
|
|
810
908
|
Label: "\u2283",
|
|
811
909
|
title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u0634\u0627\u0645\u0644\u0629 \u0644\u0640",
|
|
812
910
|
svg_path: null
|
|
@@ -817,6 +915,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
817
915
|
Tex: "\\subseteq",
|
|
818
916
|
mirror: true,
|
|
819
917
|
displayMirror: false,
|
|
918
|
+
compileMirror: true,
|
|
820
919
|
Label: "\u2286",
|
|
821
920
|
title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u062C\u0632\u0626\u064A\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
|
|
822
921
|
svg_path: null
|
|
@@ -827,6 +926,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
827
926
|
Tex: "\\supseteq",
|
|
828
927
|
mirror: true,
|
|
829
928
|
displayMirror: false,
|
|
929
|
+
compileMirror: true,
|
|
830
930
|
Label: "\u2287",
|
|
831
931
|
title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u0634\u0627\u0645\u0644\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
|
|
832
932
|
svg_path: null
|
|
@@ -867,6 +967,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
867
967
|
Tex: "\\nsubseteq",
|
|
868
968
|
mirror: true,
|
|
869
969
|
displayMirror: false,
|
|
970
|
+
compileMirror: true,
|
|
870
971
|
Label: "\u2288",
|
|
871
972
|
title: "\u0644\u064A\u0633\u062A \u0645\u062C\u0645\u0648\u0639\u0629 \u062C\u0632\u0626\u064A\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
|
|
872
973
|
svg_path: null
|
|
@@ -877,6 +978,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
877
978
|
Tex: "\\nsupseteq",
|
|
878
979
|
mirror: true,
|
|
879
980
|
displayMirror: false,
|
|
981
|
+
compileMirror: true,
|
|
880
982
|
Label: "\u2289",
|
|
881
983
|
title: "\u0644\u064A\u0633\u062A \u0645\u062C\u0645\u0648\u0639\u0629 \u0634\u0627\u0645\u0644\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
|
|
882
984
|
svg_path: null
|
|
@@ -924,6 +1026,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
924
1026
|
Tex: "\\ddots",
|
|
925
1027
|
mirror: true,
|
|
926
1028
|
displayMirror: false,
|
|
1029
|
+
compileMirror: true,
|
|
927
1030
|
Label: "\u22F1",
|
|
928
1031
|
title: "\u0646\u0642\u0627\u0637 \u0642\u0637\u0631\u064A\u0629",
|
|
929
1032
|
svg_path: null
|
|
@@ -943,6 +1046,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
943
1046
|
category: "operators3",
|
|
944
1047
|
Tex: "\\implies",
|
|
945
1048
|
mirror: true,
|
|
1049
|
+
compileMirror: true,
|
|
946
1050
|
Label: "\u21D2",
|
|
947
1051
|
title: "\u064A\u0633\u062A\u0644\u0632\u0645",
|
|
948
1052
|
svg_path: null
|
|
@@ -952,6 +1056,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
952
1056
|
category: "operators3",
|
|
953
1057
|
Tex: "\\impliedby",
|
|
954
1058
|
mirror: true,
|
|
1059
|
+
compileMirror: true,
|
|
955
1060
|
Label: "\u21D0",
|
|
956
1061
|
title: "\u0645\u0633\u062A\u0644\u0632\u0645 \u0645\u0646",
|
|
957
1062
|
svg_path: null
|
|
@@ -970,6 +1075,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
970
1075
|
category: "operators3",
|
|
971
1076
|
Tex: "\\Longrightarrow",
|
|
972
1077
|
mirror: true,
|
|
1078
|
+
compileMirror: true,
|
|
973
1079
|
Label: "\u27F9",
|
|
974
1080
|
title: "\u0633\u0647\u0645 \u0645\u0632\u062F\u0648\u062C \u0637\u0648\u064A\u0644 \u0625\u0644\u0649 \u0627\u0644\u064A\u0645\u064A\u0646",
|
|
975
1081
|
svg_path: null
|
|
@@ -979,6 +1085,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
979
1085
|
category: "operators3",
|
|
980
1086
|
Tex: "\\Longleftarrow",
|
|
981
1087
|
mirror: true,
|
|
1088
|
+
compileMirror: true,
|
|
982
1089
|
Label: "\u27F8",
|
|
983
1090
|
title: "\u0633\u0647\u0645 \u0645\u0632\u062F\u0648\u062C \u0637\u0648\u064A\u0644 \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631",
|
|
984
1091
|
svg_path: null
|
|
@@ -988,6 +1095,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
988
1095
|
category: "operators3",
|
|
989
1096
|
Tex: "\\to",
|
|
990
1097
|
mirror: true,
|
|
1098
|
+
compileMirror: true,
|
|
991
1099
|
Label: "\u2192",
|
|
992
1100
|
title: "\u064A\u0624\u0648\u0644 \u0625\u0644\u0649",
|
|
993
1101
|
svg_path: null
|
|
@@ -997,6 +1105,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
997
1105
|
category: "operators3",
|
|
998
1106
|
Tex: "\\rightleftharpoons",
|
|
999
1107
|
mirror: true,
|
|
1108
|
+
compileMirror: true,
|
|
1000
1109
|
Label: "\u21CC",
|
|
1001
1110
|
title: "\u0627\u062A\u0632\u0627\u0646",
|
|
1002
1111
|
svg_path: null
|
|
@@ -1006,6 +1115,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
1006
1115
|
category: "operators3",
|
|
1007
1116
|
Tex: "\\leftarrow",
|
|
1008
1117
|
mirror: true,
|
|
1118
|
+
compileMirror: true,
|
|
1009
1119
|
Label: "\u2190",
|
|
1010
1120
|
title: "\u0633\u0647\u0645 \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631",
|
|
1011
1121
|
svg_path: null
|
|
@@ -1015,6 +1125,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
1015
1125
|
category: "operators3",
|
|
1016
1126
|
Tex: "\\rightarrow",
|
|
1017
1127
|
mirror: true,
|
|
1128
|
+
compileMirror: true,
|
|
1018
1129
|
Label: "\u2192",
|
|
1019
1130
|
title: "\u0633\u0647\u0645 \u0625\u0644\u0649 \u0627\u0644\u064A\u0645\u064A\u0646",
|
|
1020
1131
|
svg_path: null
|
|
@@ -1024,6 +1135,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
1024
1135
|
category: "operators3",
|
|
1025
1136
|
Tex: "\\Leftarrow",
|
|
1026
1137
|
mirror: true,
|
|
1138
|
+
compileMirror: true,
|
|
1027
1139
|
Label: "\u21D0",
|
|
1028
1140
|
title: "\u0633\u0647\u0645 \u0645\u0632\u062F\u0648\u062C \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631",
|
|
1029
1141
|
svg_path: null
|
|
@@ -1033,6 +1145,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
1033
1145
|
category: "operators3",
|
|
1034
1146
|
Tex: "\\Rightarrow",
|
|
1035
1147
|
mirror: true,
|
|
1148
|
+
compileMirror: true,
|
|
1036
1149
|
Label: "\u21D2",
|
|
1037
1150
|
title: "\u0633\u0647\u0645 \u0645\u0632\u062F\u0648\u062C \u0625\u0644\u0649 \u0627\u0644\u064A\u0645\u064A\u0646",
|
|
1038
1151
|
svg_path: null
|
|
@@ -1042,6 +1155,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
1042
1155
|
category: "operators3",
|
|
1043
1156
|
Tex: "\\leftharpoonup",
|
|
1044
1157
|
mirror: true,
|
|
1158
|
+
compileMirror: true,
|
|
1045
1159
|
Label: "\u21BC",
|
|
1046
1160
|
title: "\u0633\u0647\u0645 \u062E\u0637\u0627\u0641\u064A \u0639\u0644\u0648\u064A \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631",
|
|
1047
1161
|
svg_path: null
|
|
@@ -1051,6 +1165,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
1051
1165
|
category: "operators3",
|
|
1052
1166
|
Tex: "\\rightharpoonup",
|
|
1053
1167
|
mirror: true,
|
|
1168
|
+
compileMirror: true,
|
|
1054
1169
|
Label: "\u21C0",
|
|
1055
1170
|
title: "\u0633\u0647\u0645 \u062E\u0637\u0627\u0641\u064A \u0639\u0644\u0648\u064A \u0625\u0644\u0649 \u0627\u0644\u064A\u0645\u064A\u0646",
|
|
1056
1171
|
svg_path: null
|
|
@@ -1060,6 +1175,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
1060
1175
|
category: "operators3",
|
|
1061
1176
|
Tex: "\\leftharpoondown",
|
|
1062
1177
|
mirror: true,
|
|
1178
|
+
compileMirror: true,
|
|
1063
1179
|
Label: "\u21BD",
|
|
1064
1180
|
title: "\u0633\u0647\u0645 \u062E\u0637\u0627\u0641\u064A \u0633\u0641\u0644\u064A \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631",
|
|
1065
1181
|
svg_path: null
|
|
@@ -1069,6 +1185,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
1069
1185
|
category: "operators3",
|
|
1070
1186
|
Tex: "\\rightharpoondown",
|
|
1071
1187
|
mirror: true,
|
|
1188
|
+
compileMirror: true,
|
|
1072
1189
|
Label: "\u21C1",
|
|
1073
1190
|
title: "\u0633\u0647\u0645 \u062E\u0637\u0627\u0641\u064A \u0633\u0641\u0644\u064A \u0625\u0644\u0649 \u0627\u0644\u064A\u0645\u064A\u0646",
|
|
1074
1191
|
svg_path: null
|
|
@@ -1079,6 +1196,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
1079
1196
|
category: "integrals",
|
|
1080
1197
|
Tex: "\\int",
|
|
1081
1198
|
mirror: true,
|
|
1199
|
+
compileMirror: true,
|
|
1082
1200
|
Label: "\u222B",
|
|
1083
1201
|
title: "\u062A\u0643\u0627\u0645\u0644",
|
|
1084
1202
|
svg_path: null
|
|
@@ -1089,6 +1207,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
1089
1207
|
Tex: "\\iint",
|
|
1090
1208
|
mirror: true,
|
|
1091
1209
|
displayMirror: false,
|
|
1210
|
+
compileMirror: true,
|
|
1092
1211
|
Label: "\u222C",
|
|
1093
1212
|
title: "\u062A\u0643\u0627\u0645\u0644 \u0645\u0632\u062F\u0648\u062C",
|
|
1094
1213
|
svg_path: null
|
|
@@ -1099,6 +1218,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
1099
1218
|
Tex: "\\iiint",
|
|
1100
1219
|
mirror: true,
|
|
1101
1220
|
displayMirror: false,
|
|
1221
|
+
compileMirror: true,
|
|
1102
1222
|
Label: "\u222D",
|
|
1103
1223
|
title: "\u062A\u0643\u0627\u0645\u0644 \u062B\u0644\u0627\u062B\u064A",
|
|
1104
1224
|
svg_path: null
|
|
@@ -1109,6 +1229,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
1109
1229
|
Tex: "\\iiiint",
|
|
1110
1230
|
mirror: true,
|
|
1111
1231
|
displayMirror: false,
|
|
1232
|
+
compileMirror: true,
|
|
1112
1233
|
Label: "\u2A0C",
|
|
1113
1234
|
title: "\u062A\u0643\u0627\u0645\u0644 \u0631\u0628\u0627\u0639\u064A",
|
|
1114
1235
|
svg_path: null
|
|
@@ -1119,6 +1240,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
1119
1240
|
Tex: "\\oint",
|
|
1120
1241
|
mirror: true,
|
|
1121
1242
|
displayMirror: false,
|
|
1243
|
+
compileMirror: true,
|
|
1122
1244
|
Label: "\u222E",
|
|
1123
1245
|
title: "\u062A\u0643\u0627\u0645\u0644 \u0645\u063A\u0644\u0642",
|
|
1124
1246
|
svg_path: null
|
|
@@ -1129,6 +1251,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
1129
1251
|
Tex: "\\oiint",
|
|
1130
1252
|
mirror: true,
|
|
1131
1253
|
displayMirror: false,
|
|
1254
|
+
compileMirror: true,
|
|
1132
1255
|
Label: "\u222F",
|
|
1133
1256
|
title: "\u062A\u0643\u0627\u0645\u0644 \u0633\u0637\u062D\u064A \u0645\u063A\u0644\u0642",
|
|
1134
1257
|
svg_path: null
|
|
@@ -1139,6 +1262,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
|
|
|
1139
1262
|
Tex: "\\oiiint",
|
|
1140
1263
|
mirror: true,
|
|
1141
1264
|
displayMirror: false,
|
|
1265
|
+
compileMirror: true,
|
|
1142
1266
|
Label: "\u2230",
|
|
1143
1267
|
title: "\u062A\u0643\u0627\u0645\u0644 \u062D\u062C\u0645\u064A \u0645\u063A\u0644\u0642",
|
|
1144
1268
|
svg_path: null
|
|
@@ -1148,8 +1272,9 @@ function shouldMirrorOperatorDisplay(command) {
|
|
|
1148
1272
|
return command?.displayMirror ?? command?.mirror ?? false;
|
|
1149
1273
|
}
|
|
1150
1274
|
var MIRRORED_OPERATOR_TEX = Object.values(ATOMIC_OPERATOR_COMMANDS).filter((command) => command.mirror).map((command) => command.Tex).sort((a, b) => b.length - a.length);
|
|
1151
|
-
|
|
1152
|
-
|
|
1275
|
+
var COMPILE_MIRRORED_OPERATOR_TEX = Object.values(ATOMIC_OPERATOR_COMMANDS).filter((command) => "compileMirror" in command && command.compileMirror).map((command) => command.Tex).sort((a, b) => b.length - a.length);
|
|
1276
|
+
function matchingMirroredOperatorFrom(tex, index, operatorTexList) {
|
|
1277
|
+
for (const operatorTex of operatorTexList) {
|
|
1153
1278
|
if (!tex.startsWith(operatorTex, index)) {
|
|
1154
1279
|
continue;
|
|
1155
1280
|
}
|
|
@@ -1180,19 +1305,26 @@ function findMatchingBrace(tex, openIndex) {
|
|
|
1180
1305
|
}
|
|
1181
1306
|
return -1;
|
|
1182
1307
|
}
|
|
1183
|
-
function mirrorBuTeXOperatorsInTex(tex) {
|
|
1308
|
+
function mirrorBuTeXOperatorsInTex(tex, options = {}) {
|
|
1309
|
+
const mirroredOperatorTex = options.target === "compile" ? COMPILE_MIRRORED_OPERATOR_TEX : MIRRORED_OPERATOR_TEX;
|
|
1184
1310
|
let result = "";
|
|
1185
1311
|
let index = 0;
|
|
1186
1312
|
while (index < tex.length) {
|
|
1187
1313
|
if (tex.startsWith("\\butexmirror{", index)) {
|
|
1188
1314
|
const end = findMatchingBrace(tex, index + "\\butexmirror".length);
|
|
1189
1315
|
if (end !== -1) {
|
|
1190
|
-
|
|
1316
|
+
const bodyStart = index + "\\butexmirror{".length;
|
|
1317
|
+
const body = tex.slice(bodyStart, end);
|
|
1318
|
+
if (options.target === "compile" && MIRRORED_OPERATOR_TEX.includes(body) && !mirroredOperatorTex.includes(body)) {
|
|
1319
|
+
result += body;
|
|
1320
|
+
} else {
|
|
1321
|
+
result += tex.slice(index, end + 1);
|
|
1322
|
+
}
|
|
1191
1323
|
index = end + 1;
|
|
1192
1324
|
continue;
|
|
1193
1325
|
}
|
|
1194
1326
|
}
|
|
1195
|
-
const operatorTex =
|
|
1327
|
+
const operatorTex = matchingMirroredOperatorFrom(tex, index, mirroredOperatorTex);
|
|
1196
1328
|
if (operatorTex) {
|
|
1197
1329
|
result += `\\butexmirror{${operatorTex}}`;
|
|
1198
1330
|
index += operatorTex.length;
|
|
@@ -6865,6 +6997,11 @@ var WIDGET_CHROME_CSS = `
|
|
|
6865
6997
|
font-family: ${BUTEX_DIWANI_OUTLINE_FONT_STACK};
|
|
6866
6998
|
}
|
|
6867
6999
|
|
|
7000
|
+
.butex-widget .font-mode-btn--maghribi,
|
|
7001
|
+
.butex-widget .character-font-option--maghribi {
|
|
7002
|
+
font-family: ${BUTEX_MAGHRIBI_FONT_STACK};
|
|
7003
|
+
}
|
|
7004
|
+
|
|
6868
7005
|
.butex-widget .character-font-options {
|
|
6869
7006
|
position: absolute;
|
|
6870
7007
|
z-index: 10;
|
|
@@ -7399,6 +7536,36 @@ var WIDGET_CHROME_CSS = `
|
|
|
7399
7536
|
background: var(--butex-dev-inset-bg);
|
|
7400
7537
|
color: var(--butex-dev-inset-fg);
|
|
7401
7538
|
}
|
|
7539
|
+
|
|
7540
|
+
.butex-widget .debug-json-import {
|
|
7541
|
+
display: grid;
|
|
7542
|
+
gap: 8px;
|
|
7543
|
+
margin-bottom: 10px;
|
|
7544
|
+
}
|
|
7545
|
+
|
|
7546
|
+
.butex-widget .debug-json-import textarea {
|
|
7547
|
+
min-height: 150px;
|
|
7548
|
+
resize: vertical;
|
|
7549
|
+
border: 1px solid var(--butex-dev-inset-border);
|
|
7550
|
+
border-radius: 8px;
|
|
7551
|
+
padding: 8px 10px;
|
|
7552
|
+
direction: ltr;
|
|
7553
|
+
text-align: left;
|
|
7554
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
7555
|
+
font-size: 11px;
|
|
7556
|
+
background: var(--butex-dev-inset-bg);
|
|
7557
|
+
color: var(--butex-dev-inset-fg);
|
|
7558
|
+
}
|
|
7559
|
+
|
|
7560
|
+
.butex-widget .debug-json-error {
|
|
7561
|
+
margin: 0;
|
|
7562
|
+
border: 1px solid rgba(220, 38, 38, 0.45);
|
|
7563
|
+
background: rgba(254, 226, 226, 0.9);
|
|
7564
|
+
color: #991b1b;
|
|
7565
|
+
border-radius: 8px;
|
|
7566
|
+
padding: 8px 10px;
|
|
7567
|
+
white-space: pre-wrap;
|
|
7568
|
+
}
|
|
7402
7569
|
`.trim();
|
|
7403
7570
|
var CHROME_STYLE_ID = "butex-widget-chrome-css";
|
|
7404
7571
|
function injectWidgetChromeCss(doc) {
|
|
@@ -7417,6 +7584,1026 @@ function uiLocaleDirection(locale) {
|
|
|
7417
7584
|
return locale === "ar" ? "rtl" : "ltr";
|
|
7418
7585
|
}
|
|
7419
7586
|
|
|
7587
|
+
// src/ast/commands/index.ts
|
|
7588
|
+
function renderCommandCore(context) {
|
|
7589
|
+
const optional = context.optionalArgs.map((arg) => `[${context.renderChain(arg)}]`).join("");
|
|
7590
|
+
const mandatory = context.mandatoryArgs.map((arg) => `{${context.renderChain(arg)}}`).join("");
|
|
7591
|
+
return context.name + optional + mandatory;
|
|
7592
|
+
}
|
|
7593
|
+
|
|
7594
|
+
// src/ast/arabic_ast.ts
|
|
7595
|
+
var State = class {
|
|
7596
|
+
// Empty for now, like the Python State placeholder used by BaseNode.
|
|
7597
|
+
};
|
|
7598
|
+
var BaseAstNode = class {
|
|
7599
|
+
state;
|
|
7600
|
+
superscript;
|
|
7601
|
+
subscript;
|
|
7602
|
+
nodeType;
|
|
7603
|
+
constructor(state = null) {
|
|
7604
|
+
if (state === null) {
|
|
7605
|
+
state = new State();
|
|
7606
|
+
}
|
|
7607
|
+
this.state = state;
|
|
7608
|
+
this.superscript = null;
|
|
7609
|
+
this.subscript = null;
|
|
7610
|
+
this.nodeType = this.constructor.name;
|
|
7611
|
+
}
|
|
7612
|
+
latex() {
|
|
7613
|
+
throw new Error("NotImplementedError");
|
|
7614
|
+
}
|
|
7615
|
+
arabicLatex() {
|
|
7616
|
+
throw new Error("NotImplementedError");
|
|
7617
|
+
}
|
|
7618
|
+
toArabicLatex() {
|
|
7619
|
+
return this.arabicLatex();
|
|
7620
|
+
}
|
|
7621
|
+
/** Latin-style scripts: `^{...}` and `_{...}` for english_json rendering. */
|
|
7622
|
+
latexScripts() {
|
|
7623
|
+
let s = "";
|
|
7624
|
+
if (this.superscript !== null) {
|
|
7625
|
+
s += "^{" + this.superscript.latex() + "}";
|
|
7626
|
+
}
|
|
7627
|
+
if (this.subscript !== null) {
|
|
7628
|
+
s += "_{" + this.subscript.latex() + "}";
|
|
7629
|
+
}
|
|
7630
|
+
return s;
|
|
7631
|
+
}
|
|
7632
|
+
/**
|
|
7633
|
+
* Arabic scripts use \\prescript{sup}{sub}{content} (matches reference Python output).
|
|
7634
|
+
* Call with rendered strings for sup/sub chains (may be empty strings).
|
|
7635
|
+
*/
|
|
7636
|
+
arabicLatexScripts(sup, sub, content) {
|
|
7637
|
+
if (sup !== "" || sub !== "") {
|
|
7638
|
+
return "\\prescript{" + sup + "}{" + sub + "}{" + content + "}";
|
|
7639
|
+
}
|
|
7640
|
+
return content;
|
|
7641
|
+
}
|
|
7642
|
+
};
|
|
7643
|
+
var ChainNode = class {
|
|
7644
|
+
chain;
|
|
7645
|
+
constructor(chain = []) {
|
|
7646
|
+
this.chain = chain;
|
|
7647
|
+
}
|
|
7648
|
+
latex() {
|
|
7649
|
+
return this.chain.map((node) => node.latex()).join(" ");
|
|
7650
|
+
}
|
|
7651
|
+
toEnglishLatex() {
|
|
7652
|
+
return this.chain.map((node) => node.latex()).join(" ");
|
|
7653
|
+
}
|
|
7654
|
+
/** RTL: reverse order relative to Latin chain (see test/ref_tests.txt). */
|
|
7655
|
+
arabicLatex() {
|
|
7656
|
+
const reversed = this.chain.slice().reverse();
|
|
7657
|
+
return reversed.map((node) => node.arabicLatex()).join(" ");
|
|
7658
|
+
}
|
|
7659
|
+
toArabicLatex() {
|
|
7660
|
+
return this.arabicLatex();
|
|
7661
|
+
}
|
|
7662
|
+
};
|
|
7663
|
+
var NumberNode = class extends BaseAstNode {
|
|
7664
|
+
expr;
|
|
7665
|
+
constructor(expr, state = null) {
|
|
7666
|
+
super(state);
|
|
7667
|
+
this.nodeType = "NumberObject";
|
|
7668
|
+
this.expr = expr;
|
|
7669
|
+
}
|
|
7670
|
+
latex() {
|
|
7671
|
+
return this.expr + this.latexScripts();
|
|
7672
|
+
}
|
|
7673
|
+
arabicLatex() {
|
|
7674
|
+
const sup = this.superscript !== null ? this.superscript.arabicLatex() : "";
|
|
7675
|
+
const sub = this.subscript !== null ? this.subscript.arabicLatex() : "";
|
|
7676
|
+
return this.arabicLatexScripts(sup, sub, this.expr);
|
|
7677
|
+
}
|
|
7678
|
+
};
|
|
7679
|
+
var CharNode = class extends BaseAstNode {
|
|
7680
|
+
expr;
|
|
7681
|
+
constructor(expr, state = null) {
|
|
7682
|
+
super(state);
|
|
7683
|
+
this.nodeType = "CharObject";
|
|
7684
|
+
this.expr = expr;
|
|
7685
|
+
}
|
|
7686
|
+
latex() {
|
|
7687
|
+
return this.expr + this.latexScripts();
|
|
7688
|
+
}
|
|
7689
|
+
arabicLatex() {
|
|
7690
|
+
const sup = this.superscript !== null ? this.superscript.arabicLatex() : "";
|
|
7691
|
+
const sub = this.subscript !== null ? this.subscript.arabicLatex() : "";
|
|
7692
|
+
return this.arabicLatexScripts(sup, sub, this.expr);
|
|
7693
|
+
}
|
|
7694
|
+
};
|
|
7695
|
+
var OperatorNode = class extends BaseAstNode {
|
|
7696
|
+
expr;
|
|
7697
|
+
constructor(expr, state = null) {
|
|
7698
|
+
super(state);
|
|
7699
|
+
this.nodeType = "OperatorObject";
|
|
7700
|
+
this.expr = expr;
|
|
7701
|
+
}
|
|
7702
|
+
latex() {
|
|
7703
|
+
return this.expr;
|
|
7704
|
+
}
|
|
7705
|
+
arabicLatex() {
|
|
7706
|
+
return this.expr;
|
|
7707
|
+
}
|
|
7708
|
+
};
|
|
7709
|
+
var DelimiterNode = class extends BaseAstNode {
|
|
7710
|
+
leftDelimExpr;
|
|
7711
|
+
innerExpr;
|
|
7712
|
+
rightDelimExpr;
|
|
7713
|
+
constructor(leftDelimExpr, innerExpr, rightDelimExpr, state = null) {
|
|
7714
|
+
super(state);
|
|
7715
|
+
this.nodeType = "DelimiterObject";
|
|
7716
|
+
this.leftDelimExpr = leftDelimExpr;
|
|
7717
|
+
this.innerExpr = innerExpr;
|
|
7718
|
+
this.rightDelimExpr = rightDelimExpr;
|
|
7719
|
+
}
|
|
7720
|
+
latex() {
|
|
7721
|
+
return this.leftDelimExpr + this.innerExpr.latex() + this.rightDelimExpr + this.latexScripts();
|
|
7722
|
+
}
|
|
7723
|
+
arabicLatex() {
|
|
7724
|
+
const sup = this.superscript !== null ? this.superscript.arabicLatex() : "";
|
|
7725
|
+
const sub = this.subscript !== null ? this.subscript.arabicLatex() : "";
|
|
7726
|
+
const content = this.leftDelimExpr + this.innerExpr.arabicLatex() + this.rightDelimExpr;
|
|
7727
|
+
return this.arabicLatexScripts(sup, sub, content);
|
|
7728
|
+
}
|
|
7729
|
+
};
|
|
7730
|
+
var CommandNode = class extends BaseAstNode {
|
|
7731
|
+
name;
|
|
7732
|
+
optionalArgs;
|
|
7733
|
+
mandatoryArgs;
|
|
7734
|
+
constructor(name, optionalArgs = [], mandatoryArgs = [], state = null) {
|
|
7735
|
+
super(state);
|
|
7736
|
+
this.nodeType = "CommandObject";
|
|
7737
|
+
this.name = name;
|
|
7738
|
+
this.optionalArgs = optionalArgs;
|
|
7739
|
+
this.mandatoryArgs = mandatoryArgs;
|
|
7740
|
+
}
|
|
7741
|
+
latex() {
|
|
7742
|
+
const content = renderCommandCore({
|
|
7743
|
+
name: this.name,
|
|
7744
|
+
optionalArgs: this.optionalArgs,
|
|
7745
|
+
mandatoryArgs: this.mandatoryArgs,
|
|
7746
|
+
renderChain: (chain) => chain.latex()
|
|
7747
|
+
});
|
|
7748
|
+
return content + this.latexScripts();
|
|
7749
|
+
}
|
|
7750
|
+
arabicLatex() {
|
|
7751
|
+
const sup = this.superscript !== null ? this.superscript.arabicLatex() : "";
|
|
7752
|
+
const sub = this.subscript !== null ? this.subscript.arabicLatex() : "";
|
|
7753
|
+
const arabicName = this.name === "\\sqrt" || this.name === "\\arabsqrt" ? "\\arsqrt" : this.name;
|
|
7754
|
+
const content = renderCommandCore({
|
|
7755
|
+
name: arabicName,
|
|
7756
|
+
optionalArgs: this.optionalArgs,
|
|
7757
|
+
mandatoryArgs: this.mandatoryArgs,
|
|
7758
|
+
renderChain: (chain) => chain.arabicLatex()
|
|
7759
|
+
});
|
|
7760
|
+
return this.arabicLatexScripts(sup, sub, content);
|
|
7761
|
+
}
|
|
7762
|
+
};
|
|
7763
|
+
var EnvNode = class extends BaseAstNode {
|
|
7764
|
+
opening;
|
|
7765
|
+
lines;
|
|
7766
|
+
closing;
|
|
7767
|
+
constructor(opening, lines = [], closing, state = null) {
|
|
7768
|
+
super(state);
|
|
7769
|
+
this.nodeType = "EnvObject";
|
|
7770
|
+
this.opening = opening;
|
|
7771
|
+
this.lines = lines;
|
|
7772
|
+
this.closing = closing;
|
|
7773
|
+
}
|
|
7774
|
+
latex() {
|
|
7775
|
+
if (this.lines.length === 0) {
|
|
7776
|
+
return this.opening + this.closing + this.latexScripts();
|
|
7777
|
+
}
|
|
7778
|
+
const formattedLines = this.lines.map((line) => ` ${line.latex()}`);
|
|
7779
|
+
const content = formattedLines.join(" \\\\\n");
|
|
7780
|
+
return `${this.opening}
|
|
7781
|
+
${content}
|
|
7782
|
+
${this.closing}` + this.latexScripts();
|
|
7783
|
+
}
|
|
7784
|
+
arabicLatex() {
|
|
7785
|
+
const sup = this.superscript !== null ? this.superscript.arabicLatex() : "";
|
|
7786
|
+
const sub = this.subscript !== null ? this.subscript.arabicLatex() : "";
|
|
7787
|
+
if (this.lines.length === 0) {
|
|
7788
|
+
return this.arabicLatexScripts(sup, sub, this.opening + this.closing);
|
|
7789
|
+
}
|
|
7790
|
+
const formattedLines = this.lines.map((line) => ` ${line.arabicLatex()}`);
|
|
7791
|
+
const content = formattedLines.join(" \\\\\n");
|
|
7792
|
+
const fullContent = `${this.opening}
|
|
7793
|
+
${content}
|
|
7794
|
+
${this.closing}`;
|
|
7795
|
+
return this.arabicLatexScripts(sup, sub, fullContent);
|
|
7796
|
+
}
|
|
7797
|
+
};
|
|
7798
|
+
function parseScripts(node, json, mode) {
|
|
7799
|
+
if (json.superscript) {
|
|
7800
|
+
node.superscript = parseChain(json.superscript, mode);
|
|
7801
|
+
}
|
|
7802
|
+
if (json.subscript) {
|
|
7803
|
+
node.subscript = parseChain(json.subscript, mode);
|
|
7804
|
+
}
|
|
7805
|
+
}
|
|
7806
|
+
function parseNode(json, mode) {
|
|
7807
|
+
if (json.node_type === "DelimiterObject") {
|
|
7808
|
+
const node2 = parseDelimiter(json, mode);
|
|
7809
|
+
parseScripts(node2, json, mode);
|
|
7810
|
+
return node2;
|
|
7811
|
+
}
|
|
7812
|
+
if (json.node_type === "OperatorObject") {
|
|
7813
|
+
if (typeof json.expr !== "string") {
|
|
7814
|
+
throw new Error("OperatorObject requires string expr");
|
|
7815
|
+
}
|
|
7816
|
+
const node2 = new OperatorNode(json.expr);
|
|
7817
|
+
parseScripts(node2, json, mode);
|
|
7818
|
+
return node2;
|
|
7819
|
+
}
|
|
7820
|
+
if (json.node_type === "CommandObject") {
|
|
7821
|
+
const node2 = parseCommand(json, mode);
|
|
7822
|
+
parseScripts(node2, json, mode);
|
|
7823
|
+
return node2;
|
|
7824
|
+
}
|
|
7825
|
+
if (json.node_type === "EnvObject") {
|
|
7826
|
+
const node2 = parseEnv(json, mode);
|
|
7827
|
+
parseScripts(node2, json, mode);
|
|
7828
|
+
return node2;
|
|
7829
|
+
}
|
|
7830
|
+
if (typeof json.expr !== "string") {
|
|
7831
|
+
throw new Error(`${json.node_type} requires string expr`);
|
|
7832
|
+
}
|
|
7833
|
+
let node;
|
|
7834
|
+
if (json.node_type === "NumberObject") {
|
|
7835
|
+
node = new NumberNode(json.expr);
|
|
7836
|
+
} else if (json.node_type === "CharObject") {
|
|
7837
|
+
node = new CharNode(json.expr);
|
|
7838
|
+
} else {
|
|
7839
|
+
throw new Error(`Unsupported node_type: ${json.node_type}`);
|
|
7840
|
+
}
|
|
7841
|
+
parseScripts(node, json, mode);
|
|
7842
|
+
return node;
|
|
7843
|
+
}
|
|
7844
|
+
function parseDelimiter(json, mode) {
|
|
7845
|
+
if (typeof json.left_delim_expr !== "string") {
|
|
7846
|
+
throw new Error("DelimiterObject requires string left_delim_expr");
|
|
7847
|
+
}
|
|
7848
|
+
if (!json.inner_expr || json.inner_expr.node_type !== "ChainClass") {
|
|
7849
|
+
throw new Error("DelimiterObject requires ChainClass inner_expr");
|
|
7850
|
+
}
|
|
7851
|
+
if (typeof json.right_delim_expr !== "string") {
|
|
7852
|
+
throw new Error("DelimiterObject requires string right_delim_expr");
|
|
7853
|
+
}
|
|
7854
|
+
const innerExpr = parseChain(json.inner_expr, mode);
|
|
7855
|
+
return new DelimiterNode(json.left_delim_expr, innerExpr, json.right_delim_expr);
|
|
7856
|
+
}
|
|
7857
|
+
function parseCommand(json, mode) {
|
|
7858
|
+
if (typeof json.name !== "string") {
|
|
7859
|
+
throw new Error("CommandObject requires string name");
|
|
7860
|
+
}
|
|
7861
|
+
const optionalJson = Array.isArray(json.optional_args) ? json.optional_args : [];
|
|
7862
|
+
const mandatoryJson = Array.isArray(json.mandatory_args) ? json.mandatory_args : [];
|
|
7863
|
+
const optionalArgs = optionalJson.map((arg) => parseChain(arg, mode));
|
|
7864
|
+
const mandatoryArgs = mandatoryJson.map((arg) => parseChain(arg, mode));
|
|
7865
|
+
return new CommandNode(json.name, optionalArgs, mandatoryArgs);
|
|
7866
|
+
}
|
|
7867
|
+
function parseEnv(json, mode) {
|
|
7868
|
+
if (typeof json.opening !== "string") {
|
|
7869
|
+
throw new Error("EnvObject requires string opening");
|
|
7870
|
+
}
|
|
7871
|
+
if (typeof json.closing !== "string") {
|
|
7872
|
+
throw new Error("EnvObject requires string closing");
|
|
7873
|
+
}
|
|
7874
|
+
if (!Array.isArray(json.lines)) {
|
|
7875
|
+
throw new Error("EnvObject requires lines array");
|
|
7876
|
+
}
|
|
7877
|
+
const lines = json.lines.map((line) => parseChain(line, mode));
|
|
7878
|
+
return new EnvNode(json.opening, lines, json.closing);
|
|
7879
|
+
}
|
|
7880
|
+
function parseChain(json, mode) {
|
|
7881
|
+
if (json.node_type !== "ChainClass") {
|
|
7882
|
+
throw new Error(`Expected ChainClass, got: ${json.node_type}`);
|
|
7883
|
+
}
|
|
7884
|
+
const nodes = json.chain.map((childJson) => parseNode(childJson, mode));
|
|
7885
|
+
return new ChainNode(nodes);
|
|
7886
|
+
}
|
|
7887
|
+
function fromEnglishJson(json) {
|
|
7888
|
+
if (json.node_type === "ChainClass") {
|
|
7889
|
+
return parseChain(json, "english");
|
|
7890
|
+
}
|
|
7891
|
+
return parseNode(json, "english");
|
|
7892
|
+
}
|
|
7893
|
+
function fromArabicJson(json) {
|
|
7894
|
+
if (json.node_type === "ChainClass") {
|
|
7895
|
+
return parseChain(json, "arabic");
|
|
7896
|
+
}
|
|
7897
|
+
return parseNode(json, "arabic");
|
|
7898
|
+
}
|
|
7899
|
+
|
|
7900
|
+
// src/document/mathObject.ts
|
|
7901
|
+
function isObject(value) {
|
|
7902
|
+
return typeof value === "object" && value !== null;
|
|
7903
|
+
}
|
|
7904
|
+
function isMathObjectJson(value) {
|
|
7905
|
+
return isObject(value) && value.node_type === "MathObject";
|
|
7906
|
+
}
|
|
7907
|
+
function assertChainNode(value) {
|
|
7908
|
+
if (!(value instanceof ChainNode)) {
|
|
7909
|
+
throw new Error("MathObject lines must parse to ChainNode");
|
|
7910
|
+
}
|
|
7911
|
+
return value;
|
|
7912
|
+
}
|
|
7913
|
+
function fromMathObjectJson(json, mode = "english") {
|
|
7914
|
+
if (!isMathObjectJson(json)) {
|
|
7915
|
+
throw new Error('MathObject requires node_type "MathObject"');
|
|
7916
|
+
}
|
|
7917
|
+
if (typeof json.math_mode !== "string") {
|
|
7918
|
+
throw new Error("MathObject requires string math_mode");
|
|
7919
|
+
}
|
|
7920
|
+
if (typeof json.closing !== "string") {
|
|
7921
|
+
throw new Error("MathObject requires string closing");
|
|
7922
|
+
}
|
|
7923
|
+
if (!Array.isArray(json.lines) || json.lines.length === 0) {
|
|
7924
|
+
throw new Error("MathObject requires non-empty lines array");
|
|
7925
|
+
}
|
|
7926
|
+
const parseChain2 = mode === "arabic" ? fromArabicJson : fromEnglishJson;
|
|
7927
|
+
const lines = json.lines.map((line) => assertChainNode(parseChain2(line)));
|
|
7928
|
+
return {
|
|
7929
|
+
nodeType: "MathObject",
|
|
7930
|
+
mathMode: json.math_mode,
|
|
7931
|
+
lines,
|
|
7932
|
+
closing: json.closing
|
|
7933
|
+
};
|
|
7934
|
+
}
|
|
7935
|
+
function scriptsToJson(node, path) {
|
|
7936
|
+
return {
|
|
7937
|
+
...node.superscript ? { superscript: chainToJson(node.superscript, `${path}.superscript`) } : {},
|
|
7938
|
+
...node.subscript ? { subscript: chainToJson(node.subscript, `${path}.subscript`) } : {}
|
|
7939
|
+
};
|
|
7940
|
+
}
|
|
7941
|
+
function nodeToJson(node, path) {
|
|
7942
|
+
const scripts = scriptsToJson(node, path);
|
|
7943
|
+
if (node instanceof CharNode || node instanceof NumberNode || node instanceof OperatorNode) {
|
|
7944
|
+
return { node_type: node.nodeType, expr: node.expr, ...scripts };
|
|
7945
|
+
}
|
|
7946
|
+
if (node instanceof DelimiterNode) {
|
|
7947
|
+
return {
|
|
7948
|
+
node_type: "DelimiterObject",
|
|
7949
|
+
left_delim_expr: node.leftDelimExpr,
|
|
7950
|
+
inner_expr: chainToJson(node.innerExpr, `${path}.inner_expr`),
|
|
7951
|
+
right_delim_expr: node.rightDelimExpr,
|
|
7952
|
+
...scripts
|
|
7953
|
+
};
|
|
7954
|
+
}
|
|
7955
|
+
if (node instanceof CommandNode) {
|
|
7956
|
+
return {
|
|
7957
|
+
node_type: "CommandObject",
|
|
7958
|
+
name: node.name,
|
|
7959
|
+
optional_args: node.optionalArgs.map((arg, index) => chainToJson(arg, `${path}.optional_args[${String(index)}]`)),
|
|
7960
|
+
mandatory_args: node.mandatoryArgs.map((arg, index) => chainToJson(arg, `${path}.mandatory_args[${String(index)}]`)),
|
|
7961
|
+
...scripts
|
|
7962
|
+
};
|
|
7963
|
+
}
|
|
7964
|
+
if (node instanceof EnvNode) {
|
|
7965
|
+
return {
|
|
7966
|
+
node_type: "EnvObject",
|
|
7967
|
+
opening: node.opening,
|
|
7968
|
+
lines: node.lines.map((line, index) => chainToJson(line, `${path}.lines[${String(index)}]`)),
|
|
7969
|
+
closing: node.closing,
|
|
7970
|
+
...scripts
|
|
7971
|
+
};
|
|
7972
|
+
}
|
|
7973
|
+
throw new Error(`Unsupported runtime math node at ${path}: ${node.nodeType}`);
|
|
7974
|
+
}
|
|
7975
|
+
function chainToJson(chain, path) {
|
|
7976
|
+
if (!(chain instanceof ChainNode)) {
|
|
7977
|
+
throw new Error(`Expected live ChainNode at ${path}`);
|
|
7978
|
+
}
|
|
7979
|
+
return {
|
|
7980
|
+
node_type: "ChainClass",
|
|
7981
|
+
chain: chain.chain.map((node, index) => nodeToJson(node, `${path}.chain[${String(index)}]`))
|
|
7982
|
+
};
|
|
7983
|
+
}
|
|
7984
|
+
function toMathObjectJson(math) {
|
|
7985
|
+
if (math.nodeType !== "MathObject" || !Array.isArray(math.lines) || math.lines.length === 0) {
|
|
7986
|
+
throw new Error("Cannot serialize invalid runtime MathObject");
|
|
7987
|
+
}
|
|
7988
|
+
return {
|
|
7989
|
+
node_type: "MathObject",
|
|
7990
|
+
math_mode: math.mathMode,
|
|
7991
|
+
lines: math.lines.map((line, index) => chainToJson(line, `$.lines[${String(index)}]`)),
|
|
7992
|
+
closing: math.closing
|
|
7993
|
+
};
|
|
7994
|
+
}
|
|
7995
|
+
|
|
7996
|
+
// src/document/normalizeCharImport.ts
|
|
7997
|
+
var WRAPPER_SPECS = [
|
|
7998
|
+
...NON_DEFAULT_CHARACTER_FONT_SPECS.flatMap((font) => [
|
|
7999
|
+
{ prefix: font.macro, font: font.id },
|
|
8000
|
+
...(font.importAliases ?? []).map((alias) => ({ prefix: alias, font: font.id }))
|
|
8001
|
+
]),
|
|
8002
|
+
{ prefix: "\\text" }
|
|
8003
|
+
];
|
|
8004
|
+
function readBracedArg(source, openBraceIndex) {
|
|
8005
|
+
if (source[openBraceIndex] !== "{") {
|
|
8006
|
+
return null;
|
|
8007
|
+
}
|
|
8008
|
+
let depth = 0;
|
|
8009
|
+
for (let index = openBraceIndex; index < source.length; index += 1) {
|
|
8010
|
+
const char = source[index];
|
|
8011
|
+
if (char === "{") {
|
|
8012
|
+
depth += 1;
|
|
8013
|
+
} else if (char === "}") {
|
|
8014
|
+
depth -= 1;
|
|
8015
|
+
if (depth === 0) {
|
|
8016
|
+
return { inner: source.slice(openBraceIndex + 1, index), end: index + 1 };
|
|
8017
|
+
}
|
|
8018
|
+
}
|
|
8019
|
+
}
|
|
8020
|
+
return null;
|
|
8021
|
+
}
|
|
8022
|
+
function peelWrapper(source) {
|
|
8023
|
+
for (const wrapper of WRAPPER_SPECS) {
|
|
8024
|
+
if (!source.startsWith(wrapper.prefix)) {
|
|
8025
|
+
continue;
|
|
8026
|
+
}
|
|
8027
|
+
const braced = readBracedArg(source, wrapper.prefix.length);
|
|
8028
|
+
if (!braced || braced.end !== source.length) {
|
|
8029
|
+
continue;
|
|
8030
|
+
}
|
|
8031
|
+
return { inner: braced.inner, font: wrapper.font };
|
|
8032
|
+
}
|
|
8033
|
+
return null;
|
|
8034
|
+
}
|
|
8035
|
+
function normalizeCharImportExpr(expr) {
|
|
8036
|
+
const original = expr;
|
|
8037
|
+
let current = expr;
|
|
8038
|
+
let characterFont = "default";
|
|
8039
|
+
let changed = false;
|
|
8040
|
+
while (true) {
|
|
8041
|
+
const peeled = peelWrapper(current);
|
|
8042
|
+
if (!peeled) {
|
|
8043
|
+
break;
|
|
8044
|
+
}
|
|
8045
|
+
current = peeled.inner;
|
|
8046
|
+
if (peeled.font) {
|
|
8047
|
+
characterFont = peeled.font;
|
|
8048
|
+
}
|
|
8049
|
+
changed = true;
|
|
8050
|
+
}
|
|
8051
|
+
if (!changed) {
|
|
8052
|
+
return { expr: original, characterFont: "default" };
|
|
8053
|
+
}
|
|
8054
|
+
if (current.includes("\\")) {
|
|
8055
|
+
return { expr: original, characterFont: "default" };
|
|
8056
|
+
}
|
|
8057
|
+
return { expr: current, characterFont };
|
|
8058
|
+
}
|
|
8059
|
+
|
|
8060
|
+
// src/document/mathEditorAdapter.ts
|
|
8061
|
+
var COMMAND_FONT_MAP = Object.fromEntries([
|
|
8062
|
+
["\\text", "infer"],
|
|
8063
|
+
...NON_DEFAULT_CHARACTER_FONT_SPECS.flatMap((font) => [
|
|
8064
|
+
[font.macro, font.id],
|
|
8065
|
+
...(font.importAliases ?? []).map((alias) => [alias, font.id])
|
|
8066
|
+
])
|
|
8067
|
+
]);
|
|
8068
|
+
var CHAR_FONT_EXPORT_TEX = Object.fromEntries(
|
|
8069
|
+
NON_DEFAULT_CHARACTER_FONT_SPECS.map((font) => [font.id, font.macro])
|
|
8070
|
+
);
|
|
8071
|
+
function charEditorNodeToAstNode(node) {
|
|
8072
|
+
const font = node.characterFont ?? "default";
|
|
8073
|
+
const charNode = new CharNode(node.expr);
|
|
8074
|
+
if (font === "default") {
|
|
8075
|
+
return charNode;
|
|
8076
|
+
}
|
|
8077
|
+
return new CommandNode(CHAR_FONT_EXPORT_TEX[font], [], [new ChainNode([charNode])]);
|
|
8078
|
+
}
|
|
8079
|
+
function commandIdForTex(tex) {
|
|
8080
|
+
for (const spec of Object.values(ATOMIC_COMMANDS)) {
|
|
8081
|
+
const renderTex = spec.arabicRenderTex;
|
|
8082
|
+
if (spec.englishTex === tex || spec.arabicTex === tex || renderTex === tex) {
|
|
8083
|
+
return spec.id;
|
|
8084
|
+
}
|
|
8085
|
+
}
|
|
8086
|
+
return null;
|
|
8087
|
+
}
|
|
8088
|
+
function operatorCommandIdForTex(tex) {
|
|
8089
|
+
for (const spec of Object.values(ATOMIC_OPERATOR_COMMANDS)) {
|
|
8090
|
+
if (spec.Tex === tex) {
|
|
8091
|
+
return spec.id;
|
|
8092
|
+
}
|
|
8093
|
+
}
|
|
8094
|
+
return null;
|
|
8095
|
+
}
|
|
8096
|
+
function cloneChainWithFreshIds(chain) {
|
|
8097
|
+
return structuredClone(chain);
|
|
8098
|
+
}
|
|
8099
|
+
function attachScripts(astNode, editorNode) {
|
|
8100
|
+
if (astNode.superscript) {
|
|
8101
|
+
const sup = chainToEditorChain(astNode.superscript);
|
|
8102
|
+
if (!sup.editable) {
|
|
8103
|
+
return sup;
|
|
8104
|
+
}
|
|
8105
|
+
editorNode.superscript = sup.chain;
|
|
8106
|
+
}
|
|
8107
|
+
if (astNode.subscript) {
|
|
8108
|
+
const sub = chainToEditorChain(astNode.subscript);
|
|
8109
|
+
if (!sub.editable) {
|
|
8110
|
+
return sub;
|
|
8111
|
+
}
|
|
8112
|
+
editorNode.subscript = sub.chain;
|
|
8113
|
+
}
|
|
8114
|
+
return null;
|
|
8115
|
+
}
|
|
8116
|
+
var MATRIX_ENV_NAMES = /* @__PURE__ */ new Set(["matrix", "pmatrix", "bmatrix", "Bmatrix", "vmatrix", "Vmatrix"]);
|
|
8117
|
+
function isGridEnvName(value) {
|
|
8118
|
+
return MATRIX_ENV_NAMES.has(value) || value === "array" || value === "aligned";
|
|
8119
|
+
}
|
|
8120
|
+
function isMatrixEnvName(value) {
|
|
8121
|
+
return MATRIX_ENV_NAMES.has(value);
|
|
8122
|
+
}
|
|
8123
|
+
function parseEnvOpening(opening) {
|
|
8124
|
+
const match = /^\\begin\{([^}]+)\}(?:\{([lcr]+)\})?$/.exec(opening);
|
|
8125
|
+
if (!match) {
|
|
8126
|
+
return null;
|
|
8127
|
+
}
|
|
8128
|
+
const envName = match[1] ?? "";
|
|
8129
|
+
if (!isGridEnvName(envName)) {
|
|
8130
|
+
return null;
|
|
8131
|
+
}
|
|
8132
|
+
if (envName === "array") {
|
|
8133
|
+
const spec = match[2] ?? "c";
|
|
8134
|
+
return {
|
|
8135
|
+
envName,
|
|
8136
|
+
alignments: spec.split("").map((alignment) => alignment)
|
|
8137
|
+
};
|
|
8138
|
+
}
|
|
8139
|
+
return { envName };
|
|
8140
|
+
}
|
|
8141
|
+
function splitEnvLine(line) {
|
|
8142
|
+
const cells = [];
|
|
8143
|
+
let current = [];
|
|
8144
|
+
for (const node of line.chain) {
|
|
8145
|
+
if (node instanceof OperatorNode && node.expr === "&") {
|
|
8146
|
+
cells.push(new ChainNode(current));
|
|
8147
|
+
current = [];
|
|
8148
|
+
} else {
|
|
8149
|
+
current.push(node);
|
|
8150
|
+
}
|
|
8151
|
+
}
|
|
8152
|
+
cells.push(new ChainNode(current));
|
|
8153
|
+
return cells;
|
|
8154
|
+
}
|
|
8155
|
+
function envToEditorNode(node) {
|
|
8156
|
+
const parsed = parseEnvOpening(node.opening);
|
|
8157
|
+
if (!parsed) {
|
|
8158
|
+
return { editable: false, reason: `\u0628\u064A\u0626\u0629 \u0631\u064A\u0627\u0636\u064A\u0629 \u063A\u064A\u0631 \u0645\u062F\u0639\u0648\u0645\u0629 \u062D\u0627\u0644\u064A\u0627: ${node.opening}` };
|
|
8159
|
+
}
|
|
8160
|
+
const expectedClosing = `\\end{${parsed.envName}}`;
|
|
8161
|
+
if (node.closing !== expectedClosing) {
|
|
8162
|
+
return { editable: false, reason: `\u0625\u063A\u0644\u0627\u0642 \u0628\u064A\u0626\u0629 \u0631\u064A\u0627\u0636\u064A\u0629 \u063A\u064A\u0631 \u0645\u062F\u0639\u0648\u0645 \u062D\u0627\u0644\u064A\u0627: ${node.closing}` };
|
|
8163
|
+
}
|
|
8164
|
+
const rowCells = node.lines.map(splitEnvLine);
|
|
8165
|
+
const rows = Math.max(1, rowCells.length);
|
|
8166
|
+
const columns = Math.max(1, ...rowCells.map((row) => row.length));
|
|
8167
|
+
const env = createGridEnvNode(parsed.envName, rows, columns, parsed.alignments);
|
|
8168
|
+
for (let rowIndex = 0; rowIndex < rows; rowIndex += 1) {
|
|
8169
|
+
const row = rowCells[rowIndex] ?? [];
|
|
8170
|
+
for (let columnIndex = 0; columnIndex < columns; columnIndex += 1) {
|
|
8171
|
+
const cell = chainToEditorChain(row[columnIndex] ?? new ChainNode());
|
|
8172
|
+
if (!cell.editable) {
|
|
8173
|
+
return cell;
|
|
8174
|
+
}
|
|
8175
|
+
env.matrixRows[rowIndex][columnIndex] = cell.chain;
|
|
8176
|
+
}
|
|
8177
|
+
}
|
|
8178
|
+
if (parsed.envName === "array") {
|
|
8179
|
+
env.columnAlignments = Array.from(
|
|
8180
|
+
{ length: columns },
|
|
8181
|
+
(_, index) => parsed.alignments?.[index] ?? "c"
|
|
8182
|
+
);
|
|
8183
|
+
}
|
|
8184
|
+
if (isMatrixEnvName(parsed.envName)) {
|
|
8185
|
+
env.matrixStyle = parsed.envName;
|
|
8186
|
+
}
|
|
8187
|
+
const scripts = attachScripts(node, env);
|
|
8188
|
+
return scripts ?? { editable: true, node: env };
|
|
8189
|
+
}
|
|
8190
|
+
function charFromTextLikeCommand(node) {
|
|
8191
|
+
const commandFont = COMMAND_FONT_MAP[node.name];
|
|
8192
|
+
if (commandFont === void 0) {
|
|
8193
|
+
return null;
|
|
8194
|
+
}
|
|
8195
|
+
if (node.optionalArgs.length > 0 || node.mandatoryArgs.length !== 1) {
|
|
8196
|
+
return null;
|
|
8197
|
+
}
|
|
8198
|
+
const arg = node.mandatoryArgs[0];
|
|
8199
|
+
if (arg.chain.length !== 1) {
|
|
8200
|
+
return null;
|
|
8201
|
+
}
|
|
8202
|
+
const child = arg.chain[0];
|
|
8203
|
+
if (child instanceof CommandNode) {
|
|
8204
|
+
const nested = charFromTextLikeCommand(child);
|
|
8205
|
+
if (!nested?.editable) {
|
|
8206
|
+
return null;
|
|
8207
|
+
}
|
|
8208
|
+
if (commandFont !== "infer") {
|
|
8209
|
+
nested.node.characterFont = commandFont;
|
|
8210
|
+
}
|
|
8211
|
+
const scripts2 = attachScripts(node, nested.node);
|
|
8212
|
+
return scripts2 ?? nested;
|
|
8213
|
+
}
|
|
8214
|
+
if (!(child instanceof CharNode)) {
|
|
8215
|
+
return null;
|
|
8216
|
+
}
|
|
8217
|
+
const normalized = normalizeCharImportExpr(child.expr);
|
|
8218
|
+
const characterFont = commandFont === "infer" ? normalized.characterFont : commandFont;
|
|
8219
|
+
const editorNode = createEditorNode("char", normalized.expr);
|
|
8220
|
+
if (characterFont !== "default") {
|
|
8221
|
+
editorNode.characterFont = characterFont;
|
|
8222
|
+
}
|
|
8223
|
+
const scripts = attachScripts(node, editorNode);
|
|
8224
|
+
return scripts ?? { editable: true, node: editorNode };
|
|
8225
|
+
}
|
|
8226
|
+
function commandToEditorNode(node) {
|
|
8227
|
+
if (node.name === "\\frac" && node.mandatoryArgs.length >= 2) {
|
|
8228
|
+
const frac = createFracNode();
|
|
8229
|
+
const numerator = chainToEditorChain(node.mandatoryArgs[0]);
|
|
8230
|
+
const denominator = chainToEditorChain(node.mandatoryArgs[1]);
|
|
8231
|
+
if (!numerator.editable) {
|
|
8232
|
+
return numerator;
|
|
8233
|
+
}
|
|
8234
|
+
if (!denominator.editable) {
|
|
8235
|
+
return denominator;
|
|
8236
|
+
}
|
|
8237
|
+
frac.numerator = numerator.chain;
|
|
8238
|
+
frac.denominator = denominator.chain;
|
|
8239
|
+
const scripts = attachScripts(node, frac);
|
|
8240
|
+
if (scripts) {
|
|
8241
|
+
return scripts;
|
|
8242
|
+
}
|
|
8243
|
+
return { editable: true, node: frac };
|
|
8244
|
+
}
|
|
8245
|
+
if ((node.name === "\\sqrt" || node.name === "\\arabsqrt" || node.name === "\\arsqrt") && node.mandatoryArgs.length >= 1) {
|
|
8246
|
+
const sqrt = createSqrtNode();
|
|
8247
|
+
const radicand = chainToEditorChain(node.mandatoryArgs[0]);
|
|
8248
|
+
if (!radicand.editable) {
|
|
8249
|
+
return radicand;
|
|
8250
|
+
}
|
|
8251
|
+
sqrt.radicand = radicand.chain;
|
|
8252
|
+
if (node.optionalArgs[0]) {
|
|
8253
|
+
const rootIndex = chainToEditorChain(node.optionalArgs[0]);
|
|
8254
|
+
if (!rootIndex.editable) {
|
|
8255
|
+
return rootIndex;
|
|
8256
|
+
}
|
|
8257
|
+
sqrt.rootIndex = rootIndex.chain;
|
|
8258
|
+
}
|
|
8259
|
+
const scripts = attachScripts(node, sqrt);
|
|
8260
|
+
if (scripts) {
|
|
8261
|
+
return scripts;
|
|
8262
|
+
}
|
|
8263
|
+
return { editable: true, node: sqrt };
|
|
8264
|
+
}
|
|
8265
|
+
if (node.name === "\\overset" && node.mandatoryArgs.length >= 2) {
|
|
8266
|
+
const overset = createOversetNode();
|
|
8267
|
+
const overExpr = chainToEditorChain(node.mandatoryArgs[0]);
|
|
8268
|
+
const baseExpr = chainToEditorChain(node.mandatoryArgs[1]);
|
|
8269
|
+
if (!overExpr.editable) {
|
|
8270
|
+
return overExpr;
|
|
8271
|
+
}
|
|
8272
|
+
if (!baseExpr.editable) {
|
|
8273
|
+
return baseExpr;
|
|
8274
|
+
}
|
|
8275
|
+
overset.overExpr = overExpr.chain;
|
|
8276
|
+
overset.baseExpr = baseExpr.chain;
|
|
8277
|
+
const scripts = attachScripts(node, overset);
|
|
8278
|
+
if (scripts) {
|
|
8279
|
+
return scripts;
|
|
8280
|
+
}
|
|
8281
|
+
return { editable: true, node: overset };
|
|
8282
|
+
}
|
|
8283
|
+
if (node.name === "\\underset" && node.mandatoryArgs.length >= 2) {
|
|
8284
|
+
const underset = createUndersetNode();
|
|
8285
|
+
const underExpr = chainToEditorChain(node.mandatoryArgs[0]);
|
|
8286
|
+
const baseExpr = chainToEditorChain(node.mandatoryArgs[1]);
|
|
8287
|
+
if (!underExpr.editable) {
|
|
8288
|
+
return underExpr;
|
|
8289
|
+
}
|
|
8290
|
+
if (!baseExpr.editable) {
|
|
8291
|
+
return baseExpr;
|
|
8292
|
+
}
|
|
8293
|
+
underset.underExpr = underExpr.chain;
|
|
8294
|
+
underset.baseExpr = baseExpr.chain;
|
|
8295
|
+
const scripts = attachScripts(node, underset);
|
|
8296
|
+
if (scripts) {
|
|
8297
|
+
return scripts;
|
|
8298
|
+
}
|
|
8299
|
+
return { editable: true, node: underset };
|
|
8300
|
+
}
|
|
8301
|
+
const accentId = accentCommandIdFromTex(node.name);
|
|
8302
|
+
if (accentId && node.mandatoryArgs.length >= 1) {
|
|
8303
|
+
const accent = createAccentNode(accentId);
|
|
8304
|
+
const baseExpr = chainToEditorChain(node.mandatoryArgs[0]);
|
|
8305
|
+
if (!baseExpr.editable) {
|
|
8306
|
+
return baseExpr;
|
|
8307
|
+
}
|
|
8308
|
+
accent.baseExpr = baseExpr.chain;
|
|
8309
|
+
const scripts = attachScripts(node, accent);
|
|
8310
|
+
if (scripts) {
|
|
8311
|
+
return scripts;
|
|
8312
|
+
}
|
|
8313
|
+
return { editable: true, node: accent };
|
|
8314
|
+
}
|
|
8315
|
+
const atomicId = commandIdForTex(node.name);
|
|
8316
|
+
if (atomicId && node.optionalArgs.length === 0 && node.mandatoryArgs.length === 0) {
|
|
8317
|
+
const atomic = createEditorNode("atomicCommand", atomicId);
|
|
8318
|
+
const scripts = attachScripts(node, atomic);
|
|
8319
|
+
if (scripts) {
|
|
8320
|
+
return scripts;
|
|
8321
|
+
}
|
|
8322
|
+
return { editable: true, node: atomic };
|
|
8323
|
+
}
|
|
8324
|
+
const operatorId = operatorCommandIdForTex(node.name);
|
|
8325
|
+
if (operatorId && node.optionalArgs.length === 0 && node.mandatoryArgs.length === 0) {
|
|
8326
|
+
const atomicOperator = createEditorNode("atomicOperatorCommand", operatorId);
|
|
8327
|
+
const scripts = attachScripts(node, atomicOperator);
|
|
8328
|
+
if (scripts) {
|
|
8329
|
+
return scripts;
|
|
8330
|
+
}
|
|
8331
|
+
return { editable: true, node: atomicOperator };
|
|
8332
|
+
}
|
|
8333
|
+
const textLike = charFromTextLikeCommand(node);
|
|
8334
|
+
if (textLike) {
|
|
8335
|
+
return textLike;
|
|
8336
|
+
}
|
|
8337
|
+
return { editable: false, reason: `\u0623\u0645\u0631 \u0631\u064A\u0627\u0636\u064A \u063A\u064A\u0631 \u0645\u062F\u0639\u0648\u0645 \u062D\u0627\u0644\u064A\u0627: ${node.name}` };
|
|
8338
|
+
}
|
|
8339
|
+
function astNodeToEditorNode(node) {
|
|
8340
|
+
if (node instanceof CharNode) {
|
|
8341
|
+
const normalized = normalizeCharImportExpr(node.expr);
|
|
8342
|
+
const editorNode = createEditorNode("char", normalized.expr);
|
|
8343
|
+
if (normalized.characterFont !== "default") {
|
|
8344
|
+
editorNode.characterFont = normalized.characterFont;
|
|
8345
|
+
}
|
|
8346
|
+
const scripts = attachScripts(node, editorNode);
|
|
8347
|
+
return scripts ?? { editable: true, node: editorNode };
|
|
8348
|
+
}
|
|
8349
|
+
if (node instanceof NumberNode) {
|
|
8350
|
+
const editorNode = createEditorNode("number", node.expr);
|
|
8351
|
+
const scripts = attachScripts(node, editorNode);
|
|
8352
|
+
return scripts ?? { editable: true, node: editorNode };
|
|
8353
|
+
}
|
|
8354
|
+
if (node instanceof OperatorNode) {
|
|
8355
|
+
return { editable: true, node: createEditorNode("operator", node.expr) };
|
|
8356
|
+
}
|
|
8357
|
+
if (node instanceof DelimiterNode) {
|
|
8358
|
+
const editorNode = createDelimiterNode(node.leftDelimExpr, node.rightDelimExpr);
|
|
8359
|
+
const inner = chainToEditorChain(node.innerExpr);
|
|
8360
|
+
if (!inner.editable) {
|
|
8361
|
+
return inner;
|
|
8362
|
+
}
|
|
8363
|
+
editorNode.innerExpr = inner.chain;
|
|
8364
|
+
const scripts = attachScripts(node, editorNode);
|
|
8365
|
+
return scripts ?? { editable: true, node: editorNode };
|
|
8366
|
+
}
|
|
8367
|
+
if (node instanceof CommandNode) {
|
|
8368
|
+
return commandToEditorNode(node);
|
|
8369
|
+
}
|
|
8370
|
+
if (node instanceof EnvNode) {
|
|
8371
|
+
return envToEditorNode(node);
|
|
8372
|
+
}
|
|
8373
|
+
return { editable: false, reason: `\u0639\u0642\u062F\u0629 \u0631\u064A\u0627\u0636\u064A\u0629 \u063A\u064A\u0631 \u0645\u062F\u0639\u0648\u0645\u0629 \u062D\u0627\u0644\u064A\u0627: ${node.nodeType}` };
|
|
8374
|
+
}
|
|
8375
|
+
function chainToEditorChain(chain) {
|
|
8376
|
+
const nodes = [];
|
|
8377
|
+
for (const astNode of chain.chain) {
|
|
8378
|
+
const converted = astNodeToEditorNode(astNode);
|
|
8379
|
+
if (!converted.editable) {
|
|
8380
|
+
return converted;
|
|
8381
|
+
}
|
|
8382
|
+
nodes.push(converted.node);
|
|
8383
|
+
}
|
|
8384
|
+
return { editable: true, chain: createEditorChain(nodes) };
|
|
8385
|
+
}
|
|
8386
|
+
function mathObjectToEditorSession(math) {
|
|
8387
|
+
if (math.lines.length !== 1) {
|
|
8388
|
+
return { editable: false, reason: "\u062A\u062D\u0631\u064A\u0631 \u0627\u0644\u0645\u0639\u0627\u062F\u0644\u0627\u062A \u0645\u062A\u0639\u062F\u062F\u0629 \u0627\u0644\u0623\u0633\u0637\u0631 \u062F\u0627\u062E\u0644 \u0627\u0644\u0645\u0633\u062A\u0646\u062F \u063A\u064A\u0631 \u0645\u062F\u0639\u0648\u0645 \u0628\u0639\u062F" };
|
|
8389
|
+
}
|
|
8390
|
+
const english = chainToEditorChain(math.lines[0]);
|
|
8391
|
+
if (!english.editable) {
|
|
8392
|
+
return english;
|
|
8393
|
+
}
|
|
8394
|
+
const arabic = cloneChainWithFreshIds(english.chain);
|
|
8395
|
+
const session = createEditorSession(english.chain, arabic, "english");
|
|
8396
|
+
session.sync = buildInitialSyncMap(session.englishTree, session.arabicTree);
|
|
8397
|
+
return { editable: true, session: cloneEditorSession(session) };
|
|
8398
|
+
}
|
|
8399
|
+
function attachAstScripts(editorNode, astNode) {
|
|
8400
|
+
if (editorNode.superscript) {
|
|
8401
|
+
const sup = editorChainToAstChain(editorNode.superscript);
|
|
8402
|
+
if (!sup.ok) {
|
|
8403
|
+
return sup;
|
|
8404
|
+
}
|
|
8405
|
+
astNode.superscript = sup.chain;
|
|
8406
|
+
}
|
|
8407
|
+
if (editorNode.subscript) {
|
|
8408
|
+
const sub = editorChainToAstChain(editorNode.subscript);
|
|
8409
|
+
if (!sub.ok) {
|
|
8410
|
+
return sub;
|
|
8411
|
+
}
|
|
8412
|
+
astNode.subscript = sub.chain;
|
|
8413
|
+
}
|
|
8414
|
+
return null;
|
|
8415
|
+
}
|
|
8416
|
+
function editorEnvOpening(node) {
|
|
8417
|
+
const envName = node.envName ?? node.matrixStyle;
|
|
8418
|
+
if (!envName) {
|
|
8419
|
+
return null;
|
|
8420
|
+
}
|
|
8421
|
+
if (envName === "array") {
|
|
8422
|
+
const spec = (node.columnAlignments ?? []).slice(0, node.matrixRows?.[0]?.length ?? 0).join("") || "c";
|
|
8423
|
+
return { opening: `\\begin{array}{${spec}}`, closing: "\\end{array}" };
|
|
8424
|
+
}
|
|
8425
|
+
return { opening: `\\begin{${envName}}`, closing: `\\end{${envName}}` };
|
|
8426
|
+
}
|
|
8427
|
+
function editorEnvToAstNode(node) {
|
|
8428
|
+
const wrapper = editorEnvOpening(node);
|
|
8429
|
+
if (!wrapper || !node.matrixRows) {
|
|
8430
|
+
return { ok: false, reason: "\u0628\u064A\u0626\u0629 \u0631\u064A\u0627\u0636\u064A\u0629 \u063A\u064A\u0631 \u0645\u062F\u0639\u0648\u0645\u0629 \u062D\u0627\u0644\u064A\u0627" };
|
|
8431
|
+
}
|
|
8432
|
+
const lines = [];
|
|
8433
|
+
for (const row of node.matrixRows) {
|
|
8434
|
+
const lineNodes = [];
|
|
8435
|
+
for (let columnIndex = 0; columnIndex < row.length; columnIndex += 1) {
|
|
8436
|
+
if (columnIndex > 0) {
|
|
8437
|
+
lineNodes.push(new OperatorNode("&"));
|
|
8438
|
+
}
|
|
8439
|
+
const cell = editorChainToAstChain(row[columnIndex]);
|
|
8440
|
+
if (!cell.ok) {
|
|
8441
|
+
return cell;
|
|
8442
|
+
}
|
|
8443
|
+
lineNodes.push(...cell.chain.chain);
|
|
8444
|
+
}
|
|
8445
|
+
lines.push(new ChainNode(lineNodes));
|
|
8446
|
+
}
|
|
8447
|
+
const env = new EnvNode(wrapper.opening, lines, wrapper.closing);
|
|
8448
|
+
const scripts = attachAstScripts(node, env);
|
|
8449
|
+
return scripts ?? { ok: true, node: env };
|
|
8450
|
+
}
|
|
8451
|
+
function accentChainForExport(accent) {
|
|
8452
|
+
if (!accent) {
|
|
8453
|
+
return { ok: true, chain: new ChainNode([]) };
|
|
8454
|
+
}
|
|
8455
|
+
return editorChainToAstChain(accent);
|
|
8456
|
+
}
|
|
8457
|
+
function nodeFromAccentBase(command, accent, base) {
|
|
8458
|
+
if (accent.chain.length > 0) {
|
|
8459
|
+
return new CommandNode(command, [], [accent, base]);
|
|
8460
|
+
}
|
|
8461
|
+
if (base.chain.length === 1) {
|
|
8462
|
+
return base.chain[0];
|
|
8463
|
+
}
|
|
8464
|
+
return new DelimiterNode("", base, "");
|
|
8465
|
+
}
|
|
8466
|
+
function editorNodeToAstNode(node) {
|
|
8467
|
+
let astNode;
|
|
8468
|
+
if (node.kind === "char") {
|
|
8469
|
+
astNode = charEditorNodeToAstNode(node);
|
|
8470
|
+
} else if (node.kind === "number") {
|
|
8471
|
+
astNode = new NumberNode(node.expr);
|
|
8472
|
+
} else if (node.kind === "operator") {
|
|
8473
|
+
astNode = new OperatorNode(node.expr);
|
|
8474
|
+
} else if (node.kind === "delimiter" && node.innerExpr) {
|
|
8475
|
+
const inner = editorChainToAstChain(node.innerExpr);
|
|
8476
|
+
if (!inner.ok) {
|
|
8477
|
+
return inner;
|
|
8478
|
+
}
|
|
8479
|
+
astNode = new DelimiterNode(node.leftDelimExpr, inner.chain, node.rightDelimExpr);
|
|
8480
|
+
} else if (node.kind === "frac" && node.numerator && node.denominator) {
|
|
8481
|
+
const numerator = editorChainToAstChain(node.numerator);
|
|
8482
|
+
const denominator = editorChainToAstChain(node.denominator);
|
|
8483
|
+
if (!numerator.ok) {
|
|
8484
|
+
return numerator;
|
|
8485
|
+
}
|
|
8486
|
+
if (!denominator.ok) {
|
|
8487
|
+
return denominator;
|
|
8488
|
+
}
|
|
8489
|
+
astNode = new CommandNode("\\frac", [], [numerator.chain, denominator.chain]);
|
|
8490
|
+
} else if (node.kind === "sqrt" && node.radicand) {
|
|
8491
|
+
const radicand = editorChainToAstChain(node.radicand);
|
|
8492
|
+
if (!radicand.ok) {
|
|
8493
|
+
return radicand;
|
|
8494
|
+
}
|
|
8495
|
+
const optionalArgs = [];
|
|
8496
|
+
if (node.rootIndex && node.rootIndex.nodes.length > 0) {
|
|
8497
|
+
const rootIndex = editorChainToAstChain(node.rootIndex);
|
|
8498
|
+
if (!rootIndex.ok) {
|
|
8499
|
+
return rootIndex;
|
|
8500
|
+
}
|
|
8501
|
+
optionalArgs.push(rootIndex.chain);
|
|
8502
|
+
}
|
|
8503
|
+
astNode = new CommandNode("\\sqrt", optionalArgs, [radicand.chain]);
|
|
8504
|
+
} else if (node.kind === "overset" && node.baseExpr) {
|
|
8505
|
+
const accent = accentChainForExport(node.overExpr);
|
|
8506
|
+
if (!accent.ok) {
|
|
8507
|
+
return accent;
|
|
8508
|
+
}
|
|
8509
|
+
const baseExpr = editorChainToAstChain(node.baseExpr);
|
|
8510
|
+
if (!baseExpr.ok) {
|
|
8511
|
+
return baseExpr;
|
|
8512
|
+
}
|
|
8513
|
+
astNode = nodeFromAccentBase("\\overset", accent.chain, baseExpr.chain);
|
|
8514
|
+
} else if (node.kind === "underset" && node.baseExpr) {
|
|
8515
|
+
const accent = accentChainForExport(node.underExpr);
|
|
8516
|
+
if (!accent.ok) {
|
|
8517
|
+
return accent;
|
|
8518
|
+
}
|
|
8519
|
+
const baseExpr = editorChainToAstChain(node.baseExpr);
|
|
8520
|
+
if (!baseExpr.ok) {
|
|
8521
|
+
return baseExpr;
|
|
8522
|
+
}
|
|
8523
|
+
astNode = nodeFromAccentBase("\\underset", accent.chain, baseExpr.chain);
|
|
8524
|
+
} else if (node.kind === "accent" && node.baseExpr) {
|
|
8525
|
+
const tex = accentCommandSpec(node.expr)?.englishTex;
|
|
8526
|
+
if (!tex) {
|
|
8527
|
+
return { ok: false, reason: `\u0644\u0643\u0646\u0629 \u0631\u064A\u0627\u0636\u064A\u0629 \u063A\u064A\u0631 \u0645\u062F\u0639\u0648\u0645\u0629 \u062D\u0627\u0644\u064A\u0627: ${node.expr}` };
|
|
8528
|
+
}
|
|
8529
|
+
const baseExpr = editorChainToAstChain(node.baseExpr);
|
|
8530
|
+
if (!baseExpr.ok) {
|
|
8531
|
+
return baseExpr;
|
|
8532
|
+
}
|
|
8533
|
+
astNode = new CommandNode(tex, [], [baseExpr.chain]);
|
|
8534
|
+
} else if (node.kind === "atomicCommand") {
|
|
8535
|
+
const tex = atomicCommandSpec(node.expr)?.englishTex;
|
|
8536
|
+
if (!tex) {
|
|
8537
|
+
return { ok: false, reason: `\u0623\u0645\u0631 \u0631\u064A\u0627\u0636\u064A \u063A\u064A\u0631 \u0645\u062F\u0639\u0648\u0645 \u062D\u0627\u0644\u064A\u0627: ${node.expr}` };
|
|
8538
|
+
}
|
|
8539
|
+
astNode = new CommandNode(tex);
|
|
8540
|
+
} else if (node.kind === "atomicOperatorCommand") {
|
|
8541
|
+
const tex = atomicOperatorCommandSpec(node.expr)?.Tex;
|
|
8542
|
+
if (!tex) {
|
|
8543
|
+
return { ok: false, reason: `\u0631\u0645\u0632 \u0631\u064A\u0627\u0636\u064A \u063A\u064A\u0631 \u0645\u062F\u0639\u0648\u0645 \u062D\u0627\u0644\u064A\u0627: ${node.expr}` };
|
|
8544
|
+
}
|
|
8545
|
+
astNode = new CommandNode(tex);
|
|
8546
|
+
} else if (node.kind === "env") {
|
|
8547
|
+
return editorEnvToAstNode(node);
|
|
8548
|
+
} else {
|
|
8549
|
+
return { ok: false, reason: `\u0639\u0642\u062F\u0629 \u0631\u064A\u0627\u0636\u064A\u0629 \u063A\u064A\u0631 \u0645\u062F\u0639\u0648\u0645\u0629 \u062D\u0627\u0644\u064A\u0627: ${node.kind}` };
|
|
8550
|
+
}
|
|
8551
|
+
const scripts = attachAstScripts(node, astNode);
|
|
8552
|
+
return scripts ?? { ok: true, node: astNode };
|
|
8553
|
+
}
|
|
8554
|
+
function editorChainToAstChain(chain) {
|
|
8555
|
+
const nodes = [];
|
|
8556
|
+
for (const editorNode of chain.nodes) {
|
|
8557
|
+
const converted = editorNodeToAstNode(editorNode);
|
|
8558
|
+
if (!converted.ok) {
|
|
8559
|
+
return converted;
|
|
8560
|
+
}
|
|
8561
|
+
nodes.push(converted.node);
|
|
8562
|
+
}
|
|
8563
|
+
return { ok: true, chain: new ChainNode(nodes) };
|
|
8564
|
+
}
|
|
8565
|
+
function mathNodeFromEditorSession(session, mathMode = "$", closing = "$") {
|
|
8566
|
+
const converted = editorChainToAstChain(session.englishTree);
|
|
8567
|
+
if (!converted.ok) {
|
|
8568
|
+
return converted;
|
|
8569
|
+
}
|
|
8570
|
+
return {
|
|
8571
|
+
ok: true,
|
|
8572
|
+
math: {
|
|
8573
|
+
nodeType: "MathObject",
|
|
8574
|
+
mathMode,
|
|
8575
|
+
lines: [converted.chain],
|
|
8576
|
+
closing
|
|
8577
|
+
}
|
|
8578
|
+
};
|
|
8579
|
+
}
|
|
8580
|
+
|
|
8581
|
+
// src/debugJson.ts
|
|
8582
|
+
function lineColumnForPosition(text, position) {
|
|
8583
|
+
const before = text.slice(0, Math.max(0, position));
|
|
8584
|
+
const lines = before.split("\n");
|
|
8585
|
+
return {
|
|
8586
|
+
line: lines.length,
|
|
8587
|
+
column: (lines[lines.length - 1]?.length ?? 0) + 1
|
|
8588
|
+
};
|
|
8589
|
+
}
|
|
8590
|
+
function parseJsonDebugInput(text) {
|
|
8591
|
+
try {
|
|
8592
|
+
return { ok: true, value: JSON.parse(text) };
|
|
8593
|
+
} catch (error) {
|
|
8594
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8595
|
+
const positionMatch = message.match(/position\s+(\d+)/i);
|
|
8596
|
+
if (positionMatch) {
|
|
8597
|
+
const position = Number(positionMatch[1]);
|
|
8598
|
+
if (Number.isFinite(position)) {
|
|
8599
|
+
const location = lineColumnForPosition(text, position);
|
|
8600
|
+
return { ok: false, error: `Invalid JSON at line ${String(location.line)}, column ${String(location.column)}: ${message}` };
|
|
8601
|
+
}
|
|
8602
|
+
}
|
|
8603
|
+
return { ok: false, error: `Invalid JSON: ${message}` };
|
|
8604
|
+
}
|
|
8605
|
+
}
|
|
8606
|
+
|
|
7420
8607
|
// src/react/ButexEditor.tsx
|
|
7421
8608
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7422
8609
|
var DIGIT_FORM_OPTIONS = [
|
|
@@ -7532,6 +8719,7 @@ ${latex || messages.empty}`;
|
|
|
7532
8719
|
var ButexEditor = forwardRef(
|
|
7533
8720
|
function ButexEditor2({ className, debug = false, defaultSide, uiLocale = "ar", initialSession, onSessionChange }, ref) {
|
|
7534
8721
|
const messages = equationEditorMessages(uiLocale);
|
|
8722
|
+
const debugEnabled = debug || typeof window !== "undefined" && new URLSearchParams(window.location.search).get("debug") === "1";
|
|
7535
8723
|
const wrapperRef = useRef(null);
|
|
7536
8724
|
const surfaceRef = useRef(null);
|
|
7537
8725
|
const inputRef = useRef(null);
|
|
@@ -7549,7 +8737,7 @@ var ButexEditor = forwardRef(
|
|
|
7549
8737
|
const digitFormBtnRef = useRef(null);
|
|
7550
8738
|
const runtimeRef = useRef(null);
|
|
7551
8739
|
const debugRef = useRef(debug);
|
|
7552
|
-
debugRef.current =
|
|
8740
|
+
debugRef.current = debugEnabled;
|
|
7553
8741
|
const uiLocaleRef = useRef(uiLocale);
|
|
7554
8742
|
uiLocaleRef.current = uiLocale;
|
|
7555
8743
|
const onSessionChangeRef = useRef(onSessionChange);
|
|
@@ -7557,6 +8745,9 @@ var ButexEditor = forwardRef(
|
|
|
7557
8745
|
const debugBodyHiddenRef = useRef(false);
|
|
7558
8746
|
const [debugBodyHidden, setDebugBodyHidden] = useState(false);
|
|
7559
8747
|
debugBodyHiddenRef.current = debugBodyHidden;
|
|
8748
|
+
const [debugImportOpen, setDebugImportOpen] = useState(false);
|
|
8749
|
+
const [debugImportText, setDebugImportText] = useState("");
|
|
8750
|
+
const [debugImportError, setDebugImportError] = useState("");
|
|
7560
8751
|
const [digitMenuOpen, setDigitMenuOpen] = useState(false);
|
|
7561
8752
|
const [characterFontMenuOpen, setCharacterFontMenuOpen] = useState(false);
|
|
7562
8753
|
const [delimiterMenuOpen, setDelimiterMenuOpen] = useState(false);
|
|
@@ -7637,6 +8828,54 @@ ${arabic || currentMessages.empty}`;
|
|
|
7637
8828
|
}, []);
|
|
7638
8829
|
const updatePreviewRef = useRef(updatePreview);
|
|
7639
8830
|
updatePreviewRef.current = updatePreview;
|
|
8831
|
+
async function copyDebugText(text) {
|
|
8832
|
+
try {
|
|
8833
|
+
await navigator.clipboard.writeText(text);
|
|
8834
|
+
} catch {
|
|
8835
|
+
}
|
|
8836
|
+
}
|
|
8837
|
+
function currentMathObjectJsonText() {
|
|
8838
|
+
const session = runtimeRef.current?.getSession();
|
|
8839
|
+
if (!session) {
|
|
8840
|
+
return "";
|
|
8841
|
+
}
|
|
8842
|
+
const math = mathNodeFromEditorSession(session);
|
|
8843
|
+
if (!math.ok) {
|
|
8844
|
+
return "";
|
|
8845
|
+
}
|
|
8846
|
+
return JSON.stringify(toMathObjectJson(math.math), null, 2);
|
|
8847
|
+
}
|
|
8848
|
+
function openDebugMathObjectImport() {
|
|
8849
|
+
setDebugImportText(currentMathObjectJsonText());
|
|
8850
|
+
setDebugImportError("");
|
|
8851
|
+
setDebugImportOpen(true);
|
|
8852
|
+
}
|
|
8853
|
+
function applyDebugMathObjectImport() {
|
|
8854
|
+
const parsed = parseJsonDebugInput(debugImportText);
|
|
8855
|
+
if (!parsed.ok) {
|
|
8856
|
+
setDebugImportError(parsed.error);
|
|
8857
|
+
return;
|
|
8858
|
+
}
|
|
8859
|
+
try {
|
|
8860
|
+
const math = fromMathObjectJson(parsed.value, activeEditorSide);
|
|
8861
|
+
const result = mathObjectToEditorSession(math);
|
|
8862
|
+
if (!result.editable) {
|
|
8863
|
+
setDebugImportError(result.reason);
|
|
8864
|
+
return;
|
|
8865
|
+
}
|
|
8866
|
+
const next = { ...result.session, activeSide: activeEditorSide };
|
|
8867
|
+
runtimeRef.current?.setSession(next);
|
|
8868
|
+
setSelectedDigitForm(next.currentDigitForm ?? "western");
|
|
8869
|
+
setSelectedCharacterFont(next.currentCharacterFont ?? "default");
|
|
8870
|
+
setActiveEditorSide(next.activeSide);
|
|
8871
|
+
onSessionChangeRef.current?.(next);
|
|
8872
|
+
setDebugImportError("");
|
|
8873
|
+
setDebugImportOpen(false);
|
|
8874
|
+
void updatePreviewRef.current(next);
|
|
8875
|
+
} catch (importError) {
|
|
8876
|
+
setDebugImportError(importError instanceof Error ? importError.message : String(importError));
|
|
8877
|
+
}
|
|
8878
|
+
}
|
|
7640
8879
|
useEffect(() => {
|
|
7641
8880
|
injectWidgetChromeCss();
|
|
7642
8881
|
injectBuTeXEditorStyles(typeof document !== "undefined" ? document : void 0);
|
|
@@ -8797,7 +10036,7 @@ ${arabic || currentMessages.empty}`;
|
|
|
8797
10036
|
/* @__PURE__ */ jsx("div", { ref: renderErrorRef, className: "error", hidden: true })
|
|
8798
10037
|
] }),
|
|
8799
10038
|
/* @__PURE__ */ jsx("section", { className: "panel panel-preview", "aria-label": messages.renderPreview, children: /* @__PURE__ */ jsx("div", { ref: mathOutputRef, className: "preview-box" }) }),
|
|
8800
|
-
|
|
10039
|
+
debugEnabled ? /* @__PURE__ */ jsxs("section", { className: "panel", children: [
|
|
8801
10040
|
/* @__PURE__ */ jsxs("div", { className: "dev-strip", children: [
|
|
8802
10041
|
/* @__PURE__ */ jsx("span", { className: "dev-badge", children: messages.development }),
|
|
8803
10042
|
/* @__PURE__ */ jsx("div", { ref: latexLinesRef, className: "ascii" }),
|
|
@@ -8805,6 +10044,8 @@ ${arabic || currentMessages.empty}`;
|
|
|
8805
10044
|
] }),
|
|
8806
10045
|
/* @__PURE__ */ jsxs("div", { style: { marginTop: 12 }, children: [
|
|
8807
10046
|
/* @__PURE__ */ jsxs("div", { className: "debug-head", children: [
|
|
10047
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => void copyDebugText(currentMathObjectJsonText()), children: "Copy MathObject JSON" }),
|
|
10048
|
+
/* @__PURE__ */ jsx("button", { type: "button", "aria-expanded": debugImportOpen, onClick: openDebugMathObjectImport, children: "Import MathObject JSON" }),
|
|
8808
10049
|
/* @__PURE__ */ jsx(
|
|
8809
10050
|
"button",
|
|
8810
10051
|
{
|
|
@@ -8840,6 +10081,35 @@ ${arabic || currentMessages.empty}`;
|
|
|
8840
10081
|
}
|
|
8841
10082
|
)
|
|
8842
10083
|
] }),
|
|
10084
|
+
debugImportOpen ? /* @__PURE__ */ jsxs("div", { className: "debug-json-import", children: [
|
|
10085
|
+
/* @__PURE__ */ jsx(
|
|
10086
|
+
"textarea",
|
|
10087
|
+
{
|
|
10088
|
+
value: debugImportText,
|
|
10089
|
+
"aria-label": "Import MathObject JSON",
|
|
10090
|
+
spellCheck: false,
|
|
10091
|
+
onChange: (event) => {
|
|
10092
|
+
setDebugImportText(event.currentTarget.value);
|
|
10093
|
+
setDebugImportError("");
|
|
10094
|
+
}
|
|
10095
|
+
}
|
|
10096
|
+
),
|
|
10097
|
+
/* @__PURE__ */ jsxs("div", { className: "debug-head", children: [
|
|
10098
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: applyDebugMathObjectImport, children: "Apply" }),
|
|
10099
|
+
/* @__PURE__ */ jsx(
|
|
10100
|
+
"button",
|
|
10101
|
+
{
|
|
10102
|
+
type: "button",
|
|
10103
|
+
onClick: () => {
|
|
10104
|
+
setDebugImportOpen(false);
|
|
10105
|
+
setDebugImportError("");
|
|
10106
|
+
},
|
|
10107
|
+
children: "Cancel"
|
|
10108
|
+
}
|
|
10109
|
+
)
|
|
10110
|
+
] }),
|
|
10111
|
+
debugImportError ? /* @__PURE__ */ jsx("p", { className: "debug-json-error", children: debugImportError }) : null
|
|
10112
|
+
] }) : null,
|
|
8843
10113
|
/* @__PURE__ */ jsx("div", { ref: debugLogRef, className: "debug-log" })
|
|
8844
10114
|
] })
|
|
8845
10115
|
] }) : null
|