fable-editor 1.0.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.
Files changed (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +175 -0
  3. package/dist/angular/LICENSE +21 -0
  4. package/dist/angular/README.md +175 -0
  5. package/dist/angular/angular/fable-editor.component.d.ts +29 -0
  6. package/dist/angular/angular/fable-editor.module.d.ts +7 -0
  7. package/dist/angular/angular/index.d.ts +2 -0
  8. package/dist/angular/core/config.d.ts +17 -0
  9. package/dist/angular/core/docx-import.d.ts +1 -0
  10. package/dist/angular/core/editor.d.ts +219 -0
  11. package/dist/angular/core/i18n.d.ts +139 -0
  12. package/dist/angular/core/icons.d.ts +2 -0
  13. package/dist/angular/core/index.d.ts +7 -0
  14. package/dist/angular/core/paste-engine.d.ts +6 -0
  15. package/dist/angular/core/types.d.ts +87 -0
  16. package/dist/angular/esm2022/angular/fable-editor.component.mjs +101 -0
  17. package/dist/angular/esm2022/angular/fable-editor.module.mjs +16 -0
  18. package/dist/angular/esm2022/angular/index.mjs +3 -0
  19. package/dist/angular/esm2022/core/config.mjs +122 -0
  20. package/dist/angular/esm2022/core/docx-import.mjs +391 -0
  21. package/dist/angular/esm2022/core/editor.mjs +2700 -0
  22. package/dist/angular/esm2022/core/i18n.mjs +278 -0
  23. package/dist/angular/esm2022/core/icons.mjs +89 -0
  24. package/dist/angular/esm2022/core/index.mjs +6 -0
  25. package/dist/angular/esm2022/core/paste-engine.mjs +482 -0
  26. package/dist/angular/esm2022/core/types.mjs +2 -0
  27. package/dist/angular/esm2022/fable-editor.mjs +5 -0
  28. package/dist/angular/esm2022/index.mjs +2 -0
  29. package/dist/angular/fesm2022/fable-editor.mjs +4176 -0
  30. package/dist/angular/fesm2022/fable-editor.mjs.map +1 -0
  31. package/dist/angular/index.d.ts +1 -0
  32. package/dist/core/config.d.ts +18 -0
  33. package/dist/core/config.d.ts.map +1 -0
  34. package/dist/core/docx-import.d.ts +2 -0
  35. package/dist/core/docx-import.d.ts.map +1 -0
  36. package/dist/core/editor.css +1175 -0
  37. package/dist/core/editor.d.ts +221 -0
  38. package/dist/core/editor.d.ts.map +1 -0
  39. package/dist/core/i18n.d.ts +141 -0
  40. package/dist/core/i18n.d.ts.map +1 -0
  41. package/dist/core/icons.d.ts +3 -0
  42. package/dist/core/icons.d.ts.map +1 -0
  43. package/dist/core/index.cjs +12 -0
  44. package/dist/core/index.d.ts +8 -0
  45. package/dist/core/index.d.ts.map +1 -0
  46. package/dist/core/index.mjs +2789 -0
  47. package/dist/core/paste-engine.d.ts +7 -0
  48. package/dist/core/paste-engine.d.ts.map +1 -0
  49. package/dist/core/types.d.ts +88 -0
  50. package/dist/core/types.d.ts.map +1 -0
  51. package/dist/react/FableEditor.d.ts +13 -0
  52. package/dist/react/FableEditor.d.ts.map +1 -0
  53. package/dist/react/index.cjs +41 -0
  54. package/dist/react/index.d.ts +3 -0
  55. package/dist/react/index.d.ts.map +1 -0
  56. package/dist/react/index.mjs +3471 -0
  57. package/package.json +105 -0
  58. package/style.css +1175 -0
@@ -0,0 +1,2789 @@
1
+ const W = {
2
+ en: {
3
+ dir: "ltr",
4
+ file: "File",
5
+ edit: "Edit",
6
+ view: "View",
7
+ insert: "Insert",
8
+ format: "Format",
9
+ tools: "Tools",
10
+ table: "Table",
11
+ help: "Help",
12
+ newdoc: "New document",
13
+ preview: "Preview",
14
+ print: "Print…",
15
+ undo: "Undo",
16
+ redo: "Redo",
17
+ cut: "Cut",
18
+ copy: "Copy",
19
+ paste: "Paste",
20
+ selectall: "Select all",
21
+ fullscreen: "Fullscreen",
22
+ sourcecode: "Source code",
23
+ wordcount: "Word count",
24
+ image: "Image…",
25
+ inserttable: "Table",
26
+ hr: "Horizontal line",
27
+ charmap: "Special character…",
28
+ datetime: "Date/time",
29
+ pagebreak: "Page break",
30
+ nbsp: "Nonbreaking space",
31
+ bold: "Bold",
32
+ italic: "Italic",
33
+ underline: "Underline",
34
+ strikethrough: "Strikethrough",
35
+ superscript: "Superscript",
36
+ subscript: "Subscript",
37
+ clearformat: "Clear formatting",
38
+ rowabove: "Insert row before",
39
+ rowbelow: "Insert row after",
40
+ delrow: "Delete row",
41
+ colbefore: "Insert column before",
42
+ colafter: "Insert column after",
43
+ delcol: "Delete column",
44
+ deltable: "Delete table",
45
+ ltr: "Left to right",
46
+ rtl: "Right to left",
47
+ alignleft: "Align left",
48
+ aligncenter: "Align center",
49
+ alignright: "Align right",
50
+ alignjustify: "Justify",
51
+ numlist: "Numbered list",
52
+ bullist: "Bullet list",
53
+ forecolor: "Text color",
54
+ backcolor: "Background color",
55
+ removeformat: "Clear formatting",
56
+ outdent: "Decrease indent",
57
+ indent: "Increase indent",
58
+ fontfamily: "Font family",
59
+ fontsize: "Font size",
60
+ blocks: "Blocks",
61
+ quickimage: "Insert image",
62
+ quicktable: "Insert table",
63
+ more: "More…",
64
+ para: "Paragraph",
65
+ heading: "Heading",
66
+ pre: "Preformatted",
67
+ removecolor: "Remove color",
68
+ currentcolor: "Current color",
69
+ statushelp: "Press Alt+0 for help",
70
+ words: "words",
71
+ helpttl: "Help",
72
+ shortcuts: "Handy shortcuts",
73
+ close: "Close",
74
+ save: "Save",
75
+ cancel: "Cancel",
76
+ srcttl: "Source code",
77
+ wcttl: "Word count",
78
+ wcwords: "Words",
79
+ wcchars: "Characters",
80
+ pastehint: "Use Ctrl+V / ⌘V to paste",
81
+ liststyles_ol: ["Default", "Lower alpha", "Lower roman", "Upper alpha", "Upper roman"],
82
+ liststyles_ul: ["Default", "Circle", "Square"],
83
+ previewttl: "Preview",
84
+ tablepropsttl: "Table properties",
85
+ tblwidth: "Width",
86
+ tblcellspacing: "Cell spacing",
87
+ tblcellpadding: "Cell padding",
88
+ tblborder: "Border width",
89
+ tblalign: "Alignment",
90
+ alignnone: "None",
91
+ quote: "Blockquote",
92
+ link: "Link…",
93
+ linkttl: "Insert/edit link",
94
+ linkurl: "URL",
95
+ unlink: "Remove link",
96
+ lineheight: "Line height",
97
+ wordspacing: "Word spacing",
98
+ changecase: "Change case",
99
+ lowercase: "Lowercase",
100
+ uppercase: "Uppercase",
101
+ capitalize: "Capitalize Each Word",
102
+ customcolor: "Custom color…",
103
+ normal: "Normal",
104
+ revhistory: "Revision history",
105
+ revempty: "No revisions yet",
106
+ restore: "Restore",
107
+ currentver: "Current version",
108
+ importword: "Import from Word…",
109
+ importfail: "Could not import this file. Please choose a valid .docx document.",
110
+ restoredraft: "Restore last draft",
111
+ draftempty: "No saved draft found",
112
+ deleteimg: "Delete image",
113
+ rotateleft: "Rotate left",
114
+ rotateright: "Rotate right",
115
+ fliphorizontal: "Flip horizontal",
116
+ flipvertical: "Flip vertical",
117
+ cell: "Cell",
118
+ row: "Row",
119
+ column: "Column",
120
+ cellprops: "Cell properties…",
121
+ rowprops: "Row properties…",
122
+ colprops: "Column properties…",
123
+ tblheight: "Height",
124
+ valign: "Vertical align",
125
+ valigntop: "Top",
126
+ valignmiddle: "Middle",
127
+ valignbottom: "Bottom",
128
+ fill: "Fill",
129
+ nocell: "Click inside a table cell first",
130
+ uploadimg: "Upload from computer",
131
+ imagelink: "Insert from URL",
132
+ imageurlph: "Paste image URL…",
133
+ insertimg: "Insert",
134
+ dropimage: "Drop image here",
135
+ uploading: "Uploading…",
136
+ uploadfailed: "Upload failed — click to retry"
137
+ },
138
+ ar: {
139
+ dir: "rtl",
140
+ file: "ملف",
141
+ edit: "تحرير",
142
+ view: "عرض",
143
+ insert: "إدراج",
144
+ format: "التنسيق",
145
+ tools: "الأدوات",
146
+ table: "جدول",
147
+ help: "تعليمات",
148
+ newdoc: "مستند جديد",
149
+ preview: "معاينة",
150
+ print: "طباعة…",
151
+ undo: "تراجع",
152
+ redo: "إعادة",
153
+ cut: "قص",
154
+ copy: "نسخ",
155
+ paste: "لصق",
156
+ selectall: "تحديد الكل",
157
+ fullscreen: "ملء الشاشة",
158
+ sourcecode: "الكود المصدري",
159
+ wordcount: "عدد الكلمات",
160
+ image: "صورة…",
161
+ inserttable: "جدول",
162
+ hr: "خط أفقي",
163
+ charmap: "رمز خاص…",
164
+ datetime: "التاريخ/الوقت",
165
+ pagebreak: "فاصل الصفحة",
166
+ nbsp: "مسافة غير فاصلة",
167
+ bold: "غامق",
168
+ italic: "مائل",
169
+ underline: "تسطير",
170
+ strikethrough: "يتوسطه خط",
171
+ superscript: "نص مرتفع",
172
+ subscript: "نص منخفض",
173
+ clearformat: "مسح التنسيق",
174
+ rowabove: "إدراج صف قبل",
175
+ rowbelow: "إدراج صف بعد",
176
+ delrow: "حذف الصف",
177
+ colbefore: "إدراج عمود قبل",
178
+ colafter: "إدراج عمود بعد",
179
+ delcol: "حذف العمود",
180
+ deltable: "حذف الجدول",
181
+ ltr: "من اليسار إلى اليمين",
182
+ rtl: "من اليمين إلى اليسار",
183
+ alignleft: "محاذاة لليسار",
184
+ aligncenter: "توسيط",
185
+ alignright: "محاذاة لليمين",
186
+ alignjustify: "ضبط",
187
+ numlist: "قائمة رقمية",
188
+ bullist: "قائمة نقطية",
189
+ forecolor: "لون النص",
190
+ backcolor: "لون الخلفية",
191
+ removeformat: "مسح التنسيق",
192
+ outdent: "إنقاص المسافة البادئة",
193
+ indent: "زيادة المسافة البادئة",
194
+ fontfamily: "عائلة الخط",
195
+ fontsize: "حجم الخط",
196
+ blocks: "الفقرات",
197
+ quickimage: "إدراج صورة",
198
+ quicktable: "إدراج جدول",
199
+ more: "المزيد…",
200
+ para: "الفقرة",
201
+ heading: "العنوان",
202
+ pre: "منسق مسبقاً",
203
+ removecolor: "إزالة اللون",
204
+ currentcolor: "اللون الحالي",
205
+ statushelp: "اضغط على Alt+0 للحصول على مساعدة",
206
+ words: "الكلمات",
207
+ helpttl: "تعليمات",
208
+ shortcuts: "اختصارات مفيدة",
209
+ close: "إغلاق",
210
+ save: "حفظ",
211
+ cancel: "إلغاء",
212
+ srcttl: "الكود المصدري",
213
+ wcttl: "عدد الكلمات",
214
+ wcwords: "الكلمات",
215
+ wcchars: "الأحرف",
216
+ pastehint: "استخدم Ctrl+V / ⌘V للصق",
217
+ liststyles_ol: ["افتراضي", "أبجدي صغير", "روماني صغير", "أبجدي كبير", "روماني كبير"],
218
+ liststyles_ul: ["افتراضي", "دائرة", "مربع"],
219
+ previewttl: "معاينة",
220
+ tablepropsttl: "خصائص الجدول",
221
+ tblwidth: "العرض",
222
+ tblcellspacing: "تباعد الخلايا",
223
+ tblcellpadding: "حشو الخلايا",
224
+ tblborder: "عرض الحدود",
225
+ tblalign: "المحاذاة",
226
+ alignnone: "بدون",
227
+ quote: "اقتباس",
228
+ link: "رابط…",
229
+ linkttl: "إدراج/تعديل رابط",
230
+ linkurl: "الرابط",
231
+ unlink: "إزالة الرابط",
232
+ lineheight: "تباعد الأسطر",
233
+ wordspacing: "تباعد الكلمات",
234
+ changecase: "تغيير حالة الأحرف",
235
+ lowercase: "أحرف صغيرة",
236
+ uppercase: "أحرف كبيرة",
237
+ capitalize: "تكبير أول حرف",
238
+ customcolor: "لون مخصص…",
239
+ normal: "عادي",
240
+ revhistory: "سجل المراجعات",
241
+ revempty: "لا توجد مراجعات بعد",
242
+ restore: "استعادة",
243
+ currentver: "النسخة الحالية",
244
+ importword: "استيراد من Word…",
245
+ importfail: "تعذر استيراد هذا الملف. الرجاء اختيار مستند ‎.docx صالح.",
246
+ restoredraft: "استعادة آخر مسودة",
247
+ draftempty: "لا توجد مسودة محفوظة",
248
+ deleteimg: "حذف الصورة",
249
+ rotateleft: "تدوير لليسار",
250
+ rotateright: "تدوير لليمين",
251
+ fliphorizontal: "قلب أفقي",
252
+ flipvertical: "قلب رأسي",
253
+ cell: "خلية",
254
+ row: "صف",
255
+ column: "عمود",
256
+ cellprops: "خصائص الخلية…",
257
+ rowprops: "خصائص الصف…",
258
+ colprops: "خصائص العمود…",
259
+ tblheight: "الارتفاع",
260
+ valign: "محاذاة عمودية",
261
+ valigntop: "أعلى",
262
+ valignmiddle: "وسط",
263
+ valignbottom: "أسفل",
264
+ fill: "تعبئة",
265
+ nocell: "انقر داخل خلية جدول أولاً",
266
+ uploadimg: "رفع من الجهاز",
267
+ imagelink: "إدراج من رابط",
268
+ imageurlph: "الصق رابط الصورة…",
269
+ insertimg: "إدراج",
270
+ dropimage: "أسقط الصورة هنا",
271
+ uploading: "جارٍ الرفع…",
272
+ uploadfailed: "فشل الرفع — انقر لإعادة المحاولة"
273
+ }
274
+ };
275
+ function B(p) {
276
+ return W[p];
277
+ }
278
+ const U = "undo redo | preview print | importword revhistory | fontfamily fontsize | fontsizeincrease fontsizedecrease | bold italic underline strikethrough | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist | outdent indent | link blockquote changecase lineheight wordspacing | removeformat | blocks | ltr rtl | quickimage quicktable charmap | fullscreen sourcecode", j = "file edit view insert format tools table help", X = [
279
+ ["Andale Mono", "andale mono,times"],
280
+ ["Arial", "arial,helvetica,sans-serif"],
281
+ ["Arial Black", "arial black,avant garde"],
282
+ ["Book Antiqua", "book antiqua,palatino"],
283
+ ["Comic Sans MS", "comic sans ms,sans-serif"],
284
+ ["Courier New", "courier new,courier"],
285
+ ["Georgia", "georgia,palatino"],
286
+ ["Helvetica", "helvetica"],
287
+ ["Impact", "impact,chicago"],
288
+ ["Oswald", "oswald"],
289
+ ["Sakkal Majalla", "sakkal majalla"],
290
+ ["Symbol", "symbol"],
291
+ ["Tahoma", "tahoma,arial,helvetica,sans-serif"],
292
+ ["Terminal", "terminal,monaco"],
293
+ ["Times New Roman", "times new roman,times"],
294
+ ["Trebuchet MS", "trebuchet ms,geneva"],
295
+ ["Verdana", "verdana,geneva"],
296
+ ["Webdings", "webdings"],
297
+ ["Wingdings", "wingdings,zapf dingbats"]
298
+ ], _ = ["8px", "9px", "10px", "11px", "12px", "14px", "16px", "18px", "20px", "24px", "28px", "32px", "36px", "48px", "72px", "96px"], Q = 1, G = 100, Y = ["1", "1.15", "1.4", "1.5", "1.75", "2", "2.5", "3"], K = ["1px", "2px", "4px", "6px", "8px", "12px"], D = [
299
+ ["p", "para"],
300
+ ["h1", "heading1"],
301
+ ["h2", "heading2"],
302
+ ["h3", "heading3"],
303
+ ["h4", "heading4"],
304
+ ["h5", "heading5"],
305
+ ["h6", "heading6"],
306
+ ["pre", "pre"]
307
+ ], V = ["#F76707", "#4263EB", "#CC5DE8"], J = [
308
+ "#BFEDD2",
309
+ "#FBEEB8",
310
+ "#F8CAC6",
311
+ "#ECCAFA",
312
+ "#C2E0F4",
313
+ "#2DC26B",
314
+ "#F1C40F",
315
+ "#E03E2D",
316
+ "#B96AD9",
317
+ "#3598DB",
318
+ "#169179",
319
+ "#E67E23",
320
+ "#BA372A",
321
+ "#843FA1",
322
+ "#236FA1",
323
+ "#ECF0F1",
324
+ "#CED4D9",
325
+ "#95A5A6",
326
+ "#7E8C8D",
327
+ "#34495E",
328
+ "#000000",
329
+ "#FFFFFF"
330
+ ], tt = [
331
+ "©",
332
+ "®",
333
+ "™",
334
+ "§",
335
+ "¶",
336
+ "†",
337
+ "‡",
338
+ "•",
339
+ "…",
340
+ "′",
341
+ "″",
342
+ "‰",
343
+ "°",
344
+ "±",
345
+ "×",
346
+ "÷",
347
+ "≈",
348
+ "≠",
349
+ "≤",
350
+ "≥",
351
+ "∞",
352
+ "µ",
353
+ "√",
354
+ "∑",
355
+ "€",
356
+ "£",
357
+ "¥",
358
+ "¢",
359
+ "←",
360
+ "→",
361
+ "↑",
362
+ "↓",
363
+ "«",
364
+ "»",
365
+ "“",
366
+ "”",
367
+ "‘",
368
+ "’",
369
+ "–",
370
+ "—",
371
+ "؟",
372
+ "،",
373
+ "؛",
374
+ "٪",
375
+ "٭",
376
+ "ـ",
377
+ "٠",
378
+ "١"
379
+ ], w = (p, t) => `<svg viewBox="${t || "0 0 24 24"}">${p}</svg>`, u = (p) => w(`<path class="f" d="${p}"/>`, "0 -960 960 960"), k = (p, t = 7.5) => w(
380
+ '<path d="M10 6h10M10 12h10M10 18h10"/>' + p.map(
381
+ (e, i) => `<text x="2.5" y="${8.4 + i * 6}" font-size="${t}" stroke="none" fill="#222f3e" font-family="Arial">${e}</text>`
382
+ ).join("")
383
+ ), a = {
384
+ bold: u(
385
+ "M272-200v-560h221q65 0 120 40t55 111q0 51-23 78.5T602-491q25 11 55.5 41t30.5 90q0 89-65 124.5T501-200H272Zm121-112h104q48 0 58.5-24.5T566-372q0-11-10.5-35.5T494-432H393v120Zm0-228h93q33 0 48-17t15-38q0-24-17-39t-44-15h-95v109Z"
386
+ ),
387
+ italic: u("M200-200v-100h160l120-360H320v-100h400v100H580L460-300h140v100H200Z"),
388
+ underline: u(
389
+ "M200-120v-80h560v80H200Zm123-223q-56-63-56-167v-330h103v336q0 56 28 91t82 35q54 0 82-35t28-91v-336h103v330q0 104-56 167t-157 63q-101 0-157-63Z"
390
+ ),
391
+ strikethrough: u(
392
+ "M486-160q-76 0-135-45t-85-123l88-38q14 48 48.5 79t85.5 31q42 0 76-20t34-64q0-18-7-33t-19-27h112q5 14 7.5 28.5T694-340q0 86-61.5 133T486-160ZM80-480v-80h800v80H80Zm402-326q66 0 115.5 32.5T674-674l-88 39q-9-29-33.5-52T484-710q-41 0-68 18.5T386-640h-96q2-69 54.5-117.5T482-806Z"
393
+ ),
394
+ undo: u("M280-200v-80h284q63 0 109.5-40T720-420q0-60-46.5-100T564-560H312l104 104-56 56-200-200 200-200 56 56-104 104h252q97 0 166.5 63T800-420q0 94-69.5 157T564-200H280Z"),
395
+ redo: u("M396-200q-97 0-166.5-63T160-420q0-94 69.5-157T396-640h252L544-744l56-56 200 200-200 200-56-56 104-104H396q-63 0-109.5 40T240-420q0 60 46.5 100T396-280h284v80H396Z"),
396
+ ltr: u(
397
+ "M360-360v-200q-66 0-113-47t-47-113q0-66 47-113t113-47h320v80h-80v440h-80v-440h-80v440h-80Zm0-280v-160q-33 0-56.5 23.5T280-720q0 33 23.5 56.5T360-640Zm0-80ZM680-80l-56-56 64-64H120v-80h568l-64-64 56-56 160 160L680-80Z"
398
+ ),
399
+ rtl: u(
400
+ "M360-360v-200q-66 0-113-47t-47-113q0-66 47-113t113-47h320v80h-80v440h-80v-440h-80v440h-80Zm-88 160 64 64-56 56-160-160 160-160 56 56-64 64h568v80H272Zm88-440v-160q-33 0-56.5 23.5T280-720q0 33 23.5 56.5T360-640Zm0-80Z"
401
+ ),
402
+ alignleft: u(
403
+ "M120-120v-80h720v80H120Zm0-160v-80h480v80H120Zm0-160v-80h720v80H120Zm0-160v-80h480v80H120Zm0-160v-80h720v80H120Z"
404
+ ),
405
+ aligncenter: u(
406
+ "M120-120v-80h720v80H120Zm160-160v-80h400v80H280ZM120-440v-80h720v80H120Zm160-160v-80h400v80H280ZM120-760v-80h720v80H120Z"
407
+ ),
408
+ alignright: u(
409
+ "M120-760v-80h720v80H120Zm240 160v-80h480v80H360ZM120-440v-80h720v80H120Zm240 160v-80h480v80H360ZM120-120v-80h720v80H120Z"
410
+ ),
411
+ alignjustify: u(
412
+ "M120-120v-80h720v80H120Zm0-160v-80h720v80H120Zm0-160v-80h720v80H120Zm0-160v-80h720v80H120Zm0-160v-80h720v80H120Z"
413
+ ),
414
+ fullscreen: u(
415
+ "M120-120v-200h80v120h120v80H120Zm520 0v-80h120v-120h80v200H640ZM120-640v-200h200v80H200v120h-80Zm640 0v-120H640v-80h200v200h-80Z"
416
+ ),
417
+ clearformatic: u(
418
+ "m528-546-93-93-121-121h486v120H568l-40 94ZM792-56 460-388l-80 188H249l119-280L56-792l56-56 736 736-56 56Z"
419
+ ),
420
+ numlist: u(
421
+ "M120-80v-60h100v-30h-60v-60h60v-30H120v-60h120q17 0 28.5 11.5T280-280v40q0 17-11.5 28.5T240-200q17 0 28.5 11.5T280-160v40q0 17-11.5 28.5T240-80H120Zm0-280v-110q0-17 11.5-28.5T160-510h60v-30H120v-60h120q17 0 28.5 11.5T280-560v70q0 17-11.5 28.5T240-450h-60v30h100v60H120Zm60-280v-180h-60v-60h120v240h-60Zm180 440v-80h480v80H360Zm0-240v-80h480v80H360Zm0-240v-80h480v80H360Z"
422
+ ),
423
+ bullist: u(
424
+ "M360-200v-80h480v80H360Zm0-240v-80h480v80H360Zm0-240v-80h480v80H360ZM200-160q-33 0-56.5-23.5T120-240q0-33 23.5-56.5T200-320q33 0 56.5 23.5T280-240q0 33-23.5 56.5T200-160Zm0-240q-33 0-56.5-23.5T120-480q0-33 23.5-56.5T200-560q33 0 56.5 23.5T280-480q0 33-23.5 56.5T200-400Zm-56.5-263.5Q120-687 120-720t23.5-56.5Q167-800 200-800t56.5 23.5Q280-753 280-720t-23.5 56.5Q233-640 200-640t-56.5-23.5Z"
425
+ ),
426
+ chev: w('<path d="M2 3.5 6 7.5 10 3.5"/>', "0 0 12 11"),
427
+ backcolor: u(
428
+ "M440-80q-33 0-56.5-23.5T360-160v-160H240q-33 0-56.5-23.5T160-400v-280q0-66 47-113t113-47h480v440q0 33-23.5 56.5T720-320H600v160q0 33-23.5 56.5T520-80h-80ZM240-560h480v-200h-40v160h-80v-160h-40v80h-80v-80H320q-33 0-56.5 23.5T240-680v120Zm0 160h480v-80H240v80Zm0 0v-80 80Z"
429
+ ),
430
+ outdent: u(
431
+ "M120-120v-80h720v80H120Zm320-160v-80h400v80H440Zm0-160v-80h400v80H440Zm0-160v-80h400v80H440ZM120-760v-80h720v80H120Zm160 440L120-480l160-160v320Z"
432
+ ),
433
+ indent: u(
434
+ "M120-120v-80h720v80H120Zm320-160v-80h400v80H440Zm0-160v-80h400v80H440Zm0-160v-80h400v80H440ZM120-760v-80h720v80H120Zm0 440v-320l160 160-160 160Z"
435
+ ),
436
+ more: w(
437
+ '<circle class="f" cx="5" cy="12" r="1.7"/><circle class="f" cx="12" cy="12" r="1.7"/><circle class="f" cx="19" cy="12" r="1.7"/>'
438
+ ),
439
+ image: u(
440
+ "M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm40-80h480L570-480 450-320l-90-120-120 160Zm-40 80v-560 560Z"
441
+ ),
442
+ uploadic: u(
443
+ "M440-200v-326L336-422l-56-58 200-200 200 200-56 58-104-104v326h-80ZM240-80q-33 0-56.5-23.5T160-160v-120h80v120h480v-120h80v120q0 33-23.5 56.5T720-80H240Z"
444
+ ),
445
+ tableic: u(
446
+ "M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm240-240H200v160h240v-160Zm80 0v160h240v-160H520Zm-80-80v-160H200v160h240Zm80 0h240v-160H520v160ZM200-680h560v-80H200v80Z"
447
+ ),
448
+ hric: w('<path d="M4 12h16"/>'),
449
+ charic: u(
450
+ "M120-120v-120h200q-84-45-132-125t-48-175q0-142 99-241t241-99q142 0 241 99t99 241q0 95-48 175T640-240h200v120H520v-204q78-14 129-75t51-141q0-92-64-156t-156-64q-92 0-156 64t-64 156q0 80 51 141t129 75v204H120Z"
451
+ ),
452
+ dateic: w(
453
+ '<rect x="4" y="6" width="16" height="14" rx="1.5"/><path d="M4 10h16M8 4v4M16 4v4"/>'
454
+ ),
455
+ pbic: u(
456
+ "M240-80q-33 0-56.5-23.5T160-160v-120h80v120h480v-120h80v120q0 33-23.5 56.5T720-80H240Zm-80-440v-280q0-33 23.5-56.5T240-880h320l240 240v120h-80v-80H520v-200H240v280h-80Zm200 160v-80h240v80H360Zm320 0v-80h240v80H680Zm-640 0v-80h240v80H40Zm440-160Zm0 240Z"
457
+ ),
458
+ nbspic: w('<path d="M6 12v4h12v-4"/>'),
459
+ srcic: u(
460
+ "M240-280 40-480l200-200 56 56-143 144 143 144-56 56Zm178 132-76-24 200-640 76 24-200 640Zm302-132-56-56 143-144-143-144 56-56 200 200-200 200Z"
461
+ ),
462
+ prevw: u(
463
+ "M607.5-372.5Q660-425 660-500t-52.5-127.5Q555-680 480-680t-127.5 52.5Q300-575 300-500t52.5 127.5Q405-320 480-320t127.5-52.5Zm-204-51Q372-455 372-500t31.5-76.5Q435-608 480-608t76.5 31.5Q588-545 588-500t-31.5 76.5Q525-392 480-392t-76.5-31.5ZM214-281.5Q94-363 40-500q54-137 174-218.5T480-800q146 0 266 81.5T920-500q-54 137-174 218.5T480-200q-146 0-266-81.5ZM480-500Zm207.5 160.5Q782-399 832-500q-50-101-144.5-160.5T480-720q-113 0-207.5 59.5T128-500q50 101 144.5 160.5T480-280q113 0 207.5-59.5Z"
464
+ ),
465
+ printic: u(
466
+ "M640-640v-120H320v120h-80v-200h480v200h-80Zm-480 80h640-640Zm560 100q17 0 28.5-11.5T760-500q0-17-11.5-28.5T720-540q-17 0-28.5 11.5T680-500q0 17 11.5 28.5T720-460Zm-80 260v-160H320v160h320Zm80 80H240v-160H80v-240q0-51 35-85.5t85-34.5h560q51 0 85.5 34.5T880-520v240H720v160Zm80-240v-160q0-17-11.5-28.5T760-560H200q-17 0-28.5 11.5T160-520v160h80v-80h480v80h80Z"
467
+ ),
468
+ cutic: u(
469
+ "M760-120 480-400l-94 94q8 15 11 32t3 34q0 66-47 113T240-80q-66 0-113-47T80-240q0-66 47-113t113-47q17 0 34 3t32 11l94-94-94-94q-15 8-32 11t-34 3q-66 0-113-47T80-720q0-66 47-113t113-47q66 0 113 47t47 113q0 17-3 34t-11 32l494 494v40H760ZM600-520l-80-80 240-240h120v40L600-520ZM296.5-663.5Q320-687 320-720t-23.5-56.5Q273-800 240-800t-56.5 23.5Q160-753 160-720t23.5 56.5Q207-640 240-640t56.5-23.5ZM494-466q6-6 6-14t-6-14q-6-6-14-6t-14 6q-6 6-6 14t6 14q6 6 14 6t14-6ZM296.5-183.5Q320-207 320-240t-23.5-56.5Q273-320 240-320t-56.5 23.5Q160-273 160-240t23.5 56.5Q207-160 240-160t56.5-23.5Z"
470
+ ),
471
+ copyic: u(
472
+ "M360-240q-33 0-56.5-23.5T280-320v-480q0-33 23.5-56.5T360-880h360q33 0 56.5 23.5T800-800v480q0 33-23.5 56.5T720-240H360Zm0-80h360v-480H360v480ZM200-80q-33 0-56.5-23.5T120-160v-560h80v560h440v80H200Zm160-240v-480 480Z"
473
+ ),
474
+ pasteic: u(
475
+ "M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h167q11-35 43-57.5t70-22.5q40 0 71.5 22.5T594-840h166q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560h-80v120H280v-120h-80v560Zm308.5-571.5Q520-783 520-800t-11.5-28.5Q497-840 480-840t-28.5 11.5Q440-817 440-800t11.5 28.5Q463-760 480-760t28.5-11.5Z"
476
+ ),
477
+ selall: u(
478
+ "M280-280v-400h400v400H280Zm80-80h240v-240H360v240ZM200-200v80q-33 0-56.5-23.5T120-200h80Zm-80-80v-80h80v80h-80Zm0-160v-80h80v80h-80Zm0-160v-80h80v80h-80Zm80-160h-80q0-33 23.5-56.5T200-840v80Zm80 640v-80h80v80h-80Zm0-640v-80h80v80h-80Zm160 640v-80h80v80h-80Zm0-640v-80h80v80h-80Zm160 640v-80h80v80h-80Zm0-640v-80h80v80h-80Zm160 640v-80h80q0 33-23.5 56.5T760-120Zm0-160v-80h80v80h-80Zm0-160v-80h80v80h-80Zm0-160v-80h80v80h-80Zm0-160v-80q33 0 56.5 23.5T840-760h-80Z"
479
+ ),
480
+ superscriptic: u(
481
+ "M760-600v-80q0-17 11.5-28.5T800-720h80v-40H760v-40h120q17 0 28.5 11.5T920-760v40q0 17-11.5 28.5T880-680h-80v40h120v40H760ZM235-160l185-291-172-269h106l124 200h4l123-200h107L539-451l186 291H618L482-377h-4L342-160H235Z"
482
+ ),
483
+ subscriptic: u(
484
+ "M760-160v-80q0-17 11.5-28.5T800-280h80v-40H760v-40h120q17 0 28.5 11.5T920-320v40q0 17-11.5 28.5T880-240h-80v40h120v40H760Zm-525-80 185-291-172-269h106l124 200h4l123-200h107L539-531l186 291H618L482-457h-4L342-240H235Z"
485
+ ),
486
+ newic: w('<path d="M6 3h8l5 5v13H6z"/><path d="M14 3v5h5"/>'),
487
+ helpic: w(
488
+ '<circle cx="12" cy="12" r="8.5"/><path d="M9.6 9.6a2.5 2.5 0 1 1 3.4 2.6c-.8.3-1 .9-1 1.8"/><circle class="f" cx="12" cy="16.6" r="1.1"/>'
489
+ ),
490
+ wcic: w('<path d="M4 6h16M4 10h16M4 14h9"/><path d="M15 17.5l2 2 3.6-4"/>'),
491
+ rowbefore: u(
492
+ "M200-160h560v-240H200v240Zm640 80H120v-720h160v80h-80v240h560v-240h-80v-80h160v720ZM480-480Zm0 80v-80 80Zm0 0Zm-40-240v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80Z"
493
+ ),
494
+ rowafter: u(
495
+ "M200-560h560v-240H200v240Zm-80 400v-720h720v720H680v-80h80v-240H200v240h80v80H120Zm360-320Zm0-80v80-80Zm0 0ZM440-80v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80Z"
496
+ ),
497
+ rowdelete: u(
498
+ "M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200ZM200-200h560v-560H200ZM200-400v-160h560v160H200ZM330-580l250 250 50-50-250-250ZM330-380l250-250 50 50-250 250Z"
499
+ ),
500
+ colbefore: u(
501
+ "M800-200v-560H560v560h240Zm-640 80v-160h80v80h240v-560H240v80h-80v-160h720v720H160Zm320-360Zm80 0h-80 80Zm0 0ZM160-360v-80H80v-80h80v-80h80v80h80v80h-80v80h-80Z"
502
+ ),
503
+ colafter: u(
504
+ "M160-760v560h240v-560H160ZM80-120v-720h720v160h-80v-80H480v560h240v-80h80v160H80Zm400-360Zm-80 0h80-80Zm0 0Zm320 120v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80Z"
505
+ ),
506
+ coldelete: u(
507
+ "M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200ZM200-200h560v-560H200ZM400-200v-560h160v560H400ZM330-580l250 250 50-50-250-250ZM330-380l250-250 50 50-250 250Z"
508
+ ),
509
+ tabledelete: w(
510
+ '<rect x="4" y="5" width="16" height="14" rx="1.5"/><path d="M4 10h16M4 14.5h16M9.5 5v14M14.5 5v14"/><path d="M6.5 6.5l11 11M17.5 6.5l-11 11" stroke-width="2.1"/>'
511
+ ),
512
+ quote: u(
513
+ "m228-240 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T458-480L320-240h-92Zm360 0 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T818-480L680-240h-92ZM362.5-517.5Q380-535 380-560t-17.5-42.5Q345-620 320-620t-42.5 17.5Q260-585 260-560t17.5 42.5Q295-500 320-500t42.5-17.5Zm360 0Q740-535 740-560t-17.5-42.5Q705-620 680-620t-42.5 17.5Q620-585 620-560t17.5 42.5Q655-500 680-500t42.5-17.5ZM680-560Zm-360 0Z"
514
+ ),
515
+ link: u(
516
+ "M440-280H280q-83 0-141.5-58.5T80-480q0-83 58.5-141.5T280-680h160v80H280q-50 0-85 35t-35 85q0 50 35 85t85 35h160v80ZM320-440v-80h320v80H320Zm200 160v-80h160q50 0 85-35t35-85q0-50-35-85t-85-35H520v-80h160q83 0 141.5 58.5T880-480q0 83-58.5 141.5T680-280H520Z"
517
+ ),
518
+ unlink: w(
519
+ '<path d="M13.5 6.5l1.7-1.7a4 4 0 0 1 5.6 5.6L19 12.2"/><path d="M10.5 17.5l-1.7 1.7a4 4 0 0 1-5.6-5.6L5 11.8"/><path d="M4 4l16 16"/>'
520
+ ),
521
+ lineheight: u(
522
+ "M240-160 80-320l56-56 64 62v-332l-64 62-56-56 160-160 160 160-56 56-64-62v332l64-62 56 56-160 160Zm240-40v-80h400v80H480Zm0-240v-80h400v80H480Zm0-240v-80h400v80H480Z"
523
+ ),
524
+ wordspacing: u(
525
+ "M320-80 160-240l160-160 57 56-64 64h334l-63-64 56-56 160 160L640-80l-57-56 64-64H313l63 64-56 56ZM200-480v-400h80v400h-80Zm240 0v-400h80v400h-80Zm240 0v-400h80v400h-80Z"
526
+ ),
527
+ caseic: u(
528
+ "m131-252 165-440h79l165 440h-76l-39-112H247l-40 112h-76Zm139-176h131l-64-182h-4l-63 182Zm395 186q-51 0-81-27.5T554-342q0-44 34.5-72.5T677-443q23 0 45 4t38 11v-12q0-29-20.5-47T685-505q-23 0-42 9.5T610-468l-47-35q24-29 54.5-43t68.5-14q69 0 103 32.5t34 97.5v178h-63v-37h-4q-14 23-38 35t-53 12Zm12-54q35 0 59.5-24t24.5-56q-14-8-33.5-12.5T689-393q-32 0-50 14t-18 37q0 20 16 33t40 13Z"
529
+ ),
530
+ uppercaseic: u(
531
+ "M660-240v-248l-64 64-56-56 160-160 160 160-56 56-64-64v248h-80Zm-540 0 165-440h79l165 440h-76l-39-113H236l-40 113h-76Zm139-177h131l-65-182h-4l-62 182Z"
532
+ ),
533
+ lowercaseic: u(
534
+ "M300-240q-51 0-81-27.5T189-340q0-44 34.5-72.5T312-441q23 0 45 4t38 11v-12q0-29-20.5-47T320-503q-23 0-42 9.5T245-466l-47-35q24-29 54.5-43t68.5-14q69 0 103 32.5t34 97.5v178h-63v-37h-4q-14 23-38 35t-53 12Zm12-54q35 0 59.5-24t24.5-56q-14-8-33.5-12.5T324-391q-32 0-50 14t-18 37q0 20 16 33t40 13Zm388 54L540-400l56-56 64 64v-248h80v248l64-64 56 56-160 160Z"
535
+ ),
536
+ capitalizeic: u(
537
+ "M344-250v-366H224v-64h308v64H412v366h-68Zm344 10q-44 0-69-25.5T594-336v-162h-54v-58h54v-87h66v87h74v58h-74v148q0 23 10.5 36t28.5 13q9 0 18.5-3.5T736-314v65q-10 5-22 7t-26 2Z"
538
+ ),
539
+ plus: w('<path d="M12 5.5v13M5.5 12h13"/>'),
540
+ minus: w('<path d="M5.5 12h13"/>'),
541
+ fontsizeup: u(
542
+ "m40-200 210-560h100l210 560h-96l-51-143H187l-51 143H40Zm176-224h168l-82-232h-4l-82 232Zm504 104v-120H600v-80h120v-120h80v120h120v80H800v120h-80Z"
543
+ ),
544
+ fontsizedown: u(
545
+ "m40-200 210-560h100l210 560h-96l-51-143H187l-51 143H40Zm176-224h168l-82-232h-4l-82 232Zm384-16v-80h320v80H600Z"
546
+ ),
547
+ historyic: u(
548
+ "M480-120q-138 0-240.5-91.5T122-440h82q14 104 92.5 172T480-200q117 0 198.5-81.5T760-480q0-117-81.5-198.5T480-760q-69 0-129 32t-101 88h110v80H120v-240h80v94q51-64 124.5-99T480-840q75 0 140.5 28.5t114 77q48.5 48.5 77 114T840-480q0 75-28.5 140.5t-77 114q-48.5 48.5-114 77T480-120Zm112-192L440-464v-216h80v184l128 128-56 56Z"
549
+ ),
550
+ wordic: w(
551
+ '<path d="M6 3h8l5 5v13H6z"/><path d="M14 3v5h5"/><text x="8" y="17" font-size="8.5" stroke="none" fill="#222f3e" font-family="Arial" font-weight="bold">W</text>'
552
+ ),
553
+ draftic: u(
554
+ "M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z"
555
+ ),
556
+ trash: w(
557
+ '<path d="M5 7h14M10 7V5h4v2M7.5 7l1 13h7l1-13"/>'
558
+ ),
559
+ rotateleft: w(
560
+ '<polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/>'
561
+ ),
562
+ rotateright: w(
563
+ '<polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/>'
564
+ ),
565
+ fliphorizontal: w(
566
+ '<path d="M12 3v18"/><path d="M7 8l-4 4 4 4"/><path d="M17 8l4 4-4 4"/>'
567
+ ),
568
+ flipvertical: w(
569
+ '<path d="M3 12h18"/><path d="M8 7l4-4 4 4"/><path d="M8 17l4 4 4-4"/>'
570
+ ),
571
+ check: w('<path d="M5 12.5 9.5 17 19 7"/>'),
572
+ palette: w(
573
+ '<path d="M12 3a9 9 0 1 0 0 18h1.2a2 2 0 0 0 2-2 2 2 0 0 1 2-2H18a3 3 0 0 0 3-3c0-6.1-4.5-11-9-11z"/><circle class="f" cx="7.8" cy="10.2" r="1.3"/><circle class="f" cx="11.6" cy="7.3" r="1.3"/><circle class="f" cx="15.8" cy="9.6" r="1.3"/><circle class="f" cx="9" cy="14.8" r="1.3"/>'
574
+ ),
575
+ ul_circle: u(
576
+ "M280-600v-80h560v80H280Zm0 160v-80h560v80H280Zm0 160v-80h560v80H280ZM160-600q-17 0-28.5-11.5T120-640q0-17 11.5-28.5T160-680q17 0 28.5 11.5T200-640q0 17-11.5 28.5T160-600Zm0 160q-17 0-28.5-11.5T120-480q0-17 11.5-28.5T160-520q17 0 28.5 11.5T200-480q0 17-11.5 28.5T160-440Zm0 160q-17 0-28.5-11.5T120-320q0-17 11.5-28.5T160-360q17 0 28.5 11.5T200-320q0 17-11.5 28.5T160-280Z"
577
+ ),
578
+ ul_square: u(
579
+ "M80-160v-160h160v160H80Zm240 0v-160h560v160H320ZM80-400v-160h160v160H80Zm240 0v-160h560v160H320ZM80-640v-160h160v160H80Zm240 0v-160h560v160H320Z"
580
+ ),
581
+ ol_alpha: k(["a", "b", "c"]),
582
+ ol_roman: k(["i", "ii", "iii"], 6.5),
583
+ ol_alphau: k(["A", "B", "C"]),
584
+ ol_romanu: k(["I", "II", "III"], 6.5)
585
+ }, yt = (p) => `<span class="txt">${p}</span>`, et = /* @__PURE__ */ new Set([
586
+ "p",
587
+ "div",
588
+ "span",
589
+ "br",
590
+ "hr",
591
+ "a",
592
+ "b",
593
+ "strong",
594
+ "i",
595
+ "em",
596
+ "u",
597
+ "s",
598
+ "strike",
599
+ "sub",
600
+ "sup",
601
+ "h1",
602
+ "h2",
603
+ "h3",
604
+ "h4",
605
+ "h5",
606
+ "h6",
607
+ "blockquote",
608
+ "pre",
609
+ "code",
610
+ "ul",
611
+ "ol",
612
+ "li",
613
+ "table",
614
+ "thead",
615
+ "tbody",
616
+ "tfoot",
617
+ "tr",
618
+ "td",
619
+ "th",
620
+ "caption",
621
+ "colgroup",
622
+ "col",
623
+ "img",
624
+ "figure",
625
+ "figcaption",
626
+ "mark"
627
+ ]), it = /* @__PURE__ */ new Set([
628
+ "text-align",
629
+ "direction",
630
+ "unicode-bidi",
631
+ "font-weight",
632
+ "font-style",
633
+ "text-decoration",
634
+ "text-decoration-line",
635
+ "color",
636
+ "background-color",
637
+ "background",
638
+ "background-image",
639
+ "background-position",
640
+ "background-repeat",
641
+ "background-size",
642
+ "font-size",
643
+ "font-family",
644
+ "line-height",
645
+ "letter-spacing",
646
+ "vertical-align",
647
+ "text-indent",
648
+ "margin",
649
+ "margin-top",
650
+ "margin-bottom",
651
+ "margin-left",
652
+ "margin-right",
653
+ "margin-inline-start",
654
+ "margin-inline-end",
655
+ "padding",
656
+ "padding-top",
657
+ "padding-bottom",
658
+ "padding-left",
659
+ "padding-right",
660
+ "width",
661
+ "height",
662
+ "min-width",
663
+ "max-width",
664
+ "min-height",
665
+ "max-height",
666
+ "border",
667
+ "border-top",
668
+ "border-right",
669
+ "border-bottom",
670
+ "border-left",
671
+ "border-color",
672
+ "border-style",
673
+ "border-width",
674
+ "border-radius",
675
+ "border-collapse",
676
+ "border-spacing",
677
+ "table-layout",
678
+ "float",
679
+ "display",
680
+ "box-sizing",
681
+ "list-style-type",
682
+ "white-space"
683
+ ]), R = {
684
+ "*": ["dir", "lang", "colspan", "rowspan"],
685
+ a: ["href", "target", "rel", "title"],
686
+ img: ["src", "alt", "width", "height", "title"],
687
+ col: ["span", "width"],
688
+ td: ["width", "valign"],
689
+ th: ["width", "valign"],
690
+ table: ["width", "cellpadding", "cellspacing"]
691
+ };
692
+ function Z(p) {
693
+ const t = {}, e = p.getAttribute && p.getAttribute("style");
694
+ return e && e.split(";").forEach((i) => {
695
+ const s = i.indexOf(":");
696
+ s < 1 || (t[i.slice(0, s).trim().toLowerCase()] = i.slice(s + 1).trim());
697
+ }), t;
698
+ }
699
+ function st(p) {
700
+ return p.replace(/<!--\[if !supportLists\]-->([\s\S]*?)<!--\[endif\]-->/gi, "$1").replace(/<!--\[if !supportLists\]>([\s\S]*?)<!\[endif\]-->/gi, "$1").replace(/<!\[if !supportLists\]>([\s\S]*?)<!\[endif\]>/gi, "$1").replace(/<!--\[if [\s\S]*?<!\[endif\]-->/gi, "").replace(/<!--[\s\S]*?-->/g, "").replace(/<(script|style|xml|title)[\s\S]*?<\/\1>/gi, "").replace(/<\/?(meta|link)[^>]*>/gi, "").replace(/<\?xml[\s\S]*?\?>/gi, "").replace(/<\/?(o|v|w|m|st1):[^>]*>/gi, "");
701
+ }
702
+ function lt(p) {
703
+ return /^[0-9]+[\.\)،]/.test(p) ? { ordered: !0 } : /^[٠-٩۰-۹]+/.test(p) ? { ordered: !0, style: "arabic-indic" } : /^[ivxlc]{2,}[\.\)]/.test(p) ? { ordered: !0, style: "lower-roman" } : /^[IVXLC]{2,}[\.\)]/.test(p) ? { ordered: !0, style: "upper-roman" } : /^[a-z][\.\)]/.test(p) ? { ordered: !0, style: "lower-alpha" } : /^[A-Z][\.\)]/.test(p) ? { ordered: !0, style: "upper-alpha" } : /^[ء-ي][\.\)،-]/.test(p) ? { ordered: !0, style: "arabic-indic" } : { ordered: !1 };
704
+ }
705
+ function nt(p) {
706
+ const t = (s) => {
707
+ const l = (s.getAttribute("style") || "") + " " + (s.className || "");
708
+ return /mso-list\s*:(?!\s*ignore)/i.test(l) || /MsoListParagraph/i.test(l);
709
+ }, e = [];
710
+ let i = null;
711
+ Array.from(p.body.querySelectorAll("p")).forEach((s) => {
712
+ if (!t(s)) {
713
+ i = null;
714
+ return;
715
+ }
716
+ const l = s.previousElementSibling;
717
+ i && l && i[i.length - 1] === l ? i.push(s) : (i = [s], e.push(i));
718
+ }), e.forEach((s) => {
719
+ const l = [], n = s[0];
720
+ s.forEach((o) => {
721
+ var T, M, S;
722
+ const c = +(((T = (o.getAttribute("style") || "").match(/level(\d+)/i)) == null ? void 0 : T[1]) || 1), h = Array.from(o.querySelectorAll("span")).find(
723
+ (x) => /mso-list\s*:\s*ignore/i.test(x.getAttribute("style") || "")
724
+ ), d = h ? ((M = h.textContent) == null ? void 0 : M.trim()) || "" : (((S = o.textContent) == null ? void 0 : S.trim().match(/^\S{1,4}/)) || [""])[0], { ordered: m, style: g } = lt(d);
725
+ for (h && h.remove(); l.length && l[l.length - 1].level > c; ) l.pop();
726
+ if (!l.length || l[l.length - 1].level < c) {
727
+ const x = p.createElement(m ? "ol" : "ul");
728
+ if (m && g && (x.style.listStyleType = g), l.length) {
729
+ const E = l[l.length - 1].list;
730
+ (E.lastElementChild || E).appendChild(x);
731
+ } else
732
+ n.parentNode.insertBefore(x, n);
733
+ l.push({ list: x, level: c });
734
+ }
735
+ const f = p.createElement("li"), b = Z(o), v = ["text-align", "direction", "unicode-bidi", "color", "font-size", "font-family", "background-color"].filter((x) => b[x]).map((x) => x + ":" + b[x]).join(";");
736
+ for (v && f.setAttribute("style", v), o.getAttribute("dir") && f.setAttribute("dir", o.getAttribute("dir")); o.firstChild; ) f.appendChild(o.firstChild);
737
+ l[l.length - 1].list.appendChild(f), o.remove();
738
+ });
739
+ });
740
+ }
741
+ function ot(p) {
742
+ p.querySelectorAll('b[id^="docs-internal-guid"]').forEach((t) => {
743
+ for (; t.firstChild; ) t.parentNode.insertBefore(t.firstChild, t);
744
+ t.remove();
745
+ });
746
+ }
747
+ function rt(p) {
748
+ p.querySelectorAll("table").forEach((t) => {
749
+ const e = t;
750
+ Z(e)["border-collapse"] || (e.style.borderCollapse = "collapse");
751
+ }), p.querySelectorAll("[align]").forEach((t) => {
752
+ const e = t, i = e.getAttribute("align").toLowerCase();
753
+ e.tagName.toLowerCase() === "table" ? i === "center" ? (e.style.marginLeft = e.style.marginLeft || "auto", e.style.marginRight = e.style.marginRight || "auto") : i === "right" ? e.style.marginLeft = e.style.marginLeft || "auto" : i === "left" && (e.style.marginRight = e.style.marginRight || "auto") : ["left", "right", "center", "justify"].includes(i) && (e.style.textAlign = e.style.textAlign || i, Array.from(e.children).forEach((s) => {
754
+ if (s.tagName.toLowerCase() !== "table") return;
755
+ const l = s;
756
+ i === "center" ? (l.style.marginLeft = l.style.marginLeft || "auto", l.style.marginRight = l.style.marginRight || "auto") : i === "right" ? l.style.marginLeft = l.style.marginLeft || "auto" : i === "left" && (l.style.marginRight = l.style.marginRight || "auto");
757
+ })), e.removeAttribute("align");
758
+ }), p.querySelectorAll("center table").forEach((t) => {
759
+ const e = t;
760
+ e.style.marginLeft = e.style.marginLeft || "auto", e.style.marginRight = e.style.marginRight || "auto";
761
+ }), p.querySelectorAll("[bgcolor]").forEach((t) => {
762
+ const e = t;
763
+ e.style.backgroundColor = e.style.backgroundColor || e.getAttribute("bgcolor"), e.removeAttribute("bgcolor");
764
+ });
765
+ }
766
+ function L(p, t) {
767
+ Array.from(p.childNodes).forEach((e) => {
768
+ if (e.nodeType === Node.COMMENT_NODE) {
769
+ e.remove();
770
+ return;
771
+ }
772
+ if (e.nodeType !== Node.ELEMENT_NODE) return;
773
+ const i = e, s = i.tagName.toLowerCase();
774
+ if (!et.has(s)) {
775
+ if (s === "font") {
776
+ const r = t.createElement("span");
777
+ i.getAttribute("style") && r.setAttribute("style", i.getAttribute("style")), i.getAttribute("color") && (r.style.color = i.getAttribute("color")), i.getAttribute("face") && (r.style.fontFamily = i.getAttribute("face"));
778
+ const c = i.getAttribute("size");
779
+ if (c && !r.style.fontSize) {
780
+ const h = {
781
+ 1: "8pt",
782
+ 2: "10pt",
783
+ 3: "12pt",
784
+ 4: "14pt",
785
+ 5: "18pt",
786
+ 6: "24pt",
787
+ 7: "36pt"
788
+ };
789
+ h[c] && (r.style.fontSize = h[c]);
790
+ }
791
+ for (; i.firstChild; ) r.appendChild(i.firstChild);
792
+ i.replaceWith(r), L(r, t);
793
+ return;
794
+ }
795
+ for (L(i, t); i.firstChild; ) i.parentNode.insertBefore(i.firstChild, i);
796
+ i.remove();
797
+ return;
798
+ }
799
+ const l = /* @__PURE__ */ new Set([...R["*"] || [], ...R[s] || []]);
800
+ if (Array.from(i.attributes).forEach((r) => {
801
+ const c = r.name.toLowerCase();
802
+ c !== "style" && !l.has(c) && i.removeAttribute(r.name);
803
+ }), s === "a") {
804
+ const r = i.getAttribute("href") || "";
805
+ /^(https?:|mailto:|tel:|#)/i.test(r) || i.removeAttribute("href");
806
+ }
807
+ if (s === "img") {
808
+ const r = i.getAttribute("src") || "";
809
+ if (!/^(https?:|data:image\/|blob:)/i.test(r)) {
810
+ const c = t.createElement("span");
811
+ c.textContent = "[local image — paste it separately]", c.setAttribute("style", "color:#a33;font-style:italic;font-size:12px"), i.replaceWith(c);
812
+ return;
813
+ }
814
+ }
815
+ const n = Z(i), o = [];
816
+ for (const [r, c] of Object.entries(n))
817
+ it.has(r) && (/expression|javascript|url\s*\(\s*['"]?\s*file:/i.test(c) || r === "font-weight" && /^(400|normal)$/i.test(c) || r === "font-style" && /^normal$/i.test(c) || r === "text-decoration" && /^none$/i.test(c) || o.push(r + ":" + c));
818
+ if (o.length ? i.setAttribute("style", o.join(";")) : i.removeAttribute("style"), i.removeAttribute("class"), L(i, t), s === "span" && !i.attributes.length) {
819
+ for (; i.firstChild; ) i.parentNode.insertBefore(i.firstChild, i);
820
+ i.remove();
821
+ }
822
+ });
823
+ }
824
+ function at(p) {
825
+ const t = [], e = /<style[^>]*>([\s\S]*?)<\/style>/gi;
826
+ let i;
827
+ for (; i = e.exec(p); ) {
828
+ let s = i[1].replace(/<!--|-->/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
829
+ s = s.replace(/@media[^{]*\{(?:[^{}]*\{[^{}]*\})*[^{}]*\}/gi, ""), s = s.replace(/@[\w-]+[^{]*\{[^{}]*\}/g, "");
830
+ let l;
831
+ const n = /([^{}]+)\{([^}]*)\}/g;
832
+ for (; l = n.exec(s); ) {
833
+ const o = l[2].split(";").map((r) => {
834
+ const c = r.indexOf(":");
835
+ return c < 1 ? null : [r.slice(0, c).trim().toLowerCase(), r.slice(c + 1).trim()];
836
+ }).filter((r) => !!r && !!r[1]);
837
+ o.length && l[1].split(",").map((r) => r.trim()).filter((r) => r && !r.startsWith("@")).forEach((r) => t.push({ sel: r, decls: o }));
838
+ }
839
+ }
840
+ return t;
841
+ }
842
+ function ct(p, t) {
843
+ if (!t.length) return;
844
+ const e = /* @__PURE__ */ new Map();
845
+ t.forEach(({ sel: i, decls: s }) => {
846
+ let l;
847
+ try {
848
+ l = p.querySelectorAll(i);
849
+ } catch {
850
+ return;
851
+ }
852
+ l.forEach((n) => {
853
+ let o = e.get(n);
854
+ o || (o = {}, e.set(n, o)), s.forEach(([r, c]) => {
855
+ o[r] = c;
856
+ });
857
+ });
858
+ }), e.forEach((i, s) => {
859
+ const l = Z(s), n = s.hasAttribute("dir"), o = s.hasAttribute("align"), r = Object.entries(i).filter(([d]) => !(d in l || (d === "direction" || d === "unicode-bidi") && n || d === "text-align" && (o || n) || (d === "background" || d === "background-color") && s.hasAttribute("bgcolor")));
860
+ if (!r.length) return;
861
+ const c = r.map(([d, m]) => d + ":" + m).join(";"), h = s.getAttribute("style");
862
+ s.setAttribute("style", h ? c + ";" + h : c);
863
+ });
864
+ }
865
+ function z(p) {
866
+ return p.replace(/[ﭐ-﷿ﹰ-ﻼ]+/g, (t) => t.normalize("NFKC"));
867
+ }
868
+ function ht(p) {
869
+ const t = p.createTreeWalker(p.body, NodeFilter.SHOW_TEXT, null);
870
+ let e;
871
+ for (; e = t.nextNode(); )
872
+ /[ﭐ-﷿ﹰ-ﻼ]/.test(e.nodeValue || "") && (e.nodeValue = z(e.nodeValue || ""));
873
+ }
874
+ function dt(p, t = "ltr") {
875
+ const e = at(p), i = new DOMParser().parseFromString(st(p), "text/html");
876
+ ct(i, e), /class="?Mso|mso-|urn:schemas-microsoft-com/i.test(i.body.innerHTML) && nt(i), ot(i), rt(i), L(i.body, i), ht(i);
877
+ const s = (l) => {
878
+ var n;
879
+ return l && l.tagName === "P" && !((n = l.textContent) != null && n.trim()) && !l.querySelector("img,table");
880
+ };
881
+ for (; s(i.body.firstElementChild); ) i.body.firstElementChild.remove();
882
+ for (; s(i.body.lastElementChild); ) i.body.lastElementChild.remove();
883
+ return i.body.innerHTML.trim();
884
+ }
885
+ function pt(p) {
886
+ const t = z(p).replace(/\r/g, ""), e = (i) => i.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
887
+ return /\n/.test(t) ? t.split(/\n{2,}/).map((i) => `<p dir="auto">${e(i).replace(/\n/g, "<br>") || "<br>"}</p>`).join("") : e(t);
888
+ }
889
+ function mt(p) {
890
+ const t = new DataView(p), e = /* @__PURE__ */ new Map();
891
+ let i = -1;
892
+ for (let o = p.byteLength - 22; o >= Math.max(0, p.byteLength - 22 - 65535); o--)
893
+ if (t.getUint32(o, !0) === 101010256) {
894
+ i = o;
895
+ break;
896
+ }
897
+ if (i < 0) throw new Error("EOCD not found");
898
+ const s = t.getUint16(i + 10, !0);
899
+ let l = t.getUint32(i + 16, !0);
900
+ const n = new TextDecoder();
901
+ for (let o = 0; o < s && t.getUint32(l, !0) === 33639248; o++) {
902
+ const r = t.getUint16(l + 10, !0), c = t.getUint32(l + 20, !0), h = t.getUint16(l + 28, !0), d = t.getUint16(l + 30, !0), m = t.getUint16(l + 32, !0), g = t.getUint32(l + 42, !0), f = n.decode(new Uint8Array(p, l + 46, h));
903
+ e.set(f, { name: f, method: r, compSize: c, localOffset: g }), l += 46 + h + d + m;
904
+ }
905
+ return e;
906
+ }
907
+ async function P(p, t) {
908
+ const e = new DataView(p, t.localOffset);
909
+ if (e.getUint32(0, !0) !== 67324752) throw new Error("Bad local header");
910
+ const i = e.getUint16(26, !0), s = e.getUint16(28, !0), l = t.localOffset + 30 + i + s, n = new Uint8Array(p.slice(l, l + t.compSize));
911
+ if (t.method === 0) return n;
912
+ if (t.method !== 8) throw new Error("Unsupported compression method " + t.method);
913
+ const o = new Blob([n]).stream().pipeThrough(new DecompressionStream("deflate-raw"));
914
+ return new Uint8Array(await new Response(o).arrayBuffer());
915
+ }
916
+ const O = (p) => p.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;"), I = (p, t) => Array.from(p.children).filter((e) => e.localName === t), C = (p, ...t) => {
917
+ let e = p;
918
+ for (const i of t) {
919
+ if (!e) return null;
920
+ e = Array.from(e.children).find((s) => s.localName === i) || null;
921
+ }
922
+ return e;
923
+ }, y = (p, t = "val") => {
924
+ if (!p) return "";
925
+ for (const e of Array.from(p.attributes))
926
+ if (e.localName === t) return e.value;
927
+ return "";
928
+ }, q = (p, t) => {
929
+ const e = p ? C(p, t) : null;
930
+ if (!e) return !1;
931
+ const i = y(e);
932
+ return i !== "false" && i !== "0";
933
+ }, F = {
934
+ yellow: "#FFFF00",
935
+ green: "#00FF00",
936
+ cyan: "#00FFFF",
937
+ magenta: "#FF00FF",
938
+ blue: "#0000FF",
939
+ red: "#FF0000",
940
+ darkBlue: "#00008B",
941
+ darkCyan: "#008B8B",
942
+ darkGreen: "#006400",
943
+ darkMagenta: "#8B008B",
944
+ darkRed: "#8B0000",
945
+ darkYellow: "#808000",
946
+ darkGray: "#A9A9A9",
947
+ lightGray: "#D3D3D3",
948
+ black: "#000000",
949
+ white: "#FFFFFF"
950
+ }, ut = {
951
+ png: "image/png",
952
+ jpg: "image/jpeg",
953
+ jpeg: "image/jpeg",
954
+ gif: "image/gif",
955
+ bmp: "image/bmp",
956
+ webp: "image/webp"
957
+ };
958
+ function gt(p) {
959
+ let t = "";
960
+ for (let e = 0; e < p.length; e += 32768)
961
+ t += String.fromCharCode(...p.subarray(e, e + 32768));
962
+ return btoa(t);
963
+ }
964
+ class ft {
965
+ constructor(t, e, i) {
966
+ this.rels = t, this.images = e, this.numFmt = i;
967
+ }
968
+ convertBody(t) {
969
+ let e = "", i = [];
970
+ const s = (l) => {
971
+ for (; i.length > l; ) e += `</${i.pop()}>`;
972
+ };
973
+ for (const l of Array.from(t.children))
974
+ if (l.localName === "p") {
975
+ const n = this.paraList(l);
976
+ if (n) {
977
+ const o = n.ilvl + 1;
978
+ for (; i.length > o; ) e += `</${i.pop()}>`;
979
+ for (i.length === o && i[o - 1] !== n.type && (e += `</${i.pop()}>`); i.length < o; )
980
+ e += `<${n.type}>`, i.push(n.type);
981
+ e += `<li>${this.runsOf(l) || "<br>"}</li>`;
982
+ continue;
983
+ }
984
+ s(0), e += this.convertPara(l);
985
+ } else l.localName === "tbl" ? (s(0), e += this.convertTable(l)) : l.localName;
986
+ return s(0), e || "<p><br></p>";
987
+ }
988
+ paraList(t) {
989
+ const e = C(t, "pPr", "numPr");
990
+ if (!e) return null;
991
+ const i = y(C(e, "numId"));
992
+ if (!i || i === "0") return null;
993
+ const s = parseInt(y(C(e, "ilvl")) || "0", 10) || 0;
994
+ return { type: this.numFmt.get(i) || "ul", ilvl: Math.min(s, 8) };
995
+ }
996
+ convertPara(t) {
997
+ const e = C(t, "pPr"), i = y(C(t, "pPr", "pStyle"));
998
+ let s = "p";
999
+ const l = /^Heading([1-6])$/i.exec(i);
1000
+ l ? s = "h" + l[1] : /^Title$/i.test(i) && (s = "h1");
1001
+ const n = [], o = y(C(t, "pPr", "jc"));
1002
+ o === "center" ? n.push("text-align:center") : o === "right" || o === "end" ? n.push("text-align:right") : (o === "both" || o === "distribute") && n.push("text-align:justify"), e && C(e, "bidi") && n.push("direction:rtl");
1003
+ const r = this.runsOf(t), c = n.length ? ` style="${n.join(";")}"` : "";
1004
+ return `<${s}${c}>${r || "<br>"}</${s}>`;
1005
+ }
1006
+ runsOf(t) {
1007
+ let e = "";
1008
+ for (const i of Array.from(t.children))
1009
+ if (i.localName === "r") e += this.convertRun(i);
1010
+ else if (i.localName === "hyperlink") {
1011
+ let s = this.rels.get(y(i, "id")) || "";
1012
+ const l = y(i, "anchor");
1013
+ !s && l && (s = "#" + l);
1014
+ const n = this.runsOf(i);
1015
+ e += s ? `<a href="${O(s)}">${n}</a>` : n;
1016
+ } else (i.localName === "smartTag" || i.localName === "ins") && (e += this.runsOf(i));
1017
+ return e;
1018
+ }
1019
+ convertRun(t) {
1020
+ const e = C(t, "rPr");
1021
+ let i = "";
1022
+ for (const d of Array.from(t.children))
1023
+ d.localName === "t" ? i += O(d.textContent || "") : d.localName === "br" || d.localName === "cr" ? i += "<br>" : d.localName === "tab" ? i += "&emsp;" : (d.localName === "drawing" || d.localName === "pict" || d.localName === "object") && (i += this.convertImage(d));
1024
+ if (!i) return "";
1025
+ const s = [], l = y(e ? C(e, "color") : null);
1026
+ l && l !== "auto" && s.push("color:#" + l);
1027
+ const n = y(e ? C(e, "highlight") : null);
1028
+ n && F[n] && s.push("background-color:" + F[n]);
1029
+ const o = parseFloat(y(e ? C(e, "sz") : null));
1030
+ o && s.push("font-size:" + Math.round(o / 2 * (4 / 3)) + "px");
1031
+ const r = e ? C(e, "rFonts") : null, c = y(r, "ascii") || y(r, "cs");
1032
+ c && s.push(`font-family:'${c}'`), s.length && (i = `<span style="${s.join(";")}">${i}</span>`), q(e, "b") && (i = `<strong>${i}</strong>`), q(e, "i") && (i = `<em>${i}</em>`), q(e, "u") && y(C(e, "u")) !== "none" && (i = `<u>${i}</u>`), q(e, "strike") && (i = `<s>${i}</s>`);
1033
+ const h = y(e ? C(e, "vertAlign") : null);
1034
+ return h === "superscript" ? i = `<sup>${i}</sup>` : h === "subscript" && (i = `<sub>${i}</sub>`), i;
1035
+ }
1036
+ convertImage(t) {
1037
+ let e = "", i = 0;
1038
+ const s = (o) => {
1039
+ if (o.localName === "blip" && (e = e || y(o, "embed") || y(o, "link")), o.localName === "imagedata" && (e = e || y(o, "id")), o.localName === "extent") {
1040
+ const r = parseFloat(o.getAttribute("cx") || "0");
1041
+ r && (i = Math.round(r / 9525));
1042
+ }
1043
+ for (const r of Array.from(o.children)) s(r);
1044
+ };
1045
+ if (s(t), !e) return "";
1046
+ const l = this.images.get(e);
1047
+ if (!l) return "";
1048
+ const n = i ? ` width="${i}"` : "";
1049
+ return `<img src="${l}" alt=""${n}>`;
1050
+ }
1051
+ convertTable(t) {
1052
+ let e = '<table style="border-collapse:collapse;width:100%"><tbody>';
1053
+ for (const i of I(t, "tr")) {
1054
+ e += "<tr>";
1055
+ for (const s of I(i, "tc")) {
1056
+ const l = parseInt(y(C(s, "tcPr", "gridSpan")) || "1", 10) || 1, n = l > 1 ? ` colspan="${l}"` : "";
1057
+ let o = "";
1058
+ for (const r of Array.from(s.children))
1059
+ r.localName === "p" ? o += this.convertPara(r) : r.localName === "tbl" && (o += this.convertTable(r));
1060
+ e += `<td style="border:1px solid #b9c2cc"${n}>${o || "<br>"}</td>`;
1061
+ }
1062
+ e += "</tr>";
1063
+ }
1064
+ return e + "</tbody></table>";
1065
+ }
1066
+ }
1067
+ async function bt(p) {
1068
+ const t = p instanceof ArrayBuffer ? p : await p.arrayBuffer(), e = mt(t), i = new TextDecoder(), s = async (f) => {
1069
+ const b = e.get(f);
1070
+ return b ? new DOMParser().parseFromString(i.decode(await P(t, b)), "application/xml") : null;
1071
+ }, l = await s("word/document.xml"), n = l == null ? void 0 : l.getElementsByTagName("*");
1072
+ let o = null;
1073
+ if (n) {
1074
+ for (const f of Array.from(n))
1075
+ if (f.localName === "body") {
1076
+ o = f;
1077
+ break;
1078
+ }
1079
+ }
1080
+ if (!o) throw new Error("word/document.xml missing or invalid");
1081
+ const r = /* @__PURE__ */ new Map(), c = /* @__PURE__ */ new Map(), h = await s("word/_rels/document.xml.rels");
1082
+ if (h)
1083
+ for (const f of Array.from(h.getElementsByTagName("*"))) {
1084
+ if (f.localName !== "Relationship") continue;
1085
+ const b = f.getAttribute("Id") || "", v = f.getAttribute("Target") || "", T = f.getAttribute("Type") || "";
1086
+ /hyperlink/i.test(T) ? r.set(b, v) : /image/i.test(T) && c.set(b, v);
1087
+ }
1088
+ const d = /* @__PURE__ */ new Map();
1089
+ for (const [f, b] of c) {
1090
+ const v = b.startsWith("/") ? b.slice(1) : "word/" + b.replace(/^\.\//, ""), T = e.get(v);
1091
+ if (!T) continue;
1092
+ const M = (v.split(".").pop() || "").toLowerCase(), S = ut[M];
1093
+ if (S)
1094
+ try {
1095
+ d.set(f, `data:${S};base64,${gt(await P(t, T))}`);
1096
+ } catch {
1097
+ }
1098
+ }
1099
+ const m = /* @__PURE__ */ new Map(), g = await s("word/numbering.xml");
1100
+ if (g) {
1101
+ const f = /* @__PURE__ */ new Map(), b = Array.from(g.getElementsByTagName("*"));
1102
+ for (const v of b) {
1103
+ if (v.localName !== "abstractNum") continue;
1104
+ const T = y(v, "abstractNumId"), M = I(v, "lvl").find((x) => y(x, "ilvl") === "0") || I(v, "lvl")[0], S = M ? y(C(M, "numFmt")) : "";
1105
+ f.set(T, S === "bullet" ? "ul" : "ol");
1106
+ }
1107
+ for (const v of b) {
1108
+ if (v.localName !== "num") continue;
1109
+ const T = y(v, "numId"), M = y(C(v, "abstractNumId"));
1110
+ m.set(T, f.get(M) || "ul");
1111
+ }
1112
+ }
1113
+ return new ft(r, d, m).convertBody(o);
1114
+ }
1115
+ const vt = ["nw", "ne", "sw", "se"], A = class A {
1116
+ constructor(t) {
1117
+ this.lang = "en", this.contentClass = "fable-content-" + A.instanceCounter++, this.contentStyleEl = null, this.savedRange = null, this.foreColor = "#000000", this.backColor = "#FACC15", this.openPop = null, this.openSubEl = null, this.popAnchor = null, this.dlgOvl = null, this.tblActive = null, this.tblCorner = null, this.tblColBars = [], this.tblCtx = null, this.tblCellMark = null, this.tblOpMark = null, this.tblOpMarkKind = null, this.imgActive = null, this.imgHandles = [], this.imgCtx = null, this.imgHideTimer = null, this.phActive = null, this.phCtx = null, this.phUploadTarget = null, this.selCtx = null, this.revisions = [], this.revTimer = null, this.draftTimer = null, this.draftStorageKey = "", this.listeners = [], this.isDestroyed = !1, this.options = {
1118
+ target: t.target,
1119
+ language: t.language || "en",
1120
+ height: t.height ?? 302,
1121
+ initialContent: t.initialContent ?? "<p><br></p>",
1122
+ onChange: t.onChange || (() => {
1123
+ }),
1124
+ onReady: t.onReady || (() => {
1125
+ }),
1126
+ menubar: t.menubar ?? !0,
1127
+ toolbar: t.toolbar ?? !0,
1128
+ statusbar: t.statusbar ?? !0,
1129
+ readonly: t.readonly ?? !1,
1130
+ draftKey: t.draftKey ?? (typeof location < "u" ? location.pathname : "default"),
1131
+ fontFamilyFormats: t.fontFamilyFormats ?? X,
1132
+ imageFileTypes: t.imageFileTypes ?? ["image/jpeg", "image/jpg", "image/png", "image/gif", "image/bmp", "image/webp"]
1133
+ }, this.imageUploadHandler = t.imageUploadHandler, this.onImageUploadError = t.onImageUploadError, this.contentStyle = t.contentStyle, this.lang = this.options.language, this.draftStorageKey = "tmclone-draft:" + this.options.draftKey, this.initDOM(), this.bindEvents(), this.initUI(), this.recordRevision(), this.options.onReady(this);
1134
+ }
1135
+ t(t) {
1136
+ const e = B(this.lang)[t];
1137
+ return typeof e == "string" ? e : e.join(",");
1138
+ }
1139
+ tArr(t) {
1140
+ return B(this.lang)[t];
1141
+ }
1142
+ dir() {
1143
+ return B(this.lang).dir;
1144
+ }
1145
+ /* ---------------------------------------------------------- DOM setup */
1146
+ initDOM() {
1147
+ const t = this.options.target;
1148
+ t.innerHTML = "", t.classList.add("tox-root"), this.shell = document.createElement("div"), this.shell.className = "tox", this.menubar = document.createElement("div"), this.menubar.className = "mnb", this.toolbar = document.createElement("div"), this.toolbar.className = "tbr", this.ed = document.createElement("div"), this.ed.className = "earea " + this.contentClass, this.ed.setAttribute("contenteditable", (!this.options.readonly).toString()), this.ed.spellcheck = !0, this.ed.innerHTML = this.options.initialContent, this.ed.style.height = this.options.height + "px", this.statusbar = document.createElement("div"), this.statusbar.className = "sbar", this.statusbar.innerHTML = `
1149
+ <span class="mid"></span>
1150
+ <span class="words"></span>
1151
+ <span class="grip">
1152
+ <svg viewBox="0 0 12 12"><path d="M11 1 1 11M11 6 6 11M11 11h0"/></svg>
1153
+ </span>
1154
+ `, this.sbHelp = this.statusbar.querySelector(".mid"), this.sbWords = this.statusbar.querySelector(".words");
1155
+ const e = this.statusbar.querySelector(".grip");
1156
+ this.bindGrip(e), this.shell.appendChild(this.menubar), this.shell.appendChild(this.toolbar), this.shell.appendChild(this.ed), this.shell.appendChild(this.statusbar), this.contentStyle && (this.contentStyleEl = document.createElement("style"), this.contentStyleEl.textContent = this.scopeContentStyle(this.contentStyle), this.shell.appendChild(this.contentStyleEl)), t.appendChild(this.shell), this.options.statusbar || (this.statusbar.style.display = "none"), this.imgInput = document.createElement("input"), this.imgInput.type = "file", this.imgInput.accept = this.options.imageFileTypes.join(","), this.imgInput.style.display = "none", t.appendChild(this.imgInput), this.docInput = document.createElement("input"), this.docInput.type = "file", this.docInput.accept = ".docx,application/vnd.openxmlformats-officedocument.wordprocessingml.document", this.docInput.style.display = "none", t.appendChild(this.docInput);
1157
+ }
1158
+ /** Rewrites the literal word `body` in a user-supplied `contentStyle` string to a
1159
+ * selector scoped to this instance's content div. Everything else passes through
1160
+ * verbatim, since `.ed` is a plain div in the host page (not an iframe) and an
1161
+ * unscoped `body { ... }` rule would otherwise leak onto the host page's body. */
1162
+ scopeContentStyle(t) {
1163
+ return t.replace(/\bbody\b/g, "." + this.contentClass);
1164
+ }
1165
+ bindGrip(t) {
1166
+ let e = 0, i = 0;
1167
+ const s = (l) => {
1168
+ e = l.clientY, i = this.ed.offsetHeight, l.preventDefault();
1169
+ const n = (r) => {
1170
+ this.ed.style.height = Math.max(120, i + r.clientY - e) + "px";
1171
+ }, o = () => {
1172
+ window.removeEventListener("mousemove", n), window.removeEventListener("mouseup", o);
1173
+ };
1174
+ window.addEventListener("mousemove", n), window.addEventListener("mouseup", o);
1175
+ };
1176
+ t.addEventListener("mousedown", s), this.listeners.push(() => t.removeEventListener("mousedown", s));
1177
+ }
1178
+ /* ---------------------------------------------------------- event binding */
1179
+ bindEvents() {
1180
+ this.onDoc("mousedown", (t) => {
1181
+ this.openPop && !this.openPop.contains(t.target) && !this.popAnchor.contains(t.target) && !(this.openSubEl && this.openSubEl.contains(t.target)) && this.closePop();
1182
+ }), this.onDoc("keydown", (t) => {
1183
+ t.key === "Escape" && (this.closePop(), this.closeDlg());
1184
+ }), this.onDoc("selectionchange", () => {
1185
+ const t = window.getSelection();
1186
+ t && this.ed.contains(t.anchorNode) ? (this.saveSel(), this.refreshState(), this.updateSelToolbar(t), this.positionCellMarker()) : this.clearSelToolbar();
1187
+ }), this.on(this.ed, "input", () => {
1188
+ this.refreshState(), this.onChange(), this.positionTableHandles(), this.positionImageHandles(), this.positionImgPhCtx();
1189
+ }), this.on(this.ed, "keydown", (t) => {
1190
+ t.altKey && t.key === "0" && (t.preventDefault(), this.helpDlg());
1191
+ }), this.on(this.ed, "paste", (t) => this.handlePaste(t)), this.on(this.ed, "drop", (t) => {
1192
+ var s, l, n;
1193
+ t.preventDefault();
1194
+ const e = (l = (s = t.target).closest) == null ? void 0 : l.call(s, ".img-ph");
1195
+ if (!e || !this.ed.contains(e) || this.options.readonly) return;
1196
+ const i = Array.from(((n = t.dataTransfer) == null ? void 0 : n.files) || []).find((o) => o.type.startsWith("image/"));
1197
+ i && this.readImageFileInto(i, e);
1198
+ }), this.on(this.ed, "dragover", (t) => t.preventDefault()), this.on(this.ed, "mousedown", (t) => {
1199
+ var n, o, r;
1200
+ const e = t.target, i = (n = e.closest) == null ? void 0 : n.call(e, "table");
1201
+ i && this.ed.contains(i) ? this.selectTableForResize(i) : this.clearTableHandles();
1202
+ const s = (o = e.closest) == null ? void 0 : o.call(e, ".img-ph");
1203
+ s && this.ed.contains(s) && !this.options.readonly ? (t.preventDefault(), this.selectImgPlaceholder(s)) : this.clearImgPlaceholderSel();
1204
+ const l = (r = e.closest) == null ? void 0 : r.call(e, "img");
1205
+ l && this.ed.contains(l) && !this.options.readonly ? (t.preventDefault(), this.selectImage(l)) : this.clearImageHandles();
1206
+ }), this.on(this.ed, "mouseover", (t) => {
1207
+ var i, s;
1208
+ if (this.options.readonly) return;
1209
+ const e = (s = (i = t.target).closest) == null ? void 0 : s.call(i, "img");
1210
+ e && this.ed.contains(e) && (this.cancelImgHide(), this.selectImage(e));
1211
+ }), this.on(this.ed, "mouseout", (t) => {
1212
+ var s, l, n, o;
1213
+ const e = (l = (s = t.target).closest) == null ? void 0 : l.call(s, "img");
1214
+ if (!e) return;
1215
+ const i = t.relatedTarget;
1216
+ i && ((n = this.imgCtx) != null && n.contains(i) || this.imgHandles.some((r) => r.contains(i)) || ((o = i.closest) == null ? void 0 : o.call(i, "img")) === e) || this.scheduleImgHide();
1217
+ }), this.on(this.ed, "scroll", () => {
1218
+ this.positionTableHandles(), this.positionImageHandles(), this.positionImgPhCtx();
1219
+ }), this.onWin(
1220
+ "scroll",
1221
+ () => {
1222
+ this.positionTableHandles(), this.positionImageHandles(), this.positionImgPhCtx(), this.repositionSelToolbar();
1223
+ },
1224
+ !0
1225
+ ), this.onWin("resize", () => {
1226
+ this.positionTableHandles(), this.positionImageHandles(), this.positionImgPhCtx(), this.repositionSelToolbar();
1227
+ }), this.on(this.imgInput, "change", () => {
1228
+ var s;
1229
+ const t = (s = this.imgInput.files) == null ? void 0 : s[0];
1230
+ if (!t) return;
1231
+ const e = this.phUploadTarget;
1232
+ if (this.phUploadTarget = null, e && this.ed.contains(e)) {
1233
+ this.readImageFileInto(t, e);
1234
+ return;
1235
+ }
1236
+ const i = new FileReader();
1237
+ i.onload = () => {
1238
+ this.restoreSel(), document.execCommand(
1239
+ "insertHTML",
1240
+ !1,
1241
+ `<img src="${i.result}" title="${t.name.replace(/"/g, "")}" alt="">`
1242
+ ), this.onChange();
1243
+ }, i.readAsDataURL(t);
1244
+ }), this.on(this.docInput, "change", () => {
1245
+ var e;
1246
+ const t = (e = this.docInput.files) == null ? void 0 : e[0];
1247
+ t && this.importWordFile(t).catch(() => alert(this.t("importfail")));
1248
+ }), this.onDoc("mousedown", (t) => {
1249
+ this.ed.contains(t.target) || t.target === this.tblCorner || this.tblColBars.includes(t.target) || this.tblCtx && this.tblCtx.contains(t.target) || this.imgHandles.includes(t.target) || this.imgCtx && this.imgCtx.contains(t.target) || this.phCtx && this.phCtx.contains(t.target) || this.selCtx && this.selCtx.contains(t.target) || this.openPop && this.openPop.contains(t.target) || this.openSubEl && this.openSubEl.contains(t.target) || (this.clearTableHandles(), this.clearImageHandles(), this.clearImgPlaceholderSel(), this.clearSelToolbar());
1250
+ });
1251
+ }
1252
+ on(t, e, i) {
1253
+ t.addEventListener(e, i), this.listeners.push(() => t.removeEventListener(e, i));
1254
+ }
1255
+ onDoc(t, e) {
1256
+ document.addEventListener(t, e), this.listeners.push(() => document.removeEventListener(t, e));
1257
+ }
1258
+ onWin(t, e, i) {
1259
+ window.addEventListener(t, e, i), this.listeners.push(() => window.removeEventListener(t, e, i));
1260
+ }
1261
+ /* ---------------------------------------------------------- public API */
1262
+ getContent() {
1263
+ return this.ed.innerHTML;
1264
+ }
1265
+ setContent(t) {
1266
+ this.ed.innerHTML = t || "<p><br></p>", this.refreshState(), this.clearTableHandles(), this.clearImageHandles(), this.clearImgPlaceholderSel(), this.clearSelToolbar(), this.onChange();
1267
+ }
1268
+ insertContent(t) {
1269
+ this.restoreSel(), document.execCommand("insertHTML", !1, t), this.saveSel(), this.refreshState(), this.onChange();
1270
+ }
1271
+ setLanguage(t) {
1272
+ this.lang = t, this.initUI();
1273
+ }
1274
+ focus() {
1275
+ this.ed.focus();
1276
+ }
1277
+ async importWordFile(t) {
1278
+ const e = await bt(t);
1279
+ this.recordRevision(), this.setContent(e), this.recordRevision();
1280
+ }
1281
+ restoreDraft() {
1282
+ let t = null;
1283
+ try {
1284
+ t = localStorage.getItem(this.draftStorageKey);
1285
+ } catch {
1286
+ }
1287
+ if (!t) return !1;
1288
+ try {
1289
+ const e = JSON.parse(t);
1290
+ return e.html ? (this.recordRevision(), this.setContent(e.html), !0) : !1;
1291
+ } catch {
1292
+ return !1;
1293
+ }
1294
+ }
1295
+ getRevisions() {
1296
+ return this.revisions.slice();
1297
+ }
1298
+ destroy() {
1299
+ this.isDestroyed || (this.isDestroyed = !0, this.revTimer != null && window.clearTimeout(this.revTimer), this.draftTimer != null && window.clearTimeout(this.draftTimer), this.closePop(), this.closeDlg(), this.clearTableHandles(), this.clearImageHandles(), this.clearImgPlaceholderSel(), this.clearSelToolbar(), this.listeners.forEach((t) => t()), this.listeners = [], this.shell && this.shell.parentNode && this.shell.parentNode.removeChild(this.shell), this.imgInput && this.imgInput.parentNode && this.imgInput.parentNode.removeChild(this.imgInput), this.docInput && this.docInput.parentNode && this.docInput.parentNode.removeChild(this.docInput), this.contentStyleEl = null);
1300
+ }
1301
+ /* ---------------------------------------------------------- selection */
1302
+ saveSel() {
1303
+ const t = window.getSelection();
1304
+ t && t.rangeCount && this.ed.contains(t.anchorNode) && (this.savedRange = t.getRangeAt(0).cloneRange());
1305
+ }
1306
+ restoreSel() {
1307
+ if (!this.savedRange) {
1308
+ this.ed.focus();
1309
+ return;
1310
+ }
1311
+ this.ed.focus();
1312
+ const t = window.getSelection();
1313
+ t && (t.removeAllRanges(), t.addRange(this.savedRange));
1314
+ }
1315
+ exec(t, e) {
1316
+ this.restoreSel(), document.execCommand("styleWithCSS", !1, t !== "fontSize" ? "true" : "false"), document.execCommand(t, !1, e ?? void 0), this.saveSel(), this.refreshState(), this.onChange();
1317
+ }
1318
+ closestBlock(t) {
1319
+ for (; t && t !== this.ed; ) {
1320
+ if (t.nodeType === 1 && /^(P|DIV|H[1-6]|LI|PRE|BLOCKQUOTE|TD|TH)$/i.test(t.tagName))
1321
+ return t;
1322
+ t = t.parentNode;
1323
+ }
1324
+ return null;
1325
+ }
1326
+ selectedBlocks() {
1327
+ const t = window.getSelection();
1328
+ if (!t || !t.rangeCount || !this.ed.contains(t.anchorNode)) return [];
1329
+ const e = t.getRangeAt(0), i = Array.from(this.ed.querySelectorAll("p,h1,h2,h3,h4,h5,h6,li,pre,blockquote,td,th")).filter(
1330
+ (s) => e.intersectsNode(s)
1331
+ );
1332
+ if (!i.length) {
1333
+ const s = this.closestBlock(t.anchorNode);
1334
+ if (s) return [s];
1335
+ }
1336
+ return i;
1337
+ }
1338
+ onChange() {
1339
+ this.options.onChange(this.ed.innerHTML), this.scheduleRevision(), this.scheduleDraftSave();
1340
+ }
1341
+ /* ---------------------------------------------------------- revisions / drafts */
1342
+ recordRevision() {
1343
+ const t = this.ed.innerHTML, e = this.revisions[this.revisions.length - 1];
1344
+ e && e.html === t || (this.revisions.push({ time: Date.now(), html: t }), this.revisions.length > 30 && this.revisions.shift());
1345
+ }
1346
+ scheduleRevision() {
1347
+ this.revTimer != null && window.clearTimeout(this.revTimer), this.revTimer = window.setTimeout(() => {
1348
+ this.revTimer = null, this.recordRevision();
1349
+ }, 1500);
1350
+ }
1351
+ scheduleDraftSave() {
1352
+ this.draftTimer != null && window.clearTimeout(this.draftTimer), this.draftTimer = window.setTimeout(() => {
1353
+ this.draftTimer = null;
1354
+ try {
1355
+ localStorage.setItem(this.draftStorageKey, JSON.stringify({ time: Date.now(), html: this.ed.innerHTML }));
1356
+ } catch {
1357
+ }
1358
+ }, 800);
1359
+ }
1360
+ revisionDlg() {
1361
+ this.recordRevision(), this.dialog(this.t("revhistory"), (t) => {
1362
+ if (!this.revisions.length) {
1363
+ t.innerHTML = `<p style="color:#556">${this.t("revempty")}</p>`;
1364
+ return;
1365
+ }
1366
+ const e = document.createElement("div");
1367
+ e.className = "revwrap";
1368
+ const i = document.createElement("div");
1369
+ i.className = "revlist";
1370
+ const s = document.createElement("div");
1371
+ s.className = "revprev";
1372
+ const l = document.createElement("button");
1373
+ l.type = "button", l.className = "revrestore", l.textContent = this.t("restore");
1374
+ let n = this.revisions.length - 1;
1375
+ const o = new Intl.DateTimeFormat(this.lang === "ar" ? "ar-AE" : "en-GB", {
1376
+ year: "numeric",
1377
+ month: "short",
1378
+ day: "numeric",
1379
+ hour: "2-digit",
1380
+ minute: "2-digit",
1381
+ second: "2-digit"
1382
+ }), r = {}, c = (h) => {
1383
+ n = h, this.revisions.forEach((d, m) => {
1384
+ var g;
1385
+ return (g = r[m]) == null ? void 0 : g.classList.toggle("on", m === h);
1386
+ }), s.innerHTML = this.revisions[h].html, l.disabled = h === this.revisions.length - 1;
1387
+ };
1388
+ for (let h = this.revisions.length - 1; h >= 0; h--) {
1389
+ const d = this.revisions[h], m = document.createElement("button");
1390
+ m.type = "button";
1391
+ const g = (new DOMParser().parseFromString(d.html, "text/html").body.textContent || "").trim(), f = g ? g.split(/\s+/).length : 0, b = h === this.revisions.length - 1;
1392
+ m.innerHTML = `<span>${b ? this.t("currentver") : o.format(new Date(d.time))}</span><span class="wc">${f} ${this.t("words")}</span>`, m.addEventListener("click", () => c(h)), r[h] = m, i.appendChild(m);
1393
+ }
1394
+ i.append(l), l.addEventListener("click", () => {
1395
+ const h = this.revisions[n];
1396
+ h && (this.recordRevision(), this.setContent(h.html), this.recordRevision(), this.closeDlg());
1397
+ }), e.append(i, s), t.appendChild(e), c(n);
1398
+ });
1399
+ }
1400
+ /* ---------------------------------------------------------- popups / menus */
1401
+ closeSub() {
1402
+ var t;
1403
+ (t = this.openSubEl) == null || t.remove(), this.openSubEl = null;
1404
+ }
1405
+ closePop() {
1406
+ var t;
1407
+ this.closeSub(), this.openPop && (this.openPop.remove(), this.openPop = null, (t = this.popAnchor) == null || t.classList.remove("open"), this.popAnchor = null, this.setOpTarget(null));
1408
+ }
1409
+ openSubFor(t, e) {
1410
+ this.closeSub();
1411
+ const i = document.createElement("div");
1412
+ i.className = "pop sub", i.dir = this.dir(), t.subBuild ? t.subBuild(i) : t.sub && this.menuItems(i, t.sub), i.addEventListener("mousedown", (r) => {
1413
+ r.target.tagName !== "INPUT" && r.preventDefault();
1414
+ }), document.body.appendChild(i);
1415
+ const s = e.getBoundingClientRect();
1416
+ let n = this.dir() === "rtl" ? s.left - i.offsetWidth + 2 : s.right - 2;
1417
+ n = Math.max(8, Math.min(n + scrollX, scrollX + innerWidth - i.offsetWidth - 8));
1418
+ let o = s.top + scrollY - 6;
1419
+ o = Math.max(8 + scrollY, Math.min(o, scrollY + innerHeight - i.offsetHeight - 8)), i.style.left = n + "px", i.style.top = o + "px", this.openSubEl = i;
1420
+ }
1421
+ popup(t, e) {
1422
+ if (this.openPop && this.popAnchor === t) {
1423
+ this.closePop();
1424
+ return;
1425
+ }
1426
+ this.closePop();
1427
+ const i = document.createElement("div");
1428
+ i.className = "pop", i.dir = this.dir(), e(i), document.body.appendChild(i);
1429
+ const s = t.getBoundingClientRect();
1430
+ i.style.minWidth = Math.max(160, Math.round(s.width)) + "px", i.style.top = s.bottom + scrollY + 2 + "px";
1431
+ let n = this.dir() === "rtl" ? s.right - i.offsetWidth : s.left;
1432
+ n = Math.max(8, Math.min(n + scrollX, scrollX + innerWidth - i.offsetWidth - 8)), i.style.left = n + "px", i.addEventListener("mousedown", (o) => {
1433
+ o.target.tagName !== "INPUT" && o.preventDefault();
1434
+ }), this.openPop = i, this.popAnchor = t, t.classList.add("open");
1435
+ }
1436
+ menuItems(t, e) {
1437
+ e.forEach((i) => {
1438
+ if (i === "|") {
1439
+ t.insertAdjacentHTML("beforeend", '<div class="sep"></div>');
1440
+ return;
1441
+ }
1442
+ const s = !!(i.sub || i.subBuild), l = document.createElement("button");
1443
+ l.className = "mi" + (i.on ? " on" : ""), l.innerHTML = `<span class="ic">${i.icon || ""}</span><span class="prev" ${i.previewStyle ? `style="${i.previewStyle}"` : ""}>${i.label}</span>${i.shortcut ? `<span class="sc">${i.shortcut}</span>` : ""}${s ? `<span class="subarrow">${a.chev}</span>` : ""}`, l.addEventListener("click", () => {
1444
+ i.action && (this.closePop(), i.action());
1445
+ }), l.addEventListener("mouseenter", () => {
1446
+ var n;
1447
+ s ? this.openSubFor(i, l) : this.openSubEl && t !== this.openSubEl && this.closeSub(), (n = i.hover) == null || n.call(i, !0);
1448
+ }), l.addEventListener("mouseleave", () => {
1449
+ var n;
1450
+ return (n = i.hover) == null ? void 0 : n.call(i, !1);
1451
+ }), t.appendChild(l);
1452
+ });
1453
+ }
1454
+ /* ---------------------------------------------------------- toolbar builders */
1455
+ tbtn(t, e, i, s) {
1456
+ const l = document.createElement("button");
1457
+ return l.className = "tbtn", l.type = "button", l.title = e, l.innerHTML = t, s && (l.dataset.id = s), l.addEventListener("mousedown", (n) => n.preventDefault()), l.addEventListener("click", i), l;
1458
+ }
1459
+ /** Font-size increase / decrease step button. */
1460
+ stepBtn(t) {
1461
+ const e = t > 0 ? "+" : "−", i = t > 0 ? a.fontsizeup : a.fontsizedown, s = this.tbtn(i, this.t("fontsize") + " " + e, () => this.stepFontSize(t));
1462
+ return s.addEventListener("mousedown", () => this.saveSel()), s;
1463
+ }
1464
+ /** Toolbar icon button that opens a popup menu anchored to itself. */
1465
+ menuTbtn(t, e, i, s) {
1466
+ const l = this.tbtn(t, e, () => i(l), s);
1467
+ return l.classList.add("hasmenu"), l.insertAdjacentHTML("beforeend", a.chev), l.addEventListener("mousedown", () => this.saveSel()), l;
1468
+ }
1469
+ /** Quick text-color chips plus a "more" chip that opens the full palette. */
1470
+ colorChips() {
1471
+ const t = (s) => {
1472
+ const l = document.createElement("button");
1473
+ return l.type = "button", l.className = "cchip", l.title = s, l.addEventListener("mousedown", (n) => {
1474
+ n.preventDefault(), this.saveSel();
1475
+ }), l;
1476
+ }, e = V.map((s) => {
1477
+ const l = t(this.t("forecolor"));
1478
+ return l.style.background = s, l.addEventListener("click", () => this.applyColor("fore", s)), l;
1479
+ }), i = t(this.t("forecolor"));
1480
+ return i.classList.add("more"), i.dataset.cb = "fore", i.innerHTML = a.chev, i.addEventListener("click", () => this.colorMenu(i, "fore")), [...e, i];
1481
+ }
1482
+ group(...t) {
1483
+ const e = document.createElement("div");
1484
+ return e.className = "tgrp", t.forEach((i) => {
1485
+ i.classList.add("gbtn"), e.appendChild(i);
1486
+ }), e;
1487
+ }
1488
+ tsel(t, e, i, s) {
1489
+ const l = document.createElement("button");
1490
+ return l.className = "tsel " + t, l.type = "button", l.dataset.id = e, l.innerHTML = `<span class="lbl empty">${i || ""}</span>${a.chev}`, l.addEventListener("mousedown", (n) => {
1491
+ n.preventDefault(), this.saveSel();
1492
+ }), l.addEventListener("click", () => s(l)), l;
1493
+ }
1494
+ setListStyle(t, e) {
1495
+ var l, n;
1496
+ this.restoreSel();
1497
+ const i = window.getSelection();
1498
+ if (!i) return;
1499
+ let s = (l = this.closestBlock(i.anchorNode)) == null ? void 0 : l.closest(t);
1500
+ s || (this.exec(t === "ol" ? "insertOrderedList" : "insertUnorderedList"), s = (n = this.closestBlock(i.anchorNode)) == null ? void 0 : n.closest(t)), s && (s.style.listStyleType = e), this.saveSel(), this.onChange();
1501
+ }
1502
+ listMenu(t, e) {
1503
+ var c;
1504
+ const i = e === "ol" ? "insertOrderedList" : "insertUnorderedList", s = e === "ol" ? [
1505
+ ["lower-alpha", a.ol_alpha],
1506
+ ["lower-roman", a.ol_roman],
1507
+ ["upper-alpha", a.ol_alphau],
1508
+ ["upper-roman", a.ol_romanu]
1509
+ ] : [
1510
+ ["circle", a.ul_circle],
1511
+ ["square", a.ul_square]
1512
+ ], l = this.tArr(e === "ol" ? "liststyles_ol" : "liststyles_ul").slice(1), n = window.getSelection(), o = n ? (c = this.closestBlock(n.anchorNode)) == null ? void 0 : c.closest(e) : null, r = o ? o.style.listStyleType : "";
1513
+ this.popup(t, (h) => {
1514
+ this.menuItems(h, [
1515
+ {
1516
+ label: this.t(e === "ol" ? "numlist" : "bullist"),
1517
+ icon: e === "ol" ? a.numlist : a.bullist,
1518
+ on: document.queryCommandState(i),
1519
+ action: () => this.exec(i)
1520
+ }
1521
+ ]), h.insertAdjacentHTML("beforeend", '<div class="sep"></div>');
1522
+ const d = document.createElement("div");
1523
+ d.className = "mi-grid", s.forEach(([m, g], f) => {
1524
+ const b = document.createElement("button");
1525
+ b.className = "mi" + (r === m ? " on" : ""), b.innerHTML = `<span class="ic">${g}</span><span class="prev">${l[f]}</span>`, b.addEventListener("click", () => {
1526
+ this.closePop(), this.setListStyle(e, m);
1527
+ }), d.appendChild(b);
1528
+ }), h.appendChild(d);
1529
+ });
1530
+ }
1531
+ colorMenu(t, e) {
1532
+ this.popup(t, (i) => {
1533
+ const s = document.createElement("div");
1534
+ s.className = "cpal", J.forEach((d) => {
1535
+ const m = document.createElement("button");
1536
+ m.style.background = d, m.title = d, m.addEventListener("click", () => {
1537
+ this.closePop(), this.applyColor(e, d);
1538
+ }), s.appendChild(m);
1539
+ }), i.appendChild(s), i.insertAdjacentHTML("beforeend", '<div class="sep"></div>');
1540
+ const l = document.createElement("div");
1541
+ l.className = "cfoot";
1542
+ const n = document.createElement("div");
1543
+ n.className = "cswatch cur", n.title = this.t("currentcolor");
1544
+ const o = e === "fore" ? this.foreColor : this.backColor;
1545
+ n.style.background = /^#[0-9a-f]{6}$/i.test(o) ? o : "#000000", n.innerHTML = a.check;
1546
+ const r = document.createElement("button");
1547
+ r.type = "button", r.className = "cswatch nocolor", r.title = this.t("removecolor"), r.addEventListener("click", () => {
1548
+ this.closePop(), this.applyColor(e, null);
1549
+ });
1550
+ const c = document.createElement("label");
1551
+ c.className = "cswatch cwheel", c.title = this.t("customcolor"), c.innerHTML = a.palette;
1552
+ const h = document.createElement("input");
1553
+ h.type = "color", h.value = /^#[0-9a-f]{6}$/i.test(o) ? o : "#000000", h.addEventListener("change", () => {
1554
+ this.closePop(), this.applyColor(e, h.value);
1555
+ }), c.appendChild(h), l.append(n, r, c), i.appendChild(l);
1556
+ });
1557
+ }
1558
+ applyColor(t, e) {
1559
+ t === "fore" ? (this.foreColor = e || "#000000", this.exec("foreColor", e || "#000000")) : (this.backColor = e || "transparent", this.exec("hiliteColor", e || "transparent")), this.syncColorSwatches(this.toolbar), this.selCtx && this.syncColorSwatches(this.selCtx);
1560
+ }
1561
+ syncColorSwatches(t) {
1562
+ t.querySelectorAll("[data-cb=fore]").forEach((e) => e.style.background = this.foreColor), t.querySelectorAll("[data-cb=back]").forEach((e) => e.style.background = this.backColor);
1563
+ }
1564
+ fontMenu(t) {
1565
+ this.popup(t, (e) => {
1566
+ this.menuItems(
1567
+ e,
1568
+ this.options.fontFamilyFormats.map(([i, s]) => ({
1569
+ label: i,
1570
+ previewStyle: `font-family:${s}`,
1571
+ on: this.currentFont() === i,
1572
+ action: () => this.exec("fontName", s)
1573
+ }))
1574
+ );
1575
+ });
1576
+ }
1577
+ sizeMenu(t) {
1578
+ this.popup(t, (e) => {
1579
+ this.menuItems(
1580
+ e,
1581
+ _.map((i) => ({
1582
+ label: i,
1583
+ on: this.currentSize() === i,
1584
+ action: () => this.applyFontSize(i)
1585
+ }))
1586
+ );
1587
+ });
1588
+ }
1589
+ /** Font sizing needs a non-collapsed range. With a bare caret, grow the
1590
+ selection to the word under it; in an empty spot, select a zero-width
1591
+ space so the new size applies to what gets typed next. */
1592
+ ensureSizeTarget() {
1593
+ const t = window.getSelection();
1594
+ if (!t) return;
1595
+ if (!t.rangeCount) {
1596
+ const n = document.createRange();
1597
+ n.selectNodeContents(this.ed), n.collapse(!0), t.addRange(n);
1598
+ }
1599
+ if (!t.isCollapsed) return;
1600
+ const e = t.getRangeAt(0), i = e.startContainer;
1601
+ if (i.nodeType === 3) {
1602
+ const n = i.data;
1603
+ let o = e.startOffset, r = e.startOffset;
1604
+ for (; o > 0 && /\S/.test(n[o - 1]); ) o--;
1605
+ for (; r < n.length && /\S/.test(n[r]); ) r++;
1606
+ if (r > o) {
1607
+ const c = document.createRange();
1608
+ c.setStart(i, o), c.setEnd(i, r), t.removeAllRanges(), t.addRange(c), this.savedRange = c.cloneRange();
1609
+ return;
1610
+ }
1611
+ }
1612
+ const s = document.createTextNode("​");
1613
+ e.insertNode(s);
1614
+ const l = document.createRange();
1615
+ l.setStart(s, 0), l.setEnd(s, 1), t.removeAllRanges(), t.addRange(l), this.savedRange = l.cloneRange();
1616
+ }
1617
+ applyFontSize(t) {
1618
+ this.restoreSel(), this.ensureSizeTarget(), document.execCommand("styleWithCSS", !1, "false"), document.execCommand("fontSize", !1, "7");
1619
+ const e = [];
1620
+ if (this.ed.querySelectorAll('font[size="7"]').forEach((i) => {
1621
+ const s = document.createElement("span");
1622
+ for (s.style.fontSize = t; i.firstChild; ) s.appendChild(i.firstChild);
1623
+ i.replaceWith(s), e.push(s);
1624
+ }), e.length) {
1625
+ const i = document.createRange();
1626
+ i.setStart(e[0], 0), i.setEnd(e[e.length - 1], e[e.length - 1].childNodes.length);
1627
+ const s = window.getSelection();
1628
+ s && (s.removeAllRanges(), s.addRange(i));
1629
+ }
1630
+ this.saveSel(), this.refreshState(), this.onChange();
1631
+ }
1632
+ stepFontSize(t) {
1633
+ const e = parseInt(this.currentSize(), 10) || 14, i = Math.min(G, Math.max(Q, e + t));
1634
+ i !== e && this.applyFontSize(i + "px");
1635
+ }
1636
+ /* ------------------------------------------------ case / spacing / link */
1637
+ transformCase(t) {
1638
+ this.restoreSel();
1639
+ const e = window.getSelection();
1640
+ if (!e || !e.rangeCount || e.isCollapsed) return;
1641
+ const i = e.getRangeAt(0), s = document.createTreeWalker(this.ed, NodeFilter.SHOW_TEXT), l = [];
1642
+ let n;
1643
+ for (; n = s.nextNode(); ) i.intersectsNode(n) && l.push(n);
1644
+ l.forEach((o) => {
1645
+ const r = o === i.startContainer ? i.startOffset : 0, c = o === i.endContainer ? i.endOffset : o.data.length;
1646
+ if (c <= r) return;
1647
+ const h = o.data.slice(r, c);
1648
+ let d = h;
1649
+ t === "lower" ? d = h.toLowerCase() : t === "upper" ? d = h.toUpperCase() : d = h.replace(/(^|\s)(\S)/g, (m, g, f) => g + f.toUpperCase()), o.replaceData(r, c - r, d);
1650
+ }), this.saveSel(), this.refreshState(), this.onChange();
1651
+ }
1652
+ caseMenu(t) {
1653
+ this.popup(t, (e) => {
1654
+ this.menuItems(e, [
1655
+ { label: this.t("lowercase"), icon: a.lowercaseic, action: () => this.transformCase("lower") },
1656
+ { label: this.t("uppercase"), icon: a.uppercaseic, action: () => this.transformCase("upper") },
1657
+ { label: this.t("capitalize"), icon: a.capitalizeic, action: () => this.transformCase("capitalize") }
1658
+ ]);
1659
+ });
1660
+ }
1661
+ applyBlockStyle(t, e) {
1662
+ this.restoreSel(), this.selectedBlocks().forEach((s) => {
1663
+ e ? s.style[t] = e : s.style.removeProperty(t === "lineHeight" ? "line-height" : "word-spacing");
1664
+ }), this.saveSel(), this.onChange();
1665
+ }
1666
+ currentBlockStyle(t) {
1667
+ const e = window.getSelection(), i = e ? this.closestBlock(e.anchorNode) : null;
1668
+ return i && i.style[t] || "";
1669
+ }
1670
+ lineHeightMenu(t) {
1671
+ const e = this.currentBlockStyle("lineHeight");
1672
+ this.popup(t, (i) => {
1673
+ this.menuItems(i, [
1674
+ { label: this.t("normal"), on: !e, action: () => this.applyBlockStyle("lineHeight", "") },
1675
+ ...Y.map((s) => ({
1676
+ label: s,
1677
+ on: e === s,
1678
+ action: () => this.applyBlockStyle("lineHeight", s)
1679
+ }))
1680
+ ]);
1681
+ });
1682
+ }
1683
+ wordSpacingMenu(t) {
1684
+ const e = this.currentBlockStyle("wordSpacing");
1685
+ this.popup(t, (i) => {
1686
+ this.menuItems(i, [
1687
+ { label: this.t("normal"), on: !e, action: () => this.applyBlockStyle("wordSpacing", "") },
1688
+ ...K.map((s) => ({
1689
+ label: s,
1690
+ on: e === s,
1691
+ action: () => this.applyBlockStyle("wordSpacing", s)
1692
+ }))
1693
+ ]);
1694
+ });
1695
+ }
1696
+ closestAnchor() {
1697
+ const t = window.getSelection();
1698
+ let e = t && this.ed.contains(t.anchorNode) ? t.anchorNode : null;
1699
+ for (; e && e !== this.ed; ) {
1700
+ if (e.nodeType === 1 && e.tagName === "A") return e;
1701
+ e = e.parentNode;
1702
+ }
1703
+ return null;
1704
+ }
1705
+ linkDlg() {
1706
+ this.saveSel();
1707
+ const t = this.closestAnchor();
1708
+ let e;
1709
+ const i = [];
1710
+ t && i.push({
1711
+ label: this.t("unlink"),
1712
+ action: () => {
1713
+ const s = document.createRange();
1714
+ s.selectNodeContents(t);
1715
+ const l = window.getSelection();
1716
+ l && (l.removeAllRanges(), l.addRange(s)), document.execCommand("unlink"), this.closeDlg(), this.onChange();
1717
+ }
1718
+ }), i.push(
1719
+ { label: this.t("cancel"), action: () => this.closeDlg() },
1720
+ {
1721
+ label: this.t("save"),
1722
+ primary: !0,
1723
+ action: () => {
1724
+ const s = e.value.trim();
1725
+ if (this.closeDlg(), !s) return;
1726
+ if (t) {
1727
+ t.setAttribute("href", s), this.onChange();
1728
+ return;
1729
+ }
1730
+ this.restoreSel();
1731
+ const l = window.getSelection();
1732
+ !l || l.isCollapsed ? document.execCommand("insertHTML", !1, `<a href="${s.replace(/"/g, "&quot;")}">${s.replace(/&/g, "&amp;").replace(/</g, "&lt;")}</a>`) : (document.execCommand("styleWithCSS", !1, "false"), document.execCommand("createLink", !1, s)), this.saveSel(), this.onChange();
1733
+ }
1734
+ }
1735
+ ), this.dialog(
1736
+ this.t("linkttl"),
1737
+ (s) => {
1738
+ const l = document.createElement("div");
1739
+ l.style.cssText = "display:flex;align-items:center;gap:10px;margin:10px 0;min-width:360px";
1740
+ const n = document.createElement("span");
1741
+ n.style.cssText = "width:60px;color:#556;flex:none", n.textContent = this.t("linkurl"), e = document.createElement("input"), e.type = "url", e.placeholder = "https://", e.style.cssText = "flex:1;border:1px solid #cfd6df;border-radius:6px;padding:7px 9px;font:14px inherit", e.value = (t == null ? void 0 : t.getAttribute("href")) || "", l.append(n, e), s.appendChild(l), setTimeout(() => e.focus(), 0);
1742
+ },
1743
+ i
1744
+ );
1745
+ }
1746
+ blocksMenu(t) {
1747
+ this.popup(t, (e) => {
1748
+ this.menuItems(
1749
+ e,
1750
+ D.map(([i, s]) => ({
1751
+ label: this.blockLabel(i),
1752
+ previewStyle: i.startsWith("h") ? `font-weight:700;font-size:${22 - 2 * +i[1]}px` : i === "pre" ? "font-family:monospace" : "",
1753
+ on: this.currentBlock() === i,
1754
+ action: () => this.exec("formatBlock", "<" + i + ">")
1755
+ }))
1756
+ );
1757
+ });
1758
+ }
1759
+ blockLabel(t) {
1760
+ return t === "p" ? this.t("para") : t === "pre" ? this.t("pre") : this.t("heading") + " " + t[1];
1761
+ }
1762
+ tableGrid(t, e) {
1763
+ this.popup(t, (i) => this.buildTableGridInto(i, e));
1764
+ }
1765
+ buildTableGridInto(t, e) {
1766
+ {
1767
+ const i = document.createElement("div");
1768
+ i.className = "tgridwrap";
1769
+ const s = document.createElement("div");
1770
+ s.className = "tgrid";
1771
+ const l = document.createElement("div");
1772
+ l.className = "tgridlbl", l.textContent = "1 × 1";
1773
+ const n = [];
1774
+ for (let o = 0; o < 8; o++)
1775
+ for (let r = 0; r < 10; r++) {
1776
+ const c = document.createElement("span");
1777
+ c.dataset.r = String(o), c.dataset.c = String(r), c.addEventListener("mouseenter", () => {
1778
+ n.forEach((h) => h.classList.toggle("hot", +h.dataset.r <= o && +h.dataset.c <= r)), l.textContent = r + 1 + " × " + (o + 1);
1779
+ }), c.addEventListener("click", () => {
1780
+ this.closePop(), this.insertTable(o + 1, r + 1), e == null || e();
1781
+ }), n.push(c), s.appendChild(c);
1782
+ }
1783
+ i.append(s, l), t.appendChild(i);
1784
+ }
1785
+ }
1786
+ insertTable(t, e) {
1787
+ this.restoreSel();
1788
+ let i = '<table style="border-collapse:collapse;width:100%;table-layout:fixed"><tbody>';
1789
+ for (let s = 0; s < t; s++) {
1790
+ i += "<tr>";
1791
+ for (let l = 0; l < e; l++) i += '<td style="border:1px solid #b9c2cc"><br></td>';
1792
+ i += "</tr>";
1793
+ }
1794
+ i += "</tbody></table><p><br></p>", document.execCommand("insertHTML", !1, i), this.saveSel(), this.onChange();
1795
+ }
1796
+ setDir(t) {
1797
+ this.restoreSel();
1798
+ const e = this.selectedBlocks();
1799
+ e.length ? e.forEach((i) => i.setAttribute("dir", t)) : this.ed.setAttribute("dir", t), this.saveSel(), this.refreshState(), this.onChange();
1800
+ }
1801
+ /** Splits a toolbar layout string into groups of item names: `|` separates visual
1802
+ * groups, whitespace separates items within a group. Empty groups/tokens (e.g. from
1803
+ * leading/trailing/doubled separators) are dropped. Pure function. */
1804
+ parseToolbarString(t) {
1805
+ return t.split("|").map((e) => e.trim().split(/\s+/).filter(Boolean)).filter((e) => e.length > 0);
1806
+ }
1807
+ /** Maps every supported toolbar item name to a builder for that one control. Each
1808
+ * entry is a direct lift of what used to be an inline call in `buildToolbar()` — no
1809
+ * behavior changes, just named lookup. Only `forecolor` yields multiple elements
1810
+ * (the quick color chips); everything else yields one. */
1811
+ buildToolbarRegistry() {
1812
+ const t = this.tbtn(a.tableic, this.t("quicktable"), () => this.tableGrid(t));
1813
+ return {
1814
+ undo: () => this.tbtn(a.undo, this.t("undo"), () => this.exec("undo")),
1815
+ redo: () => this.tbtn(a.redo, this.t("redo"), () => this.exec("redo")),
1816
+ preview: () => this.tbtn(a.prevw, this.t("preview"), () => this.previewDlg()),
1817
+ print: () => this.tbtn(a.printic, this.t("print"), () => this.printDoc()),
1818
+ importword: () => this.tbtn(a.wordic, this.t("importword"), () => this.pickWordDoc()),
1819
+ revhistory: () => this.tbtn(a.historyic, this.t("revhistory"), () => this.revisionDlg()),
1820
+ fontfamily: () => this.tsel("w-font", "fontsel", "", (e) => this.fontMenu(e)),
1821
+ fontsize: () => this.tsel("w-size", "sizesel", "", (e) => this.sizeMenu(e)),
1822
+ fontsizeincrease: () => this.stepBtn(1),
1823
+ fontsizedecrease: () => this.stepBtn(-1),
1824
+ bold: () => this.tbtn(a.bold, this.t("bold"), () => this.exec("bold"), "bold"),
1825
+ italic: () => this.tbtn(a.italic, this.t("italic"), () => this.exec("italic"), "italic"),
1826
+ underline: () => this.tbtn(a.underline, this.t("underline"), () => this.exec("underline"), "underline"),
1827
+ strikethrough: () => this.tbtn(a.strikethrough, this.t("strikethrough"), () => this.exec("strikeThrough"), "strikeThrough"),
1828
+ forecolor: () => this.colorChips(),
1829
+ backcolor: () => this.menuTbtn(
1830
+ a.backcolor + '<span class="colorbar" data-cb="back"></span>',
1831
+ this.t("backcolor"),
1832
+ (e) => this.colorMenu(e, "back")
1833
+ ),
1834
+ alignleft: () => this.tbtn(a.alignleft, this.t("alignleft"), () => this.exec("justifyLeft"), "justifyLeft"),
1835
+ aligncenter: () => this.tbtn(a.aligncenter, this.t("aligncenter"), () => this.exec("justifyCenter"), "justifyCenter"),
1836
+ alignright: () => this.tbtn(a.alignright, this.t("alignright"), () => this.exec("justifyRight"), "justifyRight"),
1837
+ alignjustify: () => this.tbtn(a.alignjustify, this.t("alignjustify"), () => this.exec("justifyFull"), "justifyFull"),
1838
+ bullist: () => this.menuTbtn(a.bullist, this.t("bullist"), (e) => this.listMenu(e, "ul"), "insertUnorderedList"),
1839
+ numlist: () => this.menuTbtn(a.numlist, this.t("numlist"), (e) => this.listMenu(e, "ol"), "insertOrderedList"),
1840
+ outdent: () => this.tbtn(a.outdent, this.t("outdent"), () => this.exec("outdent")),
1841
+ indent: () => this.tbtn(a.indent, this.t("indent"), () => this.exec("indent")),
1842
+ link: () => this.tbtn(a.link, this.t("linkttl"), () => this.linkDlg()),
1843
+ blockquote: () => this.tbtn(a.quote, this.t("quote"), () => this.toggleBlock("blockquote"), "blockquote"),
1844
+ changecase: () => this.menuTbtn(a.caseic, this.t("changecase"), (e) => this.caseMenu(e)),
1845
+ lineheight: () => this.menuTbtn(a.lineheight, this.t("lineheight"), (e) => this.lineHeightMenu(e)),
1846
+ wordspacing: () => this.menuTbtn(a.wordspacing, this.t("wordspacing"), (e) => this.wordSpacingMenu(e)),
1847
+ removeformat: () => this.tbtn(a.clearformatic, this.t("removeformat"), () => this.exec("removeFormat")),
1848
+ blocks: () => this.tsel("w-block", "blocksel", this.t("para"), (e) => this.blocksMenu(e)),
1849
+ ltr: () => this.tbtn(a.ltr, this.t("ltr"), () => this.setDir("ltr"), "ltr"),
1850
+ rtl: () => this.tbtn(a.rtl, this.t("rtl"), () => this.setDir("rtl"), "rtl"),
1851
+ quickimage: () => this.tbtn(a.image, this.t("quickimage"), () => this.insertImagePlaceholder()),
1852
+ quicktable: () => t,
1853
+ charmap: () => this.tbtn(a.charic, this.t("charmap"), () => this.charMap()),
1854
+ fullscreen: () => this.tbtn(a.fullscreen, this.t("fullscreen"), () => this.toggleFullscreen(), "fullscreen"),
1855
+ sourcecode: () => this.tbtn(a.srcic, this.t("sourcecode"), () => this.sourceDlg())
1856
+ };
1857
+ }
1858
+ buildToolbar() {
1859
+ this.toolbar.innerHTML = "";
1860
+ const t = this.options.toolbar === !0 ? U : this.options.toolbar, e = this.buildToolbarRegistry();
1861
+ this.parseToolbarString(t).forEach((i) => {
1862
+ const s = [];
1863
+ i.forEach((l) => {
1864
+ const n = e[l];
1865
+ if (!n) {
1866
+ console.warn(`FableEditor: unknown toolbar item "${l}"`);
1867
+ return;
1868
+ }
1869
+ const o = n();
1870
+ Array.isArray(o) ? s.push(...o) : s.push(o);
1871
+ }), s.length && this.toolbar.appendChild(this.group(...s));
1872
+ }), this.syncColorSwatches(this.toolbar);
1873
+ }
1874
+ /* ---------------------------------------------------------- menubar */
1875
+ mItem(t, e, i, s) {
1876
+ return { label: this.t(t), icon: e, action: i, shortcut: s };
1877
+ }
1878
+ buildMenubar() {
1879
+ this.menubar.innerHTML = "";
1880
+ const t = {
1881
+ file: [
1882
+ this.mItem("newdoc", a.newic, () => {
1883
+ this.recordRevision(), this.ed.innerHTML = "<p><br></p>", this.onChange();
1884
+ }),
1885
+ "|",
1886
+ this.mItem("importword", a.wordic, () => this.pickWordDoc()),
1887
+ this.mItem("restoredraft", a.draftic, () => {
1888
+ this.restoreDraft() || alert(this.t("draftempty"));
1889
+ }),
1890
+ this.mItem("revhistory", a.historyic, () => this.revisionDlg()),
1891
+ "|",
1892
+ this.mItem("preview", a.prevw, () => this.previewDlg()),
1893
+ this.mItem("print", a.printic, () => this.printDoc(), "Ctrl+P")
1894
+ ],
1895
+ edit: [
1896
+ this.mItem("undo", a.undo, () => this.exec("undo"), "Ctrl+Z"),
1897
+ this.mItem("redo", a.redo, () => this.exec("redo"), "Ctrl+Y"),
1898
+ "|",
1899
+ this.mItem("cut", a.cutic, () => this.exec("cut"), "Ctrl+X"),
1900
+ this.mItem("copy", a.copyic, () => this.exec("copy"), "Ctrl+C"),
1901
+ this.mItem("paste", a.pasteic, () => alert(this.t("pastehint")), "Ctrl+V"),
1902
+ "|",
1903
+ this.mItem("selectall", a.selall, () => this.exec("selectAll"), "Ctrl+A")
1904
+ ],
1905
+ view: [
1906
+ this.mItem("fullscreen", a.fullscreen, () => this.toggleFullscreen()),
1907
+ this.mItem("preview", a.prevw, () => this.previewDlg()),
1908
+ this.mItem("sourcecode", a.srcic, () => this.sourceDlg())
1909
+ ],
1910
+ insert: [
1911
+ this.mItem("link", a.link, () => this.linkDlg()),
1912
+ this.mItem("image", a.image, () => this.insertImagePlaceholder()),
1913
+ { label: this.t("inserttable"), icon: a.tableic, action: () => this.tableGrid(this.menubar.querySelector('[data-menu-key="table"]') || this.menubar) },
1914
+ this.mItem("hr", a.hric, () => this.exec("insertHorizontalRule")),
1915
+ "|",
1916
+ this.mItem("charmap", a.charic, () => this.charMap()),
1917
+ this.mItem(
1918
+ "datetime",
1919
+ a.dateic,
1920
+ () => this.exec("insertText", (/* @__PURE__ */ new Date()).toLocaleString(this.lang === "ar" ? "ar-AE" : "en-GB"))
1921
+ ),
1922
+ "|",
1923
+ {
1924
+ label: this.t("pagebreak"),
1925
+ icon: a.pbic,
1926
+ action: () => {
1927
+ this.restoreSel(), document.execCommand("insertHTML", !1, '<hr class="pagebreak"><p><br></p>'), this.onChange();
1928
+ }
1929
+ },
1930
+ this.mItem("nbsp", a.nbspic, () => this.exec("insertText", " "))
1931
+ ],
1932
+ format: [
1933
+ this.mItem("bold", a.bold, () => this.exec("bold"), "Ctrl+B"),
1934
+ this.mItem("italic", a.italic, () => this.exec("italic"), "Ctrl+I"),
1935
+ this.mItem("underline", a.underline, () => this.exec("underline"), "Ctrl+U"),
1936
+ this.mItem("strikethrough", a.strikethrough, () => this.exec("strikeThrough")),
1937
+ this.mItem("superscript", a.superscriptic, () => this.exec("superscript")),
1938
+ this.mItem("subscript", a.subscriptic, () => this.exec("subscript")),
1939
+ "|",
1940
+ this.mItem("lowercase", a.lowercaseic, () => this.transformCase("lower")),
1941
+ this.mItem("uppercase", a.uppercaseic, () => this.transformCase("upper")),
1942
+ this.mItem("capitalize", a.capitalizeic, () => this.transformCase("capitalize")),
1943
+ "|",
1944
+ this.mItem("clearformat", a.clearformatic, () => this.exec("removeFormat"))
1945
+ ],
1946
+ tools: [this.mItem("sourcecode", a.srcic, () => this.sourceDlg()), this.mItem("wordcount", a.wcic, () => this.wordCountDlg())],
1947
+ table: [
1948
+ { label: this.t("inserttable"), icon: a.tableic, subBuild: (s) => this.buildTableGridInto(s) },
1949
+ "|",
1950
+ {
1951
+ label: this.t("cell"),
1952
+ sub: [{ label: this.t("cellprops"), icon: a.tableic, action: () => this.cellPropsDlg() }]
1953
+ },
1954
+ {
1955
+ label: this.t("row"),
1956
+ sub: [
1957
+ { label: this.t("rowabove"), icon: a.rowbefore, action: () => this.tableOp("rowabove"), hover: (s) => this.setOpTarget(s ? "row" : null) },
1958
+ { label: this.t("rowbelow"), icon: a.rowafter, action: () => this.tableOp("rowbelow"), hover: (s) => this.setOpTarget(s ? "row" : null) },
1959
+ { label: this.t("delrow"), icon: a.rowdelete, action: () => this.tableOp("delrow"), hover: (s) => this.setOpTarget(s ? "row" : null) },
1960
+ "|",
1961
+ { label: this.t("rowprops"), icon: a.tableic, action: () => this.rowPropsDlg(), hover: (s) => this.setOpTarget(s ? "row" : null) }
1962
+ ]
1963
+ },
1964
+ {
1965
+ label: this.t("column"),
1966
+ sub: [
1967
+ { label: this.t("colbefore"), icon: a.colbefore, action: () => this.tableOp("colbefore"), hover: (s) => this.setOpTarget(s ? "col" : null) },
1968
+ { label: this.t("colafter"), icon: a.colafter, action: () => this.tableOp("colafter"), hover: (s) => this.setOpTarget(s ? "col" : null) },
1969
+ { label: this.t("delcol"), icon: a.coldelete, action: () => this.tableOp("delcol"), hover: (s) => this.setOpTarget(s ? "col" : null) },
1970
+ "|",
1971
+ { label: this.t("colprops"), icon: a.tableic, action: () => this.colPropsDlg(), hover: (s) => this.setOpTarget(s ? "col" : null) }
1972
+ ]
1973
+ },
1974
+ "|",
1975
+ {
1976
+ label: this.t("tablepropsttl"),
1977
+ icon: a.tableic,
1978
+ action: () => {
1979
+ const s = this.currentCell();
1980
+ if (!s) {
1981
+ alert(this.t("nocell"));
1982
+ return;
1983
+ }
1984
+ this.tblActive = s.closest("table"), this.tablePropsDlg();
1985
+ }
1986
+ },
1987
+ { label: this.t("deltable"), icon: a.tabledelete, action: () => this.tableOp("deltable") }
1988
+ ],
1989
+ help: [this.mItem("helpttl", a.helpic, () => this.helpDlg(), "Alt+0")]
1990
+ }, e = this.options.menubar === !0 ? j : this.options.menubar, i = /* @__PURE__ */ new Set();
1991
+ e.split(/\s+/).filter(Boolean).forEach((s) => {
1992
+ if (i.has(s)) return;
1993
+ if (i.add(s), !t[s]) {
1994
+ console.warn(`FableEditor: unknown menubar item "${s}"`);
1995
+ return;
1996
+ }
1997
+ const l = document.createElement("button");
1998
+ l.type = "button", l.textContent = this.t(s), l.dataset.menuKey = s, l.addEventListener("mousedown", (n) => {
1999
+ n.preventDefault(), this.saveSel();
2000
+ }), l.addEventListener("click", () => this.popup(l, (n) => this.menuItems(n, t[s]))), this.menubar.appendChild(l);
2001
+ });
2002
+ }
2003
+ /* ---------------------------------------------------------- table ops */
2004
+ tableOp(t) {
2005
+ var r, c, h;
2006
+ this.restoreSel();
2007
+ const e = window.getSelection();
2008
+ if (!e) return;
2009
+ const i = ((r = this.closestBlock(e.anchorNode)) == null ? void 0 : r.closest("td,th")) || (e.anchorNode && e.anchorNode.nodeType === 1 ? (h = (c = e.anchorNode).closest) == null ? void 0 : h.call(c, "td,th") : null);
2010
+ if (!i) return;
2011
+ const s = i.parentElement, l = i.closest("table"), n = Array.from(s.children).indexOf(i), o = () => {
2012
+ const d = s.cloneNode(!1);
2013
+ return Array.from(s.children).forEach((m) => {
2014
+ const g = document.createElement("td"), f = m.getAttribute("style");
2015
+ f && g.setAttribute("style", f), g.style.removeProperty("background-color"), g.innerHTML = "<br>", d.appendChild(g);
2016
+ }), d;
2017
+ };
2018
+ if (t === "rowabove" && s.before(o()), t === "rowbelow" && s.after(o()), t === "delrow") {
2019
+ const d = s.parentElement;
2020
+ s.remove(), d.querySelector("tr") || l.remove();
2021
+ }
2022
+ (t === "colbefore" || t === "colafter") && l.querySelectorAll("tr").forEach((d) => {
2023
+ const m = d.children[Math.min(n, d.children.length - 1)], g = document.createElement("td"), f = m.getAttribute("style");
2024
+ f && g.setAttribute("style", f), g.style.removeProperty("width"), g.style.removeProperty("background-color"), g.innerHTML = "<br>", t === "colbefore" ? m.before(g) : m.after(g);
2025
+ }), t === "delcol" && (l.querySelectorAll("tr").forEach((d) => {
2026
+ var m;
2027
+ return (m = d.children[n]) == null ? void 0 : m.remove();
2028
+ }), l.querySelector("td,th") || l.remove()), t === "deltable" && l.remove(), this.onChange(), this.positionTableHandles();
2029
+ }
2030
+ applyTableProps(t, e) {
2031
+ e.width ? t.style.width = /^\d+$/.test(e.width) ? e.width + "px" : e.width : t.style.removeProperty("width");
2032
+ const i = Array.from(t.querySelectorAll("td,th"));
2033
+ e.cellpadding !== "" ? i.forEach((s) => s.style.padding = e.cellpadding + "px") : i.forEach((s) => s.style.removeProperty("padding")), e.cellspacing !== "" ? (t.style.borderCollapse = "separate", t.style.borderSpacing = e.cellspacing + "px") : (t.style.borderCollapse = "collapse", t.style.removeProperty("border-spacing")), e.border !== "" && +e.border > 0 ? (t.style.border = e.border + "px solid #b9c2cc", i.forEach((s) => s.style.border = e.border + "px solid #b9c2cc")) : (t.style.removeProperty("border"), i.forEach((s) => s.style.removeProperty("border"))), t.style.removeProperty("margin-left"), t.style.removeProperty("margin-right"), e.align === "center" ? (t.style.marginLeft = "auto", t.style.marginRight = "auto") : e.align === "right" ? (t.style.marginLeft = "auto", t.style.marginRight = "0") : e.align === "left" && (t.style.marginLeft = "0", t.style.marginRight = "auto");
2034
+ }
2035
+ tablePropsDlg() {
2036
+ const t = this.tblActive;
2037
+ if (!t) return;
2038
+ let e, i, s, l, n;
2039
+ const o = "display:flex;align-items:center;gap:10px;margin:10px 0", r = "width:120px;color:#556;flex:none", c = "flex:1;border:1px solid #cfd6df;border-radius:6px;padding:7px 9px;font:14px inherit", h = t.querySelector("td,th"), d = t.style.width || "", m = h && h.style.padding ? parseFloat(h.style.padding) : "", g = t.style.borderSpacing ? parseFloat(t.style.borderSpacing) : "", f = t.style.borderWidth ? parseFloat(t.style.borderWidth) : "", b = t.style.marginLeft, v = t.style.marginRight, T = b === "auto" && v === "auto" ? "center" : b === "auto" ? "right" : v === "auto" && b === "0" ? "left" : "";
2040
+ this.dialog(
2041
+ this.t("tablepropsttl"),
2042
+ (M) => {
2043
+ const S = (x, E) => {
2044
+ const H = document.createElement("div");
2045
+ H.style.cssText = o;
2046
+ const N = document.createElement("span");
2047
+ N.style.cssText = r, N.textContent = this.t(x), H.append(N, E), M.appendChild(H);
2048
+ };
2049
+ e = document.createElement("input"), e.type = "text", e.style.cssText = c, e.placeholder = "e.g. 600px or 100%", e.value = d, S("tblwidth", e), i = document.createElement("input"), i.type = "number", i.min = "0", i.style.cssText = c, i.value = String(m), S("tblcellpadding", i), s = document.createElement("input"), s.type = "number", s.min = "0", s.style.cssText = c, s.value = String(g), S("tblcellspacing", s), l = document.createElement("input"), l.type = "number", l.min = "0", l.style.cssText = c, l.value = String(f), S("tblborder", l), n = document.createElement("select"), n.style.cssText = c, [
2050
+ ["", "alignnone"],
2051
+ ["left", "alignleft"],
2052
+ ["center", "aligncenter"],
2053
+ ["right", "alignright"]
2054
+ ].forEach(([x, E]) => {
2055
+ const H = document.createElement("option");
2056
+ H.value = x, H.textContent = this.t(E), x === T && (H.selected = !0), n.appendChild(H);
2057
+ }), S("tblalign", n);
2058
+ },
2059
+ [
2060
+ { label: this.t("cancel"), action: () => this.closeDlg() },
2061
+ {
2062
+ label: this.t("save"),
2063
+ primary: !0,
2064
+ action: () => {
2065
+ this.applyTableProps(t, {
2066
+ width: e.value.trim(),
2067
+ cellpadding: i.value.trim(),
2068
+ cellspacing: s.value.trim(),
2069
+ border: l.value.trim(),
2070
+ align: n.value
2071
+ }), this.closeDlg(), this.onChange(), this.positionTableHandles();
2072
+ }
2073
+ }
2074
+ ]
2075
+ );
2076
+ }
2077
+ /* ------------------------------------------- cell / row / column props */
2078
+ currentCell() {
2079
+ let t = this.savedRange ? this.savedRange.startContainer : null;
2080
+ if (!t || !this.ed.contains(t)) {
2081
+ const e = window.getSelection();
2082
+ t = e && this.ed.contains(e.anchorNode) ? e.anchorNode : null;
2083
+ }
2084
+ for (; t && t !== this.ed; ) {
2085
+ if (t.nodeType === 1 && /^(TD|TH)$/.test(t.tagName))
2086
+ return t;
2087
+ t = t.parentNode;
2088
+ }
2089
+ return null;
2090
+ }
2091
+ toHexColor(t) {
2092
+ if (/^#[0-9a-fA-F]{6}$/.test(t)) return t;
2093
+ const e = /rgba?\((\d+)[,\s]+(\d+)[,\s]+(\d+)/.exec(t);
2094
+ return e ? "#" + [e[1], e[2], e[3]].map((i) => (+i).toString(16).padStart(2, "0")).join("") : "";
2095
+ }
2096
+ formRow(t, e, i) {
2097
+ const s = document.createElement("div");
2098
+ s.style.cssText = "display:flex;align-items:center;gap:10px;margin:10px 0;min-width:360px";
2099
+ const l = document.createElement("span");
2100
+ l.style.cssText = "width:120px;color:#556;flex:none", l.textContent = e, s.append(l, i), t.appendChild(s);
2101
+ }
2102
+ formInput(t, e = "") {
2103
+ const i = document.createElement("input");
2104
+ return i.type = "text", i.style.cssText = "flex:1;border:1px solid #cfd6df;border-radius:6px;padding:7px 9px;font:14px inherit;min-width:0", i.value = t, i.placeholder = e, i;
2105
+ }
2106
+ formSelect(t, e) {
2107
+ const i = document.createElement("select");
2108
+ return i.style.cssText = "flex:1;border:1px solid #cfd6df;border-radius:6px;padding:7px 9px;font:14px inherit;background:#fff", t.forEach(([s, l]) => {
2109
+ const n = document.createElement("option");
2110
+ n.value = s, n.textContent = l, s === e && (n.selected = !0), i.appendChild(n);
2111
+ }), i;
2112
+ }
2113
+ formBg(t) {
2114
+ const e = document.createElement("div");
2115
+ e.style.cssText = "flex:1;display:flex;align-items:center;gap:8px";
2116
+ const i = this.toHexColor(t), s = document.createElement("input");
2117
+ s.type = "color", s.value = i || "#ffffff", s.style.cssText = "width:36px;height:29px;border:1px solid #cfd6df;border-radius:4px;padding:1px;background:none;cursor:pointer";
2118
+ const l = document.createElement("label");
2119
+ l.style.cssText = "display:flex;align-items:center;gap:6px;cursor:pointer;color:#556";
2120
+ const n = document.createElement("input");
2121
+ return n.type = "checkbox", n.checked = !!i, l.append(n, document.createTextNode(this.t("fill"))), s.addEventListener("input", () => n.checked = !0), e.append(s, l), { wrap: e, color: s, fill: n };
2122
+ }
2123
+ setOrClear(t, e, i) {
2124
+ i ? t.style.setProperty(e, /^(width|height)$/.test(e) && /^\d+$/.test(i) ? i + "px" : i) : t.style.removeProperty(e);
2125
+ }
2126
+ cellPropsDlg() {
2127
+ const t = this.currentCell();
2128
+ if (!t) {
2129
+ alert(this.t("nocell"));
2130
+ return;
2131
+ }
2132
+ let e, i, s, l, n;
2133
+ this.dialog(
2134
+ this.t("cellprops").replace("…", ""),
2135
+ (o) => {
2136
+ e = this.formInput(t.style.width, "e.g. 120px / 25%"), this.formRow(o, this.t("tblwidth"), e), i = this.formInput(t.style.height, "e.g. 40px"), this.formRow(o, this.t("tblheight"), i), s = this.formSelect(
2137
+ [
2138
+ ["", this.t("alignnone")],
2139
+ ["left", this.t("alignleft")],
2140
+ ["center", this.t("aligncenter")],
2141
+ ["right", this.t("alignright")]
2142
+ ],
2143
+ t.style.textAlign || ""
2144
+ ), this.formRow(o, this.t("tblalign"), s), l = this.formSelect(
2145
+ [
2146
+ ["", this.t("alignnone")],
2147
+ ["top", this.t("valigntop")],
2148
+ ["middle", this.t("valignmiddle")],
2149
+ ["bottom", this.t("valignbottom")]
2150
+ ],
2151
+ t.style.verticalAlign || ""
2152
+ ), this.formRow(o, this.t("valign"), l), n = this.formBg(t.style.backgroundColor || ""), this.formRow(o, this.t("backcolor"), n.wrap);
2153
+ },
2154
+ [
2155
+ { label: this.t("cancel"), action: () => this.closeDlg() },
2156
+ {
2157
+ label: this.t("save"),
2158
+ primary: !0,
2159
+ action: () => {
2160
+ this.setOrClear(t, "width", e.value.trim()), this.setOrClear(t, "height", i.value.trim()), this.setOrClear(t, "text-align", s.value), this.setOrClear(t, "vertical-align", l.value), this.setOrClear(t, "background-color", n.fill.checked ? n.color.value : ""), this.closeDlg(), this.onChange(), this.positionTableHandles();
2161
+ }
2162
+ }
2163
+ ]
2164
+ );
2165
+ }
2166
+ rowPropsDlg() {
2167
+ const t = this.currentCell();
2168
+ if (!t) {
2169
+ alert(this.t("nocell"));
2170
+ return;
2171
+ }
2172
+ const e = t.parentElement;
2173
+ let i, s;
2174
+ this.dialog(
2175
+ this.t("rowprops").replace("…", ""),
2176
+ (l) => {
2177
+ i = this.formInput(e.style.height, "e.g. 40px"), this.formRow(l, this.t("tblheight"), i), s = this.formBg(e.style.backgroundColor || ""), this.formRow(l, this.t("backcolor"), s.wrap);
2178
+ },
2179
+ [
2180
+ { label: this.t("cancel"), action: () => this.closeDlg() },
2181
+ {
2182
+ label: this.t("save"),
2183
+ primary: !0,
2184
+ action: () => {
2185
+ this.setOrClear(e, "height", i.value.trim()), this.setOrClear(e, "background-color", s.fill.checked ? s.color.value : ""), this.closeDlg(), this.onChange(), this.positionTableHandles();
2186
+ }
2187
+ }
2188
+ ]
2189
+ );
2190
+ }
2191
+ colPropsDlg() {
2192
+ const t = this.currentCell();
2193
+ if (!t) {
2194
+ alert(this.t("nocell"));
2195
+ return;
2196
+ }
2197
+ const e = t.parentElement, i = t.closest("table"), s = Array.from(e.children).indexOf(t), l = Array.from(i.rows).map((r) => r.cells[s]).filter(Boolean);
2198
+ let n, o;
2199
+ this.dialog(
2200
+ this.t("colprops").replace("…", ""),
2201
+ (r) => {
2202
+ n = this.formInput(t.style.width, "e.g. 120px / 25%"), this.formRow(r, this.t("tblwidth"), n), o = this.formBg(t.style.backgroundColor || ""), this.formRow(r, this.t("backcolor"), o.wrap);
2203
+ },
2204
+ [
2205
+ { label: this.t("cancel"), action: () => this.closeDlg() },
2206
+ {
2207
+ label: this.t("save"),
2208
+ primary: !0,
2209
+ action: () => {
2210
+ l.forEach((r) => {
2211
+ this.setOrClear(r, "width", n.value.trim()), this.setOrClear(r, "background-color", o.fill.checked ? o.color.value : "");
2212
+ }), this.closeDlg(), this.onChange(), this.positionTableHandles();
2213
+ }
2214
+ }
2215
+ ]
2216
+ );
2217
+ }
2218
+ /* ---------------------------------------------------------- dialogs */
2219
+ closeDlg() {
2220
+ this.dlgOvl && (this.dlgOvl.remove(), this.dlgOvl = null);
2221
+ }
2222
+ dialog(t, e, i) {
2223
+ this.closeDlg(), this.closePop(), this.dlgOvl = document.createElement("div"), this.dlgOvl.className = "ovl";
2224
+ const s = document.createElement("div");
2225
+ s.className = "dlg", s.dir = this.dir(), s.innerHTML = `<header><span>${t}</span><button type="button">×</button></header>
2226
+ <div class="body"></div><footer></footer>`, s.querySelector("header button").onclick = () => this.closeDlg(), e(s.querySelector(".body")), (i || [{ label: this.t("close"), primary: !0, action: () => this.closeDlg() }]).forEach((l) => {
2227
+ const n = document.createElement("button");
2228
+ n.type = "button", n.textContent = l.label, l.primary && (n.className = "pri"), n.onclick = l.action, s.querySelector("footer").appendChild(n);
2229
+ }), this.dlgOvl.appendChild(s), this.dlgOvl.addEventListener("mousedown", (l) => {
2230
+ l.target === this.dlgOvl && this.closeDlg();
2231
+ }), document.body.appendChild(this.dlgOvl);
2232
+ }
2233
+ sourceDlg() {
2234
+ let t;
2235
+ this.dialog(
2236
+ this.t("srcttl"),
2237
+ (e) => {
2238
+ t = document.createElement("textarea"), t.value = this.ed.innerHTML.replace(/></g, `>
2239
+ <`), e.appendChild(t);
2240
+ },
2241
+ [
2242
+ { label: this.t("cancel"), action: () => this.closeDlg() },
2243
+ {
2244
+ label: this.t("save"),
2245
+ primary: !0,
2246
+ action: () => {
2247
+ this.ed.innerHTML = t.value, this.closeDlg(), this.onChange();
2248
+ }
2249
+ }
2250
+ ]
2251
+ );
2252
+ }
2253
+ helpDlg() {
2254
+ this.dialog(this.t("helpttl"), (t) => {
2255
+ const e = [
2256
+ ["Ctrl+B", this.t("bold")],
2257
+ ["Ctrl+I", this.t("italic")],
2258
+ ["Ctrl+U", this.t("underline")],
2259
+ ["Ctrl+Z", this.t("undo")],
2260
+ ["Ctrl+Y", this.t("redo")],
2261
+ ["Ctrl+A", this.t("selectall")],
2262
+ ["Alt+0", this.t("helpttl")]
2263
+ ];
2264
+ t.innerHTML = `<p style="color:#556">${this.t("shortcuts")}</p>
2265
+ <table class="kbd">${e.map((i) => `<tr><td>${i[1]}</td><td><kbd>${i[0]}</kbd></td></tr>`).join("")}</table>`;
2266
+ });
2267
+ }
2268
+ wordCountDlg() {
2269
+ this.dialog(this.t("wcttl"), (t) => {
2270
+ var e;
2271
+ t.innerHTML = `<table class="kbd">
2272
+ <tr><td>${this.t("wcwords")}</td><td>${this.countWords()}</td></tr>
2273
+ <tr><td>${this.t("wcchars")}</td><td>${((e = this.ed.textContent) == null ? void 0 : e.replace(/\s/g, "").length) ?? 0}</td></tr></table>`;
2274
+ });
2275
+ }
2276
+ previewDlg() {
2277
+ this.dialog(this.t("previewttl"), (t) => {
2278
+ const e = document.createElement("div");
2279
+ e.style.cssText = "width:640px;max-width:78vw;max-height:52vh;overflow:auto;border:1px solid #e3e3e3;border-radius:6px;padding:14px;font-family:Helvetica,Arial,sans-serif;font-size:14px", e.innerHTML = this.ed.innerHTML, t.appendChild(e);
2280
+ });
2281
+ }
2282
+ charMap() {
2283
+ this.dialog(
2284
+ this.t("charmap").replace("…", ""),
2285
+ (t) => {
2286
+ const e = document.createElement("div");
2287
+ e.className = "chgrid", tt.forEach((i) => {
2288
+ const s = document.createElement("button");
2289
+ s.textContent = i, s.onclick = () => {
2290
+ this.closeDlg(), this.exec("insertText", i);
2291
+ }, e.appendChild(s);
2292
+ }), t.appendChild(e);
2293
+ }
2294
+ );
2295
+ }
2296
+ printDoc() {
2297
+ const t = window.open("", "_blank");
2298
+ t && (t.document.write(
2299
+ `<html dir="${this.dir()}"><body style="font-family:Helvetica,Arial,sans-serif;font-size:14px">${this.ed.innerHTML}</body></html>`
2300
+ ), t.document.close(), t.focus(), t.print());
2301
+ }
2302
+ pickImage() {
2303
+ this.imgInput.value = "", this.imgInput.click();
2304
+ }
2305
+ /* ---------------------------------------------- image upload placeholder */
2306
+ insertImagePlaceholder() {
2307
+ this.restoreSel();
2308
+ const t = "img-ph-" + Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
2309
+ document.execCommand(
2310
+ "insertHTML",
2311
+ !1,
2312
+ `<div class="img-ph" id="${t}" contenteditable="false">${a.image}<span>${this.t("dropimage")}</span></div>`
2313
+ );
2314
+ const e = this.ed.querySelector("#" + t);
2315
+ e && (e.removeAttribute("id"), this.selectImgPlaceholder(e)), this.onChange();
2316
+ }
2317
+ clearImgPlaceholderSel() {
2318
+ var t, e;
2319
+ (t = this.phCtx) == null || t.remove(), this.phCtx = null, (e = this.phActive) == null || e.classList.remove("active"), this.phActive = null;
2320
+ }
2321
+ selectImgPlaceholder(t) {
2322
+ this.phActive !== t && (this.clearImgPlaceholderSel(), this.phActive = t, t.classList.add("active"), this.phCtx = document.createElement("div"), this.phCtx.className = "imgctx img-ph-ctx", this.phCtx.dir = this.dir(), document.body.appendChild(this.phCtx), this.renderPhCtxButtons());
2323
+ }
2324
+ renderPhCtxButtons() {
2325
+ const t = this.phCtx;
2326
+ t && (t.innerHTML = "", t.append(
2327
+ this.ctxBtn(a.uploadic, this.t("uploadimg"), () => {
2328
+ this.phUploadTarget = this.phActive, this.pickImage();
2329
+ }),
2330
+ this.ctxBtn(a.link, this.t("imagelink"), () => this.renderPhCtxUrlInput())
2331
+ ), this.positionImgPhCtx());
2332
+ }
2333
+ renderPhCtxUrlInput() {
2334
+ const t = this.phCtx;
2335
+ if (!t) return;
2336
+ t.innerHTML = "";
2337
+ const e = document.createElement("input");
2338
+ e.type = "url", e.className = "urlinp", e.placeholder = this.t("imageurlph");
2339
+ const i = document.createElement("button");
2340
+ i.type = "button", i.className = "txtbtn", i.textContent = this.t("insertimg");
2341
+ const s = () => {
2342
+ const l = e.value.trim(), n = this.phActive;
2343
+ if (!n) return;
2344
+ if (!/^(https?:|data:image\/|blob:)/i.test(l)) {
2345
+ e.classList.add("err"), e.focus();
2346
+ return;
2347
+ }
2348
+ i.disabled = !0, e.disabled = !0;
2349
+ const o = new Image();
2350
+ o.onload = () => this.replacePlaceholderWithImage(n, l, ""), o.onerror = () => {
2351
+ i.disabled = !1, e.disabled = !1, e.classList.add("err"), e.focus();
2352
+ }, o.src = l;
2353
+ };
2354
+ i.addEventListener("click", s), e.addEventListener("input", () => e.classList.remove("err")), e.addEventListener("keydown", (l) => {
2355
+ l.key === "Enter" ? (l.preventDefault(), s()) : l.key === "Escape" && (l.stopPropagation(), this.renderPhCtxButtons());
2356
+ }), t.append(e, i), this.positionImgPhCtx(), e.focus();
2357
+ }
2358
+ readImageFileInto(t, e) {
2359
+ if (e.classList.contains("uploading")) return;
2360
+ if (this.imageUploadHandler) {
2361
+ this.uploadImageFile(t, e);
2362
+ return;
2363
+ }
2364
+ const i = new FileReader();
2365
+ i.onload = () => {
2366
+ this.ed.contains(e) && this.replacePlaceholderWithImage(e, i.result, t.name.replace(/"/g, ""));
2367
+ }, i.readAsDataURL(t);
2368
+ }
2369
+ /** Runs the host-supplied imageUploadHandler instead of inlining base64,
2370
+ * so apps can route the file to S3 / Azure Blob / their own server. */
2371
+ uploadImageFile(t, e) {
2372
+ const i = t.name.replace(/"/g, "");
2373
+ e.classList.remove("upload-error"), e.classList.add("uploading");
2374
+ const s = e.querySelector("span");
2375
+ s && (s.textContent = this.t("uploading")), this.imageUploadHandler(t).then((l) => {
2376
+ this.ed.contains(e) && this.replacePlaceholderWithImage(e, l, i);
2377
+ }).catch((l) => {
2378
+ var n;
2379
+ this.ed.contains(e) && (e.classList.remove("uploading"), e.classList.add("upload-error"), s && (s.textContent = this.t("uploadfailed")), (n = this.onImageUploadError) == null || n.call(this, l, t));
2380
+ });
2381
+ }
2382
+ replacePlaceholderWithImage(t, e, i) {
2383
+ const s = document.createElement("img");
2384
+ s.src = e, s.alt = "", i && (s.title = i), t.replaceWith(s), this.phActive === t && this.clearImgPlaceholderSel(), this.refreshState(), this.onChange();
2385
+ }
2386
+ positionImgPhCtx() {
2387
+ if (this.phActive && !document.body.contains(this.phActive)) {
2388
+ this.clearImgPlaceholderSel();
2389
+ return;
2390
+ }
2391
+ if (!this.phActive || !this.phCtx) return;
2392
+ const t = this.phActive.getBoundingClientRect(), e = this.phCtx.offsetWidth, i = this.phCtx.offsetHeight;
2393
+ let s = t.left + scrollX + (t.width - e) / 2;
2394
+ s = Math.max(8 + scrollX, Math.min(s, scrollX + innerWidth - e - 8));
2395
+ let l = t.bottom + scrollY + 8;
2396
+ t.bottom + 8 + i > innerHeight - 4 && (l = Math.max(this.ctxMinTop(), t.top + scrollY - i - 8)), this.phCtx.style.left = s + "px", this.phCtx.style.top = l + "px";
2397
+ }
2398
+ pickWordDoc() {
2399
+ this.docInput.value = "", this.docInput.click();
2400
+ }
2401
+ /* ---------------------------------------------------------- fullscreen */
2402
+ toggleFullscreen() {
2403
+ this.shell.classList.toggle("fullscreen");
2404
+ const t = this.toolbar.querySelector("[data-id=fullscreen]");
2405
+ t == null || t.classList.toggle("on", this.shell.classList.contains("fullscreen")), this.positionTableHandles();
2406
+ }
2407
+ /* ---------------------------------------------------------- table resize */
2408
+ clearTableHandles() {
2409
+ var t, e, i, s, l;
2410
+ (t = this.tblCorner) == null || t.remove(), this.tblCorner = null, this.tblColBars.forEach((n) => n.remove()), this.tblColBars = [], (e = this.tblCtx) == null || e.remove(), this.tblCtx = null, (i = this.tblCellMark) == null || i.remove(), this.tblCellMark = null, (s = this.tblOpMark) == null || s.remove(), this.tblOpMark = null, this.tblOpMarkKind = null, (l = this.tblActive) == null || l.classList.remove("tbl-selected"), this.tblActive = null;
2411
+ }
2412
+ /** Blue outline around the cell that holds the caret, so it is clear
2413
+ which cell / row / column the table operations will target. */
2414
+ positionCellMarker() {
2415
+ if (!this.tblCellMark) return;
2416
+ const t = this.currentCell();
2417
+ if (!t || !this.tblActive || t.closest("table") !== this.tblActive) {
2418
+ this.tblCellMark.style.display = "none";
2419
+ return;
2420
+ }
2421
+ const e = t.getBoundingClientRect();
2422
+ this.tblCellMark.style.display = "block", this.tblCellMark.style.left = e.left + scrollX + "px", this.tblCellMark.style.top = e.top + scrollY + "px", this.tblCellMark.style.width = e.width + "px", this.tblCellMark.style.height = e.height + "px";
2423
+ }
2424
+ /** Dashed highlight over the whole row / column an operation targets,
2425
+ shown while its button or menu item is hovered. */
2426
+ setOpTarget(t) {
2427
+ this.tblOpMarkKind = t, this.positionOpMark();
2428
+ }
2429
+ positionOpMark() {
2430
+ var h;
2431
+ const t = this.tblOpMarkKind, e = t ? this.currentCell() : null;
2432
+ if (!t || !e || !this.tblActive || e.closest("table") !== this.tblActive) {
2433
+ (h = this.tblOpMark) == null || h.remove(), this.tblOpMark = null;
2434
+ return;
2435
+ }
2436
+ this.tblOpMark || (this.tblOpMark = document.createElement("div"), this.tblOpMark.className = "tbl-opmark", document.body.appendChild(this.tblOpMark));
2437
+ const i = this.tblActive.getBoundingClientRect(), s = e.getBoundingClientRect(), l = e.parentElement.getBoundingClientRect(), n = t === "row" ? l.left : s.left, o = t === "row" ? l.top : i.top, r = t === "row" ? l.width : s.width, c = t === "row" ? l.height : i.height;
2438
+ this.tblOpMark.style.left = n + scrollX + "px", this.tblOpMark.style.top = o + scrollY + "px", this.tblOpMark.style.width = r + "px", this.tblOpMark.style.height = c + "px";
2439
+ }
2440
+ /** Lowest allowed top for floating context toolbars — keeps them from
2441
+ covering the editor menubar/toolbar when the target sits on the first line. */
2442
+ ctxMinTop() {
2443
+ return Math.max(scrollY + 4, this.ed.getBoundingClientRect().top + scrollY - 2);
2444
+ }
2445
+ ctxBtn(t, e, i, s) {
2446
+ const l = document.createElement("button");
2447
+ return l.type = "button", l.title = e, l.innerHTML = t, s && (l.dataset.id = s), l.addEventListener("mousedown", (n) => n.preventDefault()), l.addEventListener("click", i), l;
2448
+ }
2449
+ ctxSep() {
2450
+ const t = document.createElement("div");
2451
+ return t.className = "sep", t;
2452
+ }
2453
+ buildTableCtxToolbar() {
2454
+ const t = document.createElement("div");
2455
+ t.className = "tblctx", t.dir = this.dir();
2456
+ const e = (i, s) => (i.addEventListener("mouseenter", () => this.setOpTarget(s)), i.addEventListener("mouseleave", () => this.setOpTarget(null)), i);
2457
+ return t.append(
2458
+ e(this.ctxBtn(a.rowbefore, this.t("rowabove"), () => this.tableOp("rowabove")), "row"),
2459
+ e(this.ctxBtn(a.rowafter, this.t("rowbelow"), () => this.tableOp("rowbelow")), "row"),
2460
+ e(this.ctxBtn(a.rowdelete, this.t("delrow"), () => this.tableOp("delrow")), "row"),
2461
+ this.ctxSep(),
2462
+ e(this.ctxBtn(a.colbefore, this.t("colbefore"), () => this.tableOp("colbefore")), "col"),
2463
+ e(this.ctxBtn(a.colafter, this.t("colafter"), () => this.tableOp("colafter")), "col"),
2464
+ e(this.ctxBtn(a.coldelete, this.t("delcol"), () => this.tableOp("delcol")), "col"),
2465
+ this.ctxSep(),
2466
+ this.ctxBtn(a.tabledelete, this.t("deltable"), () => this.tableOp("deltable")),
2467
+ this.ctxBtn(a.tableic, this.t("tablepropsttl"), () => this.tablePropsDlg())
2468
+ ), document.body.appendChild(t), t;
2469
+ }
2470
+ positionTableHandles() {
2471
+ if (!this.tblActive || !document.body.contains(this.tblActive)) {
2472
+ this.clearTableHandles();
2473
+ return;
2474
+ }
2475
+ const t = this.ed.getAttribute("dir") === "rtl", e = this.tblActive.getBoundingClientRect(), i = e.top + scrollY, s = e.left + scrollX, l = e.right + scrollX, n = e.bottom + scrollY;
2476
+ if (this.tblCorner && (this.tblCorner.style.top = n - 5 + "px", this.tblCorner.style.left = (t ? s - 5 : l - 5) + "px", this.tblCorner.style.cursor = t ? "nesw-resize" : "nwse-resize"), this.tblCtx) {
2477
+ const r = this.tblCtx.offsetWidth, c = this.tblCtx.offsetHeight;
2478
+ let h = s + (l - s) / 2 - r / 2;
2479
+ h = Math.max(8 + scrollX, Math.min(h, scrollX + innerWidth - r - 8));
2480
+ let d = i - c - 8;
2481
+ d < this.ctxMinTop() && (d = n + 8), this.tblCtx.style.left = h + "px", this.tblCtx.style.top = d + "px";
2482
+ }
2483
+ this.tblColBars.forEach((r) => r.remove()), this.tblColBars = [];
2484
+ const o = this.tblActive.rows[0];
2485
+ if (o)
2486
+ for (let r = 0; r < o.cells.length - 1; r++) {
2487
+ const c = o.cells[r].getBoundingClientRect(), h = (t ? c.left : c.right) + scrollX, d = document.createElement("div");
2488
+ d.className = "tbl-colbar", d.style.top = i + "px", d.style.left = h + "px", d.style.height = n - i + "px", document.body.appendChild(d), d.addEventListener("mousedown", (m) => this.startColBarDrag(m, r)), this.tblColBars.push(d);
2489
+ }
2490
+ this.positionCellMarker(), this.positionOpMark();
2491
+ }
2492
+ selectTableForResize(t) {
2493
+ this.tblActive !== t && (this.clearTableHandles(), this.tblActive = t, t.classList.add("tbl-selected"), this.tblCorner = document.createElement("div"), this.tblCorner.className = "tbl-handle", document.body.appendChild(this.tblCorner), this.tblCorner.addEventListener("mousedown", (e) => this.startTableCornerDrag(e)), this.tblCellMark = document.createElement("div"), this.tblCellMark.className = "tbl-cellmark", this.tblCellMark.style.display = "none", document.body.appendChild(this.tblCellMark), this.tblCtx = this.buildTableCtxToolbar(), this.positionTableHandles());
2494
+ }
2495
+ withNoTextSelect(t) {
2496
+ const e = document.body.style.userSelect;
2497
+ document.body.style.userSelect = "none", t(() => {
2498
+ document.body.style.userSelect = e;
2499
+ });
2500
+ }
2501
+ startTableCornerDrag(t) {
2502
+ t.preventDefault();
2503
+ const e = this.tblActive;
2504
+ if (!e) return;
2505
+ const i = this.ed.getAttribute("dir") === "rtl", s = t.clientX, l = e.getBoundingClientRect().width;
2506
+ e.style.tableLayout = e.style.tableLayout || "fixed", this.withNoTextSelect((n) => {
2507
+ const o = (c) => {
2508
+ const h = i ? -(c.clientX - s) : c.clientX - s;
2509
+ e.style.width = Math.max(60, Math.round(l + h)) + "px", this.positionTableHandles();
2510
+ }, r = () => {
2511
+ window.removeEventListener("mousemove", o), window.removeEventListener("mouseup", r), n(), this.onChange();
2512
+ };
2513
+ window.addEventListener("mousemove", o), window.addEventListener("mouseup", r);
2514
+ });
2515
+ }
2516
+ startColBarDrag(t, e) {
2517
+ t.preventDefault(), t.stopPropagation();
2518
+ const i = this.tblActive;
2519
+ if (!i) return;
2520
+ const s = this.ed.getAttribute("dir") === "rtl", l = Array.from(i.rows), n = l.map((d) => d.cells[e]).filter(Boolean), o = l.map((d) => d.cells[e + 1]).filter(Boolean);
2521
+ if (!n.length || !o.length) return;
2522
+ const r = t.clientX, c = n[0].getBoundingClientRect().width, h = o[0].getBoundingClientRect().width;
2523
+ i.style.tableLayout = "fixed", this.withNoTextSelect((d) => {
2524
+ const m = (f) => {
2525
+ const b = (s ? -1 : 1) * (f.clientX - r);
2526
+ n.forEach((v) => v.style.width = Math.max(24, Math.round(c + b)) + "px"), o.forEach((v) => v.style.width = Math.max(24, Math.round(h - b)) + "px"), this.positionTableHandles();
2527
+ }, g = () => {
2528
+ window.removeEventListener("mousemove", m), window.removeEventListener("mouseup", g), d(), this.onChange();
2529
+ };
2530
+ window.addEventListener("mousemove", m), window.addEventListener("mouseup", g);
2531
+ });
2532
+ }
2533
+ /* ---------------------------------------------------------- image toolbar / resize */
2534
+ cancelImgHide() {
2535
+ this.imgHideTimer != null && (window.clearTimeout(this.imgHideTimer), this.imgHideTimer = null);
2536
+ }
2537
+ scheduleImgHide() {
2538
+ this.cancelImgHide(), this.imgHideTimer = window.setTimeout(() => this.clearImageHandles(), 250);
2539
+ }
2540
+ clearImageHandles() {
2541
+ var t, e;
2542
+ this.cancelImgHide(), this.imgHandles.forEach((i) => i.remove()), this.imgHandles = [], (t = this.imgCtx) == null || t.remove(), this.imgCtx = null, (e = this.imgActive) == null || e.classList.remove("img-selected"), this.imgActive = null;
2543
+ }
2544
+ selectImage(t) {
2545
+ this.imgActive !== t && (this.clearImageHandles(), this.imgActive = t, t.classList.add("img-selected"), this.imgHandles = vt.map((e) => {
2546
+ const i = document.createElement("div");
2547
+ return i.className = "img-handle img-handle-" + e, i.dataset.corner = e, i.addEventListener("mousedown", (s) => this.startImageResizeDrag(s, e)), i.addEventListener("mouseenter", () => this.cancelImgHide()), i.addEventListener("mouseleave", () => this.scheduleImgHide()), document.body.appendChild(i), i;
2548
+ }), this.imgCtx = this.buildImageCtxToolbar(t), this.positionImageHandles());
2549
+ }
2550
+ buildImageCtxToolbar(t) {
2551
+ const e = document.createElement("div");
2552
+ e.className = "imgctx", e.dir = this.dir();
2553
+ const i = () => {
2554
+ var h;
2555
+ const c = this.buildImageCtxToolbar(t);
2556
+ (h = this.imgCtx) == null || h.replaceWith(c), this.imgCtx = c, this.positionImageHandles();
2557
+ }, s = (c) => {
2558
+ this.setImageAlign(t, c), i();
2559
+ }, l = t.style.float === "left", n = t.style.float === "right", o = !l && !n && t.style.marginLeft === "auto" && t.style.marginRight === "auto", r = (c, h, d, m) => {
2560
+ const g = this.ctxBtn(c, h, m);
2561
+ return g.classList.toggle("on", d), g;
2562
+ };
2563
+ return e.append(
2564
+ r(a.alignleft, this.t("alignleft"), l, () => s("left")),
2565
+ r(a.aligncenter, this.t("aligncenter"), o, () => s("center")),
2566
+ r(a.alignright, this.t("alignright"), n, () => s("right")),
2567
+ this.ctxSep(),
2568
+ r(a.rotateleft, this.t("rotateleft"), !1, () => {
2569
+ this.rotateImage(t, -90), i();
2570
+ }),
2571
+ r(a.rotateright, this.t("rotateright"), !1, () => {
2572
+ this.rotateImage(t, 90), i();
2573
+ }),
2574
+ this.ctxSep(),
2575
+ r(a.fliphorizontal, this.t("fliphorizontal"), t.dataset.flipx === "1", () => {
2576
+ this.flipImage(t, "x"), i();
2577
+ }),
2578
+ r(a.flipvertical, this.t("flipvertical"), t.dataset.flipy === "1", () => {
2579
+ this.flipImage(t, "y"), i();
2580
+ }),
2581
+ this.ctxSep(),
2582
+ r(a.trash, this.t("deleteimg"), !1, () => {
2583
+ t.remove(), this.clearImageHandles(), this.onChange();
2584
+ })
2585
+ ), e.addEventListener("mousedown", (c) => c.preventDefault()), e.addEventListener("mouseenter", () => this.cancelImgHide()), e.addEventListener("mouseleave", () => this.scheduleImgHide()), document.body.appendChild(e), e;
2586
+ }
2587
+ setImageAlign(t, e) {
2588
+ t.style.float = "", t.style.display = "", t.style.marginLeft = "", t.style.marginRight = "", t.style.marginBottom = "", e === "left" ? (t.style.float = "left", t.style.marginInlineEnd = "1em", t.style.marginBottom = "0.5em") : e === "right" ? (t.style.float = "right", t.style.marginInlineStart = "1em", t.style.marginBottom = "0.5em") : (t.style.display = "block", t.style.marginLeft = "auto", t.style.marginRight = "auto"), this.onChange();
2589
+ }
2590
+ applyImgTransform(t) {
2591
+ const e = parseInt(t.dataset.rotate || "0", 10), i = t.dataset.flipx === "1" ? -1 : 1, s = t.dataset.flipy === "1" ? -1 : 1;
2592
+ t.style.transform = e || i < 0 || s < 0 ? `rotate(${e}deg) scale(${i}, ${s})` : "";
2593
+ }
2594
+ rotateImage(t, e) {
2595
+ const i = ((parseInt(t.dataset.rotate || "0", 10) + e) % 360 + 360) % 360;
2596
+ t.dataset.rotate = String(i), this.applyImgTransform(t), this.positionImageHandles(), this.onChange();
2597
+ }
2598
+ flipImage(t, e) {
2599
+ const i = e === "x" ? "flipx" : "flipy";
2600
+ t.dataset[i] = t.dataset[i] === "1" ? "" : "1", this.applyImgTransform(t), this.positionImageHandles(), this.onChange();
2601
+ }
2602
+ positionImageHandles() {
2603
+ if (!this.imgActive || !document.body.contains(this.imgActive)) {
2604
+ this.clearImageHandles();
2605
+ return;
2606
+ }
2607
+ const t = this.imgActive.getBoundingClientRect(), e = t.top + scrollY, i = t.left + scrollX, s = t.right + scrollX, l = t.bottom + scrollY, n = {
2608
+ nw: [i, e],
2609
+ ne: [s, e],
2610
+ sw: [i, l],
2611
+ se: [s, l]
2612
+ };
2613
+ if (this.imgHandles.forEach((o) => {
2614
+ const [r, c] = n[o.dataset.corner];
2615
+ o.style.left = r - 5 + "px", o.style.top = c - 5 + "px";
2616
+ }), this.imgCtx) {
2617
+ const o = this.imgCtx.offsetWidth, r = this.imgCtx.offsetHeight;
2618
+ let c = i + (s - i) / 2 - o / 2;
2619
+ c = Math.max(8 + scrollX, Math.min(c, scrollX + innerWidth - o - 8));
2620
+ let h = e - r - 8;
2621
+ h < this.ctxMinTop() && (h = l + 8), this.imgCtx.style.left = c + "px", this.imgCtx.style.top = h + "px";
2622
+ }
2623
+ }
2624
+ startImageResizeDrag(t, e) {
2625
+ t.preventDefault();
2626
+ const i = this.imgActive;
2627
+ if (!i) return;
2628
+ this.cancelImgHide();
2629
+ const s = t.clientX, l = i.getBoundingClientRect().width, n = e === "nw" || e === "sw" ? -1 : 1;
2630
+ this.withNoTextSelect((o) => {
2631
+ const r = (h) => {
2632
+ i.style.width = Math.max(24, Math.round(l + n * (h.clientX - s))) + "px", i.style.height = "auto", this.positionImageHandles();
2633
+ }, c = () => {
2634
+ window.removeEventListener("mousemove", r), window.removeEventListener("mouseup", c), o(), this.onChange();
2635
+ };
2636
+ window.addEventListener("mousemove", r), window.addEventListener("mouseup", c);
2637
+ });
2638
+ }
2639
+ /* ---------------------------------------------------------- selection bubble toolbar */
2640
+ toggleBlock(t) {
2641
+ this.exec("formatBlock", this.currentBlock() === t ? "<p>" : "<" + t + ">");
2642
+ }
2643
+ clearSelToolbar() {
2644
+ var t;
2645
+ (t = this.selCtx) == null || t.remove(), this.selCtx = null;
2646
+ }
2647
+ updateSelToolbar(t) {
2648
+ if (this.options.readonly || t.isCollapsed || !t.rangeCount) {
2649
+ this.clearSelToolbar();
2650
+ return;
2651
+ }
2652
+ const e = t.getRangeAt(0), i = e.getBoundingClientRect();
2653
+ if (!i.width && !i.height) {
2654
+ this.clearSelToolbar();
2655
+ return;
2656
+ }
2657
+ this.selCtx || (this.selCtx = this.buildSelToolbar()), this.positionSelToolbar(e);
2658
+ }
2659
+ buildSelToolbar() {
2660
+ var o;
2661
+ const t = document.createElement("div");
2662
+ t.className = "selctx", t.dir = this.dir();
2663
+ const e = this.ctxBtn(
2664
+ '<b style="font:600 15px/1 Georgia,serif">A</b><span class="colorbar" data-cb="fore"></span>',
2665
+ this.t("forecolor"),
2666
+ () => this.colorMenu(e, "fore")
2667
+ ), i = this.ctxBtn(a.backcolor, this.t("backcolor"), () => this.colorMenu(i, "back"));
2668
+ (o = i.querySelector("svg")) == null || o.insertAdjacentHTML("afterend", '<span class="colorbar" data-cb="back"></span>');
2669
+ const s = this.ctxBtn(a.caseic, this.t("changecase"), () => this.caseMenu(s)), l = this.ctxBtn(a.lineheight, this.t("lineheight"), () => this.lineHeightMenu(l)), n = this.ctxBtn(a.wordspacing, this.t("wordspacing"), () => this.wordSpacingMenu(n));
2670
+ return t.append(
2671
+ this.ctxBtn(a.bold, this.t("bold"), () => this.exec("bold"), "bold"),
2672
+ this.ctxBtn(a.italic, this.t("italic"), () => this.exec("italic"), "italic"),
2673
+ e,
2674
+ i,
2675
+ this.ctxSep(),
2676
+ this.ctxBtn(a.quote, this.t("quote"), () => this.toggleBlock("blockquote"), "blockquote"),
2677
+ this.ctxBtn('<b style="font:700 12px/1 Arial,sans-serif">H2</b>', this.blockLabel("h2"), () => this.toggleBlock("h2"), "h2"),
2678
+ this.ctxBtn('<b style="font:700 12px/1 Arial,sans-serif">H3</b>', this.blockLabel("h3"), () => this.toggleBlock("h3"), "h3"),
2679
+ this.ctxSep(),
2680
+ this.ctxBtn(a.link, this.t("linkttl"), () => this.linkDlg()),
2681
+ s,
2682
+ l,
2683
+ n
2684
+ ), t.addEventListener("mousedown", (r) => r.preventDefault()), document.body.appendChild(t), this.syncColorSwatches(t), t;
2685
+ }
2686
+ positionSelToolbar(t) {
2687
+ if (!this.selCtx) return;
2688
+ const e = t.getBoundingClientRect(), i = e.top + scrollY, s = e.left + scrollX, l = e.right + scrollX, n = e.bottom + scrollY, o = this.selCtx.offsetWidth, r = this.selCtx.offsetHeight;
2689
+ let c = s + (l - s) / 2 - o / 2;
2690
+ c = Math.max(8 + scrollX, Math.min(c, scrollX + innerWidth - o - 8));
2691
+ let h = i - r - 8;
2692
+ h < this.ctxMinTop() && (h = n + 8), this.selCtx.style.left = c + "px", this.selCtx.style.top = h + "px";
2693
+ }
2694
+ repositionSelToolbar() {
2695
+ if (!this.selCtx) return;
2696
+ const t = window.getSelection();
2697
+ t && t.rangeCount && !t.isCollapsed && this.ed.contains(t.anchorNode) && this.positionSelToolbar(t.getRangeAt(0));
2698
+ }
2699
+ /* ---------------------------------------------------------- state sync */
2700
+ currentBlock() {
2701
+ const t = window.getSelection();
2702
+ if (!t || !t.anchorNode || !this.ed.contains(t.anchorNode)) return "p";
2703
+ const e = this.closestBlock(t.anchorNode);
2704
+ return e ? e.tagName.toLowerCase().replace("div", "p") : "p";
2705
+ }
2706
+ /** Element whose computed font reflects the current caret, falling back to the editor root before any selection lands inside it. */
2707
+ fontRefEl() {
2708
+ const t = window.getSelection();
2709
+ return t && t.anchorNode && this.ed.contains(t.anchorNode) ? t.anchorNode.nodeType === 1 ? t.anchorNode : t.anchorNode.parentElement : this.ed;
2710
+ }
2711
+ currentFont() {
2712
+ const t = getComputedStyle(this.fontRefEl()).fontFamily.toLowerCase(), e = this.options.fontFamilyFormats.find(([i, s]) => t.includes(s.split(",")[0].toLowerCase()));
2713
+ return e ? e[0] : "";
2714
+ }
2715
+ currentSize() {
2716
+ const t = Math.round(parseFloat(getComputedStyle(this.fontRefEl()).fontSize));
2717
+ return t > 0 ? t + "px" : "";
2718
+ }
2719
+ refreshState() {
2720
+ var r, c, h;
2721
+ const t = window.getSelection(), e = t ? this.ed.contains(t.anchorNode) : !1, i = this.currentBlock();
2722
+ [this.toolbar, this.selCtx].filter(Boolean).forEach((d) => {
2723
+ [
2724
+ "bold",
2725
+ "italic",
2726
+ "underline",
2727
+ "strikeThrough",
2728
+ "justifyLeft",
2729
+ "justifyCenter",
2730
+ "justifyRight",
2731
+ "justifyFull",
2732
+ "insertOrderedList",
2733
+ "insertUnorderedList"
2734
+ ].forEach((m) => {
2735
+ const g = d.querySelector(`[data-id=${m}]`);
2736
+ g && g.classList.toggle("on", e && document.queryCommandState(m));
2737
+ }), ["h2", "h3", "blockquote"].forEach((m) => {
2738
+ const g = d.querySelector(`[data-id=${m}]`);
2739
+ g && g.classList.toggle("on", e && i === m);
2740
+ });
2741
+ });
2742
+ const l = t ? this.closestBlock(t.anchorNode) : null, n = ((r = l == null ? void 0 : l.closest("[dir]")) == null ? void 0 : r.getAttribute("dir")) || this.ed.getAttribute("dir") || this.dir();
2743
+ (c = this.toolbar.querySelector("[data-id=ltr]")) == null || c.classList.toggle("on", e && n === "ltr"), (h = this.toolbar.querySelector("[data-id=rtl]")) == null || h.classList.toggle("on", e && n === "rtl");
2744
+ const o = (d, m, g) => {
2745
+ const f = this.toolbar.querySelector(`[data-id=${d}] .lbl`);
2746
+ f && (f.textContent = m || g || "", f.classList.toggle("empty", !m));
2747
+ };
2748
+ o("fontsel", this.currentFont()), o("sizesel", this.currentSize().replace("px", "")), e && o("blocksel", D.some((d) => d[0] === i) ? this.blockLabel(i) : this.t("para")), this.sbWords.textContent = this.countWords() + " " + this.t("words");
2749
+ }
2750
+ countWords() {
2751
+ const t = (this.ed.textContent || "").trim();
2752
+ return t ? t.split(/\s+/).length : 0;
2753
+ }
2754
+ /* ---------------------------------------------------------- paste */
2755
+ handlePaste(t) {
2756
+ const e = t.clipboardData;
2757
+ if (!e) return;
2758
+ t.preventDefault();
2759
+ const i = e.getData("text/html"), s = Array.from(e.items).find((l) => l.type.startsWith("image/"));
2760
+ if (s && !i) {
2761
+ const l = new FileReader();
2762
+ l.onload = () => {
2763
+ document.execCommand("insertHTML", !1, `<img src="${l.result}" alt="">`), this.onChange();
2764
+ }, l.readAsDataURL(s.getAsFile());
2765
+ return;
2766
+ }
2767
+ i ? document.execCommand("insertHTML", !1, dt(i, this.dir())) : document.execCommand("insertHTML", !1, pt(e.getData("text/plain"))), this.onChange();
2768
+ }
2769
+ /* ---------------------------------------------------------- init */
2770
+ initUI() {
2771
+ this.closePop(), this.closeDlg(), this.clearTableHandles(), this.clearImgPlaceholderSel(), this.shell.dir = this.dir(), this.ed.dir = this.dir(), this.options.menubar ? this.buildMenubar() : this.menubar.style.display = "none", this.options.toolbar ? this.buildToolbar() : this.toolbar.style.display = "none", this.sbHelp.textContent = this.t("statushelp"), this.refreshState();
2772
+ }
2773
+ };
2774
+ A.instanceCounter = 0;
2775
+ let $ = A;
2776
+ export {
2777
+ D as BLOCKS,
2778
+ tt as CHARS,
2779
+ J as COLORS,
2780
+ X as FONTS,
2781
+ $ as FableEditor,
2782
+ W as I18N,
2783
+ a as IC,
2784
+ _ as SIZES,
2785
+ yt as TXT,
2786
+ dt as cleanPastedHTML,
2787
+ B as getStrings,
2788
+ pt as normalizeTextPaste
2789
+ };