autumnnote 1.6.0 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +4 -4
  2. package/dist/autumnnote.css +0 -2
  3. package/dist/autumnnote.es.js +468 -552
  4. package/dist/autumnnote.es.js.map +1 -1
  5. package/dist/autumnnote.umd.js +461 -546
  6. package/dist/autumnnote.umd.js.map +1 -1
  7. package/package.json +21 -3
  8. package/src/js/Context.js +21 -16
  9. package/src/js/core/dom.js +9 -9
  10. package/src/js/core/env.js +1 -1
  11. package/src/js/core/func.js +1 -1
  12. package/src/js/core/lists.js +1 -1
  13. package/src/js/core/markdown.js +18 -18
  14. package/src/js/core/range.js +6 -6
  15. package/src/js/editing/History.js +4 -4
  16. package/src/js/editing/Style.js +32 -32
  17. package/src/js/editing/Table.js +2 -2
  18. package/src/js/editing/Typing.js +15 -15
  19. package/src/js/index.js +1 -1
  20. package/src/js/module/AutoSaveRestore.js +2 -4
  21. package/src/js/module/BaseDialog.js +126 -0
  22. package/src/js/module/BubbleToolbar.js +25 -25
  23. package/src/js/module/Buttons.js +4 -4
  24. package/src/js/module/Clipboard.js +12 -13
  25. package/src/js/module/CodeTooltip.js +14 -16
  26. package/src/js/module/Codeview.js +3 -5
  27. package/src/js/module/ContextMenu.js +27 -27
  28. package/src/js/module/Editor.js +17 -18
  29. package/src/js/module/EmojiDialog.js +5 -5
  30. package/src/js/module/FindReplace.js +8 -7
  31. package/src/js/module/IconDialog.js +13 -15
  32. package/src/js/module/ImageCropOverlay.js +7 -7
  33. package/src/js/module/ImageDialog.js +12 -82
  34. package/src/js/module/ImageResizer.js +4 -4
  35. package/src/js/module/ImageTooltip.js +14 -14
  36. package/src/js/module/LinkDialog.js +13 -79
  37. package/src/js/module/LinkTooltip.js +12 -12
  38. package/src/js/module/MarkdownShortcuts.js +11 -14
  39. package/src/js/module/Mention.js +8 -10
  40. package/src/js/module/Placeholder.js +1 -1
  41. package/src/js/module/ShortcutsDialog.js +2 -4
  42. package/src/js/module/Statusbar.js +3 -5
  43. package/src/js/module/TableTooltip.js +30 -32
  44. package/src/js/module/Toolbar.js +21 -21
  45. package/src/js/module/VideoDialog.js +17 -87
  46. package/src/js/module/VideoResizer.js +5 -7
  47. package/src/js/module/VideoTooltip.js +7 -7
  48. package/src/js/renderer.js +1 -1
  49. package/src/styles/autumnnote.scss +0 -3
@@ -114,14 +114,14 @@
114
114
  const handler = (e) => {
115
115
  if (e.key === "Escape") {
116
116
  e.stopPropagation();
117
- onEscape && onEscape();
117
+ onEscape?.();
118
118
  return;
119
119
  }
120
120
  if (e.key !== "Tab") return;
121
121
  const els = getFocusable();
122
122
  if (!els.length) return;
123
123
  const first = els[0];
124
- const last = els[els.length - 1];
124
+ const last = els.at(-1);
125
125
  if (e.shiftKey) {
126
126
  if (document.activeElement === first) {
127
127
  e.preventDefault();
@@ -159,14 +159,14 @@
159
159
  box.style.top = `${r.top}px`;
160
160
  box.dataset.anDragPinned = "1";
161
161
  }
162
- const startX = e.clientX - parseFloat(box.style.left);
163
- const startY = e.clientY - parseFloat(box.style.top);
162
+ const startX = e.clientX - Number.parseFloat(box.style.left);
163
+ const startY = e.clientY - Number.parseFloat(box.style.top);
164
164
  handle.style.cursor = "grabbing";
165
165
  const onMove = (ev) => {
166
166
  const bw = box.offsetWidth;
167
167
  const bh = box.offsetHeight;
168
- box.style.left = `${Math.max(0, Math.min(ev.clientX - startX, window.innerWidth - bw))}px`;
169
- box.style.top = `${Math.max(0, Math.min(ev.clientY - startY, window.innerHeight - bh))}px`;
168
+ box.style.left = `${Math.max(0, Math.min(ev.clientX - startX, globalThis.innerWidth - bw))}px`;
169
+ box.style.top = `${Math.max(0, Math.min(ev.clientY - startY, globalThis.innerHeight - bh))}px`;
170
170
  };
171
171
  const onUp = () => {
172
172
  handle.style.cursor = "grab";
@@ -212,10 +212,10 @@
212
212
  return range;
213
213
  }
214
214
  /**
215
- * Select this wrapped range in the window.
215
+ * Select this wrapped range in the globalThis.
216
216
  */
217
217
  select() {
218
- const sel = window.getSelection();
218
+ const sel = globalThis.getSelection();
219
219
  if (!sel) return;
220
220
  sel.removeAllRanges();
221
221
  sel.addRange(this.toNativeRange());
@@ -268,13 +268,13 @@
268
268
  return new WrappedRange(range.startContainer, range.startOffset, range.endContainer, range.endOffset);
269
269
  }
270
270
  /**
271
- * Returns a WrappedRange for the current window selection,
271
+ * Returns a WrappedRange for the current globalThis selection,
272
272
  * optionally restricted to a given editable element.
273
273
  * @param {HTMLElement} [editable]
274
274
  * @returns {WrappedRange|null}
275
275
  */
276
276
  function currentRange(editable) {
277
- const sel = window.getSelection();
277
+ const sel = globalThis.getSelection();
278
278
  if (!sel || sel.rangeCount === 0) return null;
279
279
  const native = sel.getRangeAt(0);
280
280
  if (editable && !editable.contains(native.commonAncestorContainer)) return null;
@@ -285,7 +285,7 @@
285
285
  * @param {Function} fn
286
286
  */
287
287
  function withSavedRange(fn) {
288
- const sel = window.getSelection();
288
+ const sel = globalThis.getSelection();
289
289
  if (!sel || sel.rangeCount === 0) {
290
290
  fn(null);
291
291
  return;
@@ -320,16 +320,16 @@
320
320
  * execCommand's state detection is unreliable.
321
321
  */
322
322
  function underline() {
323
- const sel = window.getSelection();
323
+ const sel = globalThis.getSelection();
324
324
  if (!sel || !sel.rangeCount) return;
325
325
  let container = sel.getRangeAt(0).commonAncestorContainer;
326
326
  if (container.nodeType === 3) container = container.parentElement;
327
- const uEl = container && container.closest("u");
327
+ const uEl = container?.closest("u");
328
328
  const nativeState = document.queryCommandState("underline");
329
329
  if (uEl && !nativeState) {
330
330
  const parent = uEl.parentNode;
331
331
  while (uEl.firstChild) parent.insertBefore(uEl.firstChild, uEl);
332
- parent.removeChild(uEl);
332
+ uEl.remove();
333
333
  return;
334
334
  }
335
335
  execCommand("underline");
@@ -340,16 +340,16 @@
340
340
  * execCommand's state detection is unreliable (mirrors underline() logic).
341
341
  */
342
342
  function strikethrough() {
343
- const sel = window.getSelection();
343
+ const sel = globalThis.getSelection();
344
344
  if (!sel || !sel.rangeCount) return;
345
345
  let sc = sel.getRangeAt(0).startContainer;
346
346
  if (sc.nodeType === 3) sc = sc.parentElement;
347
- const sEl = sc && (sc.closest("s") || sc.closest("strike"));
347
+ const sEl = sc?.closest("s") || sc?.closest("strike");
348
348
  const nativeState = document.queryCommandState("strikeThrough");
349
349
  if (sEl && !nativeState) {
350
350
  const parent = sEl.parentNode;
351
351
  while (sEl.firstChild) parent.insertBefore(sEl.firstChild, sEl);
352
- parent.removeChild(sEl);
352
+ sEl.remove();
353
353
  return;
354
354
  }
355
355
  execCommand("strikeThrough");
@@ -384,7 +384,7 @@
384
384
  * @param {HTMLElement|Document} [editable] - scoping element to avoid touching nodes outside this editor
385
385
  */
386
386
  function fontSize(size, editable = document) {
387
- const sel = window.getSelection();
387
+ const sel = globalThis.getSelection();
388
388
  const wasCollapsed = !sel || !sel.rangeCount || sel.getRangeAt(0).collapsed;
389
389
  if (wasCollapsed && sel && sel.rangeCount > 0) {
390
390
  try {
@@ -410,12 +410,12 @@
410
410
  span.style.fontSize = size;
411
411
  el.parentNode.insertBefore(span, el);
412
412
  while (el.firstChild) span.appendChild(el.firstChild);
413
- el.parentNode.removeChild(el);
413
+ el.remove();
414
414
  newSpans.push(span);
415
415
  });
416
416
  if (!wasCollapsed && sel && newSpans.length > 0) {
417
417
  const first = newSpans[0];
418
- const last = newSpans[newSpans.length - 1];
418
+ const last = newSpans.at(-1);
419
419
  try {
420
420
  const nr = document.createRange();
421
421
  const startNode = first.firstChild || first;
@@ -459,11 +459,11 @@
459
459
  * (which would destroy the ul > li checklist structure).
460
460
  */
461
461
  function outdent() {
462
- const sel = window.getSelection();
462
+ const sel = globalThis.getSelection();
463
463
  if (sel && sel.rangeCount) {
464
464
  let container = sel.getRangeAt(0).commonAncestorContainer;
465
465
  if (container.nodeType === 3) container = container.parentElement;
466
- const checkLi = container && container.closest(".an-checklist li");
466
+ const checkLi = container?.closest(".an-checklist li");
467
467
  if (checkLi) {
468
468
  _checklistItemToP(checkLi);
469
469
  return;
@@ -493,7 +493,7 @@
493
493
  if (child.nodeType === 1 && child.tagName === "INPUT") continue;
494
494
  p.appendChild(child.cloneNode(true));
495
495
  }
496
- p.innerHTML = p.innerHTML.replace(/\u200B/g, "");
496
+ p.innerHTML = p.innerHTML.replaceAll("​", "");
497
497
  if (!p.hasChildNodes() || !p.textContent.trim()) {
498
498
  p.innerHTML = "";
499
499
  p.appendChild(document.createTextNode("\xA0"));
@@ -505,14 +505,14 @@
505
505
  checkUl.parentNode.insertBefore(newUl, checkUl.nextSibling);
506
506
  }
507
507
  checkUl.parentNode.insertBefore(p, checkUl.nextSibling);
508
- checkUl.removeChild(checkLi);
509
- if (checkUl.children.length === 0) checkUl.parentNode.removeChild(checkUl);
508
+ checkLi.remove();
509
+ if (checkUl.children.length === 0) checkUl.remove();
510
510
  try {
511
511
  const nr = document.createRange();
512
512
  const firstChild = p.firstChild;
513
513
  nr.setStart(firstChild && firstChild.nodeType === 3 ? firstChild : p, 0);
514
514
  nr.collapse(true);
515
- const s = window.getSelection();
515
+ const s = globalThis.getSelection();
516
516
  if (s) {
517
517
  s.removeAllRanges();
518
518
  s.addRange(nr);
@@ -536,7 +536,7 @@
536
536
  * @param {string} value - Line-height value to apply; typically a unitless multiplier (for example, "1.5").
537
537
  */
538
538
  function lineHeight(value) {
539
- const sel = window.getSelection();
539
+ const sel = globalThis.getSelection();
540
540
  if (!sel || sel.rangeCount === 0) return;
541
541
  const range = sel.getRangeAt(0);
542
542
  const BLOCK_TAGS = new Set([
@@ -588,22 +588,22 @@
588
588
  * @param {HTMLElement} [_editable]
589
589
  */
590
590
  function toggleInlineCode(_editable) {
591
- const sel = window.getSelection();
591
+ const sel = globalThis.getSelection();
592
592
  if (!sel || !sel.rangeCount) return;
593
593
  const range = sel.getRangeAt(0);
594
594
  let container = range.commonAncestorContainer;
595
595
  if (container.nodeType === 3) container = container.parentElement;
596
- const codeEl = container && container.closest("code");
596
+ const codeEl = container?.closest("code");
597
597
  if (codeEl && !codeEl.closest("pre")) {
598
598
  const parent = codeEl.parentNode;
599
599
  const prevSibling = codeEl.previousSibling;
600
600
  const movedChildren = Array.from(codeEl.childNodes);
601
601
  while (codeEl.firstChild) parent.insertBefore(codeEl.firstChild, codeEl);
602
- parent.removeChild(codeEl);
603
- if (parent && parent.normalize) parent.normalize();
602
+ codeEl.remove();
603
+ parent?.normalize();
604
604
  if (movedChildren.length > 0) try {
605
605
  const firstMoved = movedChildren[0];
606
- const lastMoved = movedChildren[movedChildren.length - 1];
606
+ const lastMoved = movedChildren.at(-1);
607
607
  const nr = document.createRange();
608
608
  const anchorNode = firstMoved.parentNode === parent ? firstMoved : prevSibling ? prevSibling.nextSibling : parent.firstChild;
609
609
  if (anchorNode) {
@@ -644,11 +644,11 @@
644
644
  * @returns {boolean}
645
645
  */
646
646
  function isInlineCode() {
647
- const sel = window.getSelection();
647
+ const sel = globalThis.getSelection();
648
648
  if (!sel || !sel.rangeCount) return false;
649
649
  let sc = sel.getRangeAt(0).startContainer;
650
650
  if (sc.nodeType === 3) sc = sc.parentElement;
651
- const code = sc && sc.closest("code");
651
+ const code = sc?.closest("code");
652
652
  return !!(code && !code.closest("pre"));
653
653
  }
654
654
  /**
@@ -666,12 +666,12 @@
666
666
  * Empty or whitespace-only selections do not create a checklist.
667
667
  */
668
668
  function toggleChecklist() {
669
- const sel = window.getSelection();
669
+ const sel = globalThis.getSelection();
670
670
  if (!sel || !sel.rangeCount) return;
671
671
  const range = sel.getRangeAt(0);
672
672
  let container = range.commonAncestorContainer;
673
673
  if (container.nodeType === 3) container = container.parentElement;
674
- const ul = container && container.closest(".an-checklist");
674
+ const ul = container?.closest(".an-checklist");
675
675
  if (ul) {
676
676
  const selectedLis = Array.from(ul.querySelectorAll("li")).filter((li) => sel.containsNode(li, true));
677
677
  if (selectedLis.length > 0) {
@@ -682,14 +682,14 @@
682
682
  if (child.nodeType === 1 && child.tagName === "INPUT") continue;
683
683
  p.appendChild(child.cloneNode(true));
684
684
  }
685
- p.innerHTML = p.innerHTML.replace(/\u200b/g, "");
685
+ p.innerHTML = p.innerHTML.replaceAll("​", "");
686
686
  if (!p.hasChildNodes() || !p.textContent.trim()) {
687
687
  p.innerHTML = "";
688
688
  p.appendChild(document.createTextNode("\xA0"));
689
689
  }
690
690
  ul.parentNode.insertBefore(p, ul);
691
691
  if (!firstP) firstP = p;
692
- ul.removeChild(li);
692
+ li.remove();
693
693
  });
694
694
  if (ul.children.length === 0) ul.remove();
695
695
  if (firstP) {
@@ -717,7 +717,7 @@
717
717
  ]);
718
718
  let block = container;
719
719
  while (block && block.parentNode && !BLOCK_TAGS.has(block.tagName)) block = block.parentNode;
720
- const itemText = block && BLOCK_TAGS.has(block.tagName) ? Array.from(block.childNodes).map((n) => n.textContent).join("").replace(/\u00a0/g, " ") : "";
720
+ const itemText = block && BLOCK_TAGS.has(block.tagName) ? Array.from(block.childNodes).map((n) => n.textContent).join("").replaceAll("\xA0", " ") : "";
721
721
  const ul = document.createElement("ul");
722
722
  ul.className = "an-checklist";
723
723
  const li = document.createElement("li");
@@ -788,7 +788,7 @@
788
788
  });
789
789
  const firstBlock = blocks[0];
790
790
  firstBlock.parentNode.insertBefore(newUl, firstBlock);
791
- blocks.forEach((block) => block.parentNode && block.parentNode.removeChild(block));
791
+ blocks.forEach((block) => block.remove());
792
792
  if (lastTextNode) {
793
793
  const nr = document.createRange();
794
794
  nr.setStart(lastTextNode, lastTextNode.textContent.length);
@@ -802,11 +802,11 @@
802
802
  * @returns {boolean}
803
803
  */
804
804
  function isInChecklist() {
805
- const sel = window.getSelection();
805
+ const sel = globalThis.getSelection();
806
806
  if (!sel || !sel.rangeCount) return false;
807
807
  let container = sel.getRangeAt(0).commonAncestorContainer;
808
808
  if (container.nodeType === 3) container = container.parentElement;
809
- return !!(container && container.closest(".an-checklist li"));
809
+ return !!container?.closest(".an-checklist li");
810
810
  }
811
811
  //#endregion
812
812
  //#region src/js/module/Buttons.js
@@ -888,7 +888,7 @@
888
888
  var italicBtn = btn("italic", "italic", "Italic (Ctrl+I)", () => italic(), () => document.queryCommandState("italic"));
889
889
  var underlineBtn = btn("underline", "underline", "Underline (Ctrl+U)", () => underline(), () => {
890
890
  if (document.queryCommandState("underline")) return true;
891
- const sel = window.getSelection();
891
+ const sel = globalThis.getSelection();
892
892
  if (!sel || !sel.rangeCount) return false;
893
893
  let sc = sel.getRangeAt(0).startContainer;
894
894
  if (sc.nodeType === 3) sc = sc.parentElement;
@@ -951,7 +951,7 @@
951
951
  action: (ctx, value) => fontSize(value, ctx.layoutInfo.editable),
952
952
  getValue: (ctx) => {
953
953
  try {
954
- const sel = window.getSelection();
954
+ const sel = globalThis.getSelection();
955
955
  if (sel && sel.rangeCount) {
956
956
  let el = sel.getRangeAt(0).startContainer;
957
957
  if (el && el.nodeType === 3) el = el.parentElement;
@@ -959,7 +959,7 @@
959
959
  const size = el && el.style.fontSize ? el.style.fontSize : "";
960
960
  if (size) return size;
961
961
  }
962
- const editable = ctx && ctx.layoutInfo && ctx.layoutInfo.editable;
962
+ const editable = ctx?.layoutInfo?.editable;
963
963
  if (editable) return editable.style.fontSize || "";
964
964
  return "";
965
965
  } catch {
@@ -1056,7 +1056,7 @@
1056
1056
  action: (_ctx, value) => lineHeight(value),
1057
1057
  getValue: () => {
1058
1058
  try {
1059
- const sel = window.getSelection();
1059
+ const sel = globalThis.getSelection();
1060
1060
  if (!sel || !sel.rangeCount) return "";
1061
1061
  const BLOCKS = new Set([
1062
1062
  "P",
@@ -4171,7 +4171,7 @@
4171
4171
  } catch (_) {}
4172
4172
  if (!initialContent) initialContent = targetEl.tagName === "TEXTAREA" ? (targetEl.value || "").trim() : (targetEl.innerHTML || "").trim();
4173
4173
  editable.innerHTML = sanitiseHTML(initialContent, { allowIframes: true });
4174
- const defaultFont = options.defaultFontFamily || options.fontFamilies && options.fontFamilies[0];
4174
+ const defaultFont = options.defaultFontFamily || options.fontFamilies?.[0];
4175
4175
  if (defaultFont) editable.style.fontFamily = defaultFont;
4176
4176
  if (options.defaultFontSize) editable.style.fontSize = options.defaultFontSize;
4177
4177
  if (options.height) editable.style.minHeight = `${options.height}px`;
@@ -4233,7 +4233,7 @@
4233
4233
  * @returns {{ start: number, end: number }|null}
4234
4234
  */
4235
4235
  _serializeSelection() {
4236
- const sel = window.getSelection();
4236
+ const sel = globalThis.getSelection();
4237
4237
  if (!sel || sel.rangeCount === 0) return null;
4238
4238
  const range = sel.getRangeAt(0);
4239
4239
  if (!this.editable.contains(range.startContainer)) return null;
@@ -4299,7 +4299,7 @@
4299
4299
  const range = document.createRange();
4300
4300
  range.setStart(startNode, startOff);
4301
4301
  range.setEnd(endNode, endOff);
4302
- const sel = window.getSelection();
4302
+ const sel = globalThis.getSelection();
4303
4303
  sel.removeAllRanges();
4304
4304
  sel.addRange(range);
4305
4305
  } catch (_) {
@@ -4307,7 +4307,7 @@
4307
4307
  const fb = document.createRange();
4308
4308
  fb.setStart(this.editable, 0);
4309
4309
  fb.collapse(true);
4310
- const s = window.getSelection();
4310
+ const s = globalThis.getSelection();
4311
4311
  if (s) {
4312
4312
  s.removeAllRanges();
4313
4313
  s.addRange(fb);
@@ -4371,8 +4371,7 @@
4371
4371
  recordUndo() {
4372
4372
  const current = this._serialize();
4373
4373
  const { html: tokenized } = this._tokenizeImages(current);
4374
- const prev = this.stack[this.stackOffset];
4375
- if (prev && prev.html === tokenized) return;
4374
+ if (this.stack[this.stackOffset]?.html === tokenized) return;
4376
4375
  this._savePoint();
4377
4376
  }
4378
4377
  /**
@@ -4456,7 +4455,7 @@
4456
4455
  function insertTable(cols, rows, opts = {}) {
4457
4456
  if (cols <= 0 || rows <= 0) return;
4458
4457
  const table = createTable(cols, rows, opts);
4459
- const sel = window.getSelection();
4458
+ const sel = globalThis.getSelection();
4460
4459
  if (!sel || sel.rangeCount === 0) return;
4461
4460
  const range = sel.getRangeAt(0);
4462
4461
  range.deleteContents();
@@ -4474,7 +4473,7 @@
4474
4473
  "PRE"
4475
4474
  ]);
4476
4475
  let anchor = range.startContainer;
4477
- if (anchor && anchor.nodeType === 3) anchor = anchor.parentElement;
4476
+ if (anchor?.nodeType === 3) anchor = anchor.parentElement;
4478
4477
  while (anchor && !BLOCK.has(anchor.tagName?.toUpperCase()) && anchor.parentElement) anchor = anchor.parentElement;
4479
4478
  if (anchor && BLOCK.has(anchor.tagName?.toUpperCase()) && anchor.parentNode) {
4480
4479
  anchor.after(table);
@@ -4564,8 +4563,8 @@
4564
4563
  * Inspired by Summernote's Typing module
4565
4564
  */
4566
4565
  var _FA_PATTERN = /\bfa-/;
4567
- var isFAIcon = (n) => !!(n && n.nodeName === "I" && _FA_PATTERN.test(n.className || ""));
4568
- var isZwsAnchor = (n) => !!(n && n.nodeType === Node.TEXT_NODE && (n.textContent === "​" || n.textContent === ""));
4566
+ var isFAIcon = (n) => !!(n?.nodeName === "I" && _FA_PATTERN.test(n.className || ""));
4567
+ var isZwsAnchor = (n) => !!(n?.nodeType === Node.TEXT_NODE && (n.textContent === "​" || n.textContent === ""));
4569
4568
  /**
4570
4569
  * Handles special keydown behaviour inside the editor.
4571
4570
  * @param {KeyboardEvent} event
@@ -4575,7 +4574,7 @@
4575
4574
  */
4576
4575
  function handleKeydown(event, editable, options = {}) {
4577
4576
  const moveCaret = (setFn) => {
4578
- const sel = window.getSelection();
4577
+ const sel = globalThis.getSelection();
4579
4578
  if (!sel) return false;
4580
4579
  const nr = document.createRange();
4581
4580
  setFn(nr);
@@ -4585,8 +4584,8 @@
4585
4584
  return true;
4586
4585
  };
4587
4586
  if (isKey(event, key.BACKSPACE)) {
4588
- const sel = window.getSelection();
4589
- if (sel && sel.rangeCount > 0) {
4587
+ const sel = globalThis.getSelection();
4588
+ if (sel?.rangeCount > 0) {
4590
4589
  const r = sel.getRangeAt(0);
4591
4590
  if (r.collapsed && r.startContainer.nodeType === Node.TEXT_NODE) {
4592
4591
  const textNode = r.startContainer;
@@ -4616,7 +4615,7 @@
4616
4615
  return false;
4617
4616
  }
4618
4617
  if (isKey(event, key.LEFT) || isKey(event, key.RIGHT)) {
4619
- const sel = window.getSelection();
4618
+ const sel = globalThis.getSelection();
4620
4619
  if (!sel || sel.rangeCount === 0) return false;
4621
4620
  const r = sel.getRangeAt(0);
4622
4621
  if (!r.collapsed) return false;
@@ -4704,7 +4703,7 @@
4704
4703
  else execCommand("indent");
4705
4704
  return true;
4706
4705
  }
4707
- if (para && para.nodeName.toUpperCase() === "PRE") {
4706
+ if (para?.nodeName.toUpperCase() === "PRE") {
4708
4707
  if (event.shiftKey) return false;
4709
4708
  event.preventDefault();
4710
4709
  execCommand("insertText", " ".repeat(options.tabSize || 4));
@@ -4727,18 +4726,18 @@
4727
4726
  if (!range) return false;
4728
4727
  const sc = range.sc;
4729
4728
  const el = sc.nodeType === 3 ? sc.parentElement : sc;
4730
- if (el && el.nodeName === "I" && /\bfa-/.test(el.className || "")) {
4729
+ if (el?.nodeName === "I" && /\bfa-/.test(el.className || "")) {
4731
4730
  const nr = document.createRange();
4732
4731
  nr.setStartAfter(el);
4733
4732
  nr.collapse(true);
4734
- const selI = window.getSelection();
4733
+ const selI = globalThis.getSelection();
4735
4734
  if (selI) {
4736
4735
  selI.removeAllRanges();
4737
4736
  selI.addRange(nr);
4738
4737
  }
4739
4738
  return false;
4740
4739
  }
4741
- const videoWrapper = el && el.closest(".an-video-wrapper");
4740
+ const videoWrapper = el?.closest(".an-video-wrapper");
4742
4741
  if (videoWrapper) {
4743
4742
  event.preventDefault();
4744
4743
  const p = document.createElement("p");
@@ -4747,16 +4746,16 @@
4747
4746
  const nr = document.createRange();
4748
4747
  nr.setStart(p, 0);
4749
4748
  nr.collapse(true);
4750
- const sel = window.getSelection();
4749
+ const sel = globalThis.getSelection();
4751
4750
  sel.removeAllRanges();
4752
4751
  sel.addRange(nr);
4753
4752
  return true;
4754
4753
  }
4755
- const checkLi = el && el.closest(".an-checklist li");
4754
+ const checkLi = el?.closest(".an-checklist li");
4756
4755
  if (checkLi) {
4757
4756
  event.preventDefault();
4758
4757
  const ul = checkLi.closest(".an-checklist");
4759
- const sel = window.getSelection();
4758
+ const sel = globalThis.getSelection();
4760
4759
  let nativeRange = sel.getRangeAt(0);
4761
4760
  const liText = (li) => Array.from(li.childNodes).filter((n) => !(n.nodeType === 1 && n.tagName === "INPUT")).map((n) => n.textContent).join("").replace(/[\u00a0\u200B]/g, " ").trim();
4762
4761
  if (!liText(checkLi)) {
@@ -4800,12 +4799,12 @@
4800
4799
  return true;
4801
4800
  }
4802
4801
  const para = closestPara(range.sc, editable);
4803
- if (para && para.nodeName.toUpperCase() === "PRE") {
4802
+ if (para?.nodeName.toUpperCase() === "PRE") {
4804
4803
  event.preventDefault();
4805
4804
  execCommand("insertText", "\n");
4806
4805
  return true;
4807
4806
  }
4808
- if (para && para.nodeName.toUpperCase() === "BLOCKQUOTE") {
4807
+ if (para?.nodeName.toUpperCase() === "BLOCKQUOTE") {
4809
4808
  const native = range.toNativeRange();
4810
4809
  native.setEnd(para, para.childNodes.length);
4811
4810
  if (native.toString() === "" && range.isCollapsed()) {
@@ -4879,7 +4878,7 @@
4879
4878
  return `\`${inner()}\``;
4880
4879
  case "pre": {
4881
4880
  const codeEl = el.querySelector("code");
4882
- const langMatch = (codeEl && codeEl.className || "").match(/language-(\S+)/);
4881
+ const langMatch = /language-(\S+)/.exec(codeEl && codeEl.className || "");
4883
4882
  return `\n\n\`\`\`${langMatch ? langMatch[1] : ""}\n${(codeEl || el).textContent || ""}\n\`\`\`\n\n`;
4884
4883
  }
4885
4884
  case "blockquote": return `\n\n${inner().trim().split("\n").map((l) => `> ${l}`).join("\n")}\n\n`;
@@ -4910,7 +4909,7 @@
4910
4909
  case "table": {
4911
4910
  const rows = Array.from(el.querySelectorAll("tr"));
4912
4911
  if (!rows.length) return inner();
4913
- const cellTexts = rows.map((tr) => Array.from(tr.querySelectorAll("th, td")).map((c) => c.textContent.trim().replace(/\|/g, "\\|")));
4912
+ const cellTexts = rows.map((tr) => Array.from(tr.querySelectorAll("th, td")).map((c) => c.textContent.trim().replaceAll("|", "\\|")));
4914
4913
  const cols = Math.max(...cellTexts.map((r) => r.length));
4915
4914
  const padRow = (row) => {
4916
4915
  const r = [...row];
@@ -4919,7 +4918,7 @@
4919
4918
  };
4920
4919
  let md = "\n\n";
4921
4920
  md += `| ${padRow(cellTexts[0]).join(" | ")} |\n`;
4922
- md += `| ${Array(cols).fill("---").join(" | ")} |\n`;
4921
+ md += `| ${new Array(cols).fill("---").join(" | ")} |\n`;
4923
4922
  for (let r = 1; r < cellTexts.length; r++) md += `| ${padRow(cellTexts[r]).join(" | ")} |\n`;
4924
4923
  return md + "\n";
4925
4924
  }
@@ -4943,12 +4942,12 @@
4943
4942
  * @returns {string}
4944
4943
  */
4945
4944
  function markdownToHTML(text) {
4946
- const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
4945
+ const lines = text.replaceAll("\r\n", "\n").replaceAll("\r", "\n").split("\n");
4947
4946
  const out = [];
4948
4947
  let i = 0;
4949
4948
  while (i < lines.length) {
4950
4949
  const line = lines[i];
4951
- const fenceMatch = line.match(/^```(\S*)$/);
4950
+ const fenceMatch = /^```(\S*)$/.exec(line);
4952
4951
  if (fenceMatch) {
4953
4952
  const lang = fenceMatch[1];
4954
4953
  const codeLines = [];
@@ -4967,7 +4966,7 @@
4967
4966
  i++;
4968
4967
  continue;
4969
4968
  }
4970
- const hMatch = line.match(/^(#{1,6})\s+(.+)$/);
4969
+ const hMatch = /^(#{1,6})\s+(.+)$/.exec(line);
4971
4970
  if (hMatch) {
4972
4971
  const level = hMatch[1].length;
4973
4972
  out.push(`<h${level}>${_inline(hMatch[2])}</h${level}>`);
@@ -5014,7 +5013,8 @@
5014
5013
  i++;
5015
5014
  }
5016
5015
  const thead = `<thead><tr>${headerCells.map((c) => `<th>${_inline(c)}</th>`).join("")}</tr></thead>`;
5017
- const tbody = bodyRows.length ? `<tbody>${bodyRows.map((row) => `<tr>${row.map((c) => `<td>${_inline(c)}</td>`).join("")}</tr>`).join("")}</tbody>` : "";
5016
+ const renderRow = (row) => `<tr>${row.map((c) => `<td>${_inline(c)}</td>`).join("")}</tr>`;
5017
+ const tbody = bodyRows.length ? `<tbody>${bodyRows.map(renderRow).join("")}</tbody>` : "";
5018
5018
  out.push(`<table>${thead}${tbody}</table>`);
5019
5019
  continue;
5020
5020
  }
@@ -5050,10 +5050,10 @@
5050
5050
  return text;
5051
5051
  }
5052
5052
  function _esc(v) {
5053
- return String(v).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5053
+ return String(v).replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
5054
5054
  }
5055
5055
  function _escAttr(v) {
5056
- return String(v).replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5056
+ return String(v).replaceAll("&", "&amp;").replaceAll("\"", "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
5057
5057
  }
5058
5058
  //#endregion
5059
5059
  //#region src/js/core/detectLang.js
@@ -5135,7 +5135,7 @@
5135
5135
  const onBeforeInput = (event) => this._enforceLimit(event);
5136
5136
  const onSelChange = () => {
5137
5137
  if (!this.context._alive) return;
5138
- const sel = window.getSelection();
5138
+ const sel = globalThis.getSelection();
5139
5139
  if (sel && sel.rangeCount > 0 && editable.contains(sel.anchorNode)) {
5140
5140
  this.context.invoke("toolbar.refresh");
5141
5141
  if (typeof this.options.onSelectionChange === "function") this.options.onSelectionChange(this.context);
@@ -5145,7 +5145,7 @@
5145
5145
  if (e.target.type === "checkbox" && e.target.closest(".an-checklist")) this.afterCommand();
5146
5146
  };
5147
5147
  const fixChecklistCursor = (event) => {
5148
- const sel = window.getSelection();
5148
+ const sel = globalThis.getSelection();
5149
5149
  if (!sel || !sel.rangeCount) return;
5150
5150
  const r = sel.getRangeAt(0);
5151
5151
  if (!r.collapsed) return;
@@ -5199,7 +5199,7 @@
5199
5199
  /** @type {string|null} 'superscript' | 'subscript' | null */
5200
5200
  let _compositionSupSub = null;
5201
5201
  const onCompositionStart = () => {
5202
- const sel = window.getSelection();
5202
+ const sel = globalThis.getSelection();
5203
5203
  if (!sel || !sel.rangeCount) {
5204
5204
  _compositionSupSub = null;
5205
5205
  return;
@@ -5217,12 +5217,12 @@
5217
5217
  const tag = _compositionSupSub;
5218
5218
  _compositionSupSub = null;
5219
5219
  if (!tag) return;
5220
- const sel = window.getSelection();
5220
+ const sel = globalThis.getSelection();
5221
5221
  if (!sel || !sel.rangeCount) return;
5222
5222
  let node = sel.getRangeAt(0).startContainer;
5223
5223
  if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
5224
5224
  const el = node;
5225
- if (!(el && (tag === "superscript" ? el.closest("sup") : el.closest("sub")))) document.execCommand(tag);
5225
+ if (!(tag === "superscript" ? el?.closest("sup") : el?.closest("sub"))) document.execCommand(tag);
5226
5226
  };
5227
5227
  this._disposers.push(on(editable, "compositionstart", onCompositionStart), on(editable, "compositionend", onCompositionEnd));
5228
5228
  }
@@ -5296,7 +5296,7 @@
5296
5296
  if (type === "insertFromPaste" || type === "insertFromDrop") return;
5297
5297
  if (!type.startsWith("insert")) return;
5298
5298
  const text = this.context.layoutInfo.editable.innerText || "";
5299
- const chars = text.replace(/\n/g, "").length;
5299
+ const chars = text.replaceAll("\n", "").length;
5300
5300
  if (maxChars && chars >= maxChars) {
5301
5301
  event.preventDefault();
5302
5302
  if (typeof this.options.onCharLimitReached === "function") this.options.onCharLimitReached(this.context);
@@ -5335,7 +5335,7 @@
5335
5335
  */
5336
5336
  _cleanOrphanedFigures() {
5337
5337
  this.context.layoutInfo.editable.querySelectorAll("figure.an-figure").forEach((fig) => {
5338
- if (!fig.querySelector("img")) fig.parentNode.removeChild(fig);
5338
+ if (!fig.querySelector("img")) fig.remove();
5339
5339
  });
5340
5340
  }
5341
5341
  /**
@@ -5371,7 +5371,7 @@
5371
5371
  * @returns {string}
5372
5372
  */
5373
5373
  getHTML() {
5374
- const raw = this.context.layoutInfo.editable.innerHTML.replace(/\u200B/g, "");
5374
+ const raw = this.context.layoutInfo.editable.innerHTML.replaceAll("​", "");
5375
5375
  return this.context.invoke("clipboard.resolveImages", raw) ?? raw;
5376
5376
  }
5377
5377
  /**
@@ -5416,7 +5416,7 @@
5416
5416
  * @returns {boolean}
5417
5417
  */
5418
5418
  isEmpty() {
5419
- const text = (this.context.layoutInfo.editable.innerText || "").trim().replace(/\u00a0/g, "");
5419
+ const text = (this.context.layoutInfo.editable.innerText || "").trim().replaceAll("\xA0", "");
5420
5420
  const hasMedia = !!this.context.layoutInfo.editable.querySelector("img, video, iframe, table");
5421
5421
  return !text && !hasMedia;
5422
5422
  }
@@ -5551,11 +5551,11 @@
5551
5551
  formatBlock(tagName) {
5552
5552
  formatBlock(tagName);
5553
5553
  if (tagName === "pre") {
5554
- const sel = window.getSelection();
5554
+ const sel = globalThis.getSelection();
5555
5555
  if (sel && sel.rangeCount > 0) {
5556
5556
  const container = sel.getRangeAt(0).commonAncestorContainer;
5557
5557
  const pre = container.nodeType === 1 ? container.closest("pre") : container.parentElement?.closest("pre");
5558
- if (pre && !pre.getAttribute("data-language")) {
5558
+ if (pre && !pre.dataset.language) {
5559
5559
  const lang = detectLang(pre.textContent || "");
5560
5560
  if (lang) {
5561
5561
  this.context.invoke("codeTooltip.applyLanguage", pre, lang);
@@ -5608,7 +5608,7 @@
5608
5608
  * @param {boolean} [openInNewTab=false]
5609
5609
  */
5610
5610
  insertLink(url, text, openInNewTab = false) {
5611
- const sel = window.getSelection();
5611
+ const sel = globalThis.getSelection();
5612
5612
  if (!sel || sel.rangeCount === 0) return;
5613
5613
  const safeUrl = sanitiseUrl(url);
5614
5614
  if (!safeUrl) return;
@@ -5671,7 +5671,7 @@
5671
5671
  this.afterCommand();
5672
5672
  }
5673
5673
  _getClosestAnchor() {
5674
- const sel = window.getSelection();
5674
+ const sel = globalThis.getSelection();
5675
5675
  if (!sel || sel.rangeCount === 0) return null;
5676
5676
  let node = sel.getRangeAt(0).startContainer;
5677
5677
  while (node) {
@@ -5686,7 +5686,7 @@
5686
5686
  * @returns {string}
5687
5687
  */
5688
5688
  _escapeAttr(str) {
5689
- return String(str ?? "").replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5689
+ return String(str ?? "").replaceAll("&", "&amp;").replaceAll("\"", "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
5690
5690
  }
5691
5691
  };
5692
5692
  //#endregion
@@ -5801,7 +5801,7 @@
5801
5801
  this._refreshRaf = null;
5802
5802
  this._disposers.forEach((d) => d());
5803
5803
  this._disposers = [];
5804
- if (this.el && this.el.parentNode) this.el.parentNode.removeChild(this.el);
5804
+ if (this.el && this.el.parentNode) this.el.remove();
5805
5805
  this.el = null;
5806
5806
  }
5807
5807
  _buildButtons() {
@@ -5869,8 +5869,8 @@
5869
5869
  let isOpen = false;
5870
5870
  const setHighlight = (rows, cols) => {
5871
5871
  cells.forEach((cell) => {
5872
- const r = +cell.getAttribute("data-row");
5873
- const c = +cell.getAttribute("data-col");
5872
+ const r = +cell.dataset.row;
5873
+ const c = +cell.dataset.col;
5874
5874
  cell.classList.toggle("active", r <= rows && c <= cols);
5875
5875
  });
5876
5876
  label.textContent = rows && cols ? `${rows} × ${cols}` : this.context.locale.toolbar.insertTableLabel || "Insert Table";
@@ -5884,8 +5884,8 @@
5884
5884
  const ph = popup.offsetHeight;
5885
5885
  let left = rect.left;
5886
5886
  let top = rect.bottom + 4;
5887
- if (left + pw > window.innerWidth - 8) left = Math.max(8, window.innerWidth - pw - 8);
5888
- if (top + ph > window.innerHeight - 8) top = rect.top - ph - 4;
5887
+ if (left + pw > globalThis.innerWidth - 8) left = Math.max(8, globalThis.innerWidth - pw - 8);
5888
+ if (top + ph > globalThis.innerHeight - 8) top = rect.top - ph - 4;
5889
5889
  popup.style.left = `${left}px`;
5890
5890
  popup.style.top = `${top}px`;
5891
5891
  popup.style.visibility = "";
@@ -5905,14 +5905,14 @@
5905
5905
  const d2 = on(grid, "mouseover", (e) => {
5906
5906
  const cell = e.target?.closest(".an-table-cell");
5907
5907
  if (!cell) return;
5908
- setHighlight(+cell.getAttribute("data-row"), +cell.getAttribute("data-col"));
5908
+ setHighlight(+cell.dataset.row, +cell.dataset.col);
5909
5909
  });
5910
5910
  const d3 = on(grid, "mouseleave", () => setHighlight(0, 0));
5911
5911
  const d4 = on(grid, "click", (e) => {
5912
5912
  const cell = e.target?.closest(".an-table-cell");
5913
5913
  if (!cell) return;
5914
- const rows = +cell.getAttribute("data-row");
5915
- const cols = +cell.getAttribute("data-col");
5914
+ const rows = +cell.dataset.row;
5915
+ const cols = +cell.dataset.col;
5916
5916
  closePopup();
5917
5917
  this.context.invoke("editor.focus");
5918
5918
  def.action(this.context, rows, cols);
@@ -5921,7 +5921,7 @@
5921
5921
  if (isOpen) closePopup();
5922
5922
  });
5923
5923
  this._disposers.push(d1, d2, d3, d4, d5, () => {
5924
- if (popup.parentNode) popup.parentNode.removeChild(popup);
5924
+ if (popup.parentNode) popup.remove();
5925
5925
  });
5926
5926
  wrap.appendChild(btn);
5927
5927
  document.body.appendChild(popup);
@@ -6011,13 +6011,13 @@
6011
6011
  /** @type {Range|null} saved selection range before popup opens */
6012
6012
  let savedRange = null;
6013
6013
  const saveSelection = () => {
6014
- const sel = window.getSelection();
6014
+ const sel = globalThis.getSelection();
6015
6015
  savedRange = sel && sel.rangeCount ? sel.getRangeAt(0).cloneRange() : null;
6016
6016
  };
6017
6017
  const restoreSelection = () => {
6018
6018
  if (!savedRange) return;
6019
6019
  try {
6020
- const sel = window.getSelection();
6020
+ const sel = globalThis.getSelection();
6021
6021
  if (!sel) return;
6022
6022
  sel.removeAllRanges();
6023
6023
  sel.addRange(savedRange);
@@ -6032,7 +6032,7 @@
6032
6032
  const rect = arrowBtn.getBoundingClientRect();
6033
6033
  const popupMinW = 184;
6034
6034
  let left = rect.left;
6035
- if (left + popupMinW > window.innerWidth) left = rect.right - popupMinW;
6035
+ if (left + popupMinW > globalThis.innerWidth) left = rect.right - popupMinW;
6036
6036
  popup.style.top = `${rect.bottom + 4}px`;
6037
6037
  popup.style.left = `${Math.max(4, left)}px`;
6038
6038
  popup.style.display = "block";
@@ -6095,9 +6095,9 @@
6095
6095
  passive: true,
6096
6096
  capture: true
6097
6097
  });
6098
- window.addEventListener("resize", onScrollResize, { passive: true });
6099
- this._disposers.push(d1, d2, d2b, d3, d3b, d4, d5, d6, () => document.removeEventListener("scroll", onScrollResize, { capture: true }), () => window.removeEventListener("resize", onScrollResize), () => {
6100
- if (popup.parentNode) popup.parentNode.removeChild(popup);
6098
+ globalThis.addEventListener("resize", onScrollResize, { passive: true });
6099
+ this._disposers.push(d1, d2, d2b, d3, d3b, d4, d5, d6, () => document.removeEventListener("scroll", onScrollResize, { capture: true }), () => globalThis.removeEventListener("resize", onScrollResize), () => {
6100
+ if (popup.parentNode) popup.remove();
6101
6101
  });
6102
6102
  this._colorPickerClosers.push(closePopup);
6103
6103
  this._disposers.push(() => {
@@ -6141,7 +6141,7 @@
6141
6141
  /** @type {Range|null} */
6142
6142
  let _savedRange = null;
6143
6143
  const dMousedown = on(select, "mousedown", () => {
6144
- const sel = window.getSelection();
6144
+ const sel = globalThis.getSelection();
6145
6145
  _savedRange = sel && sel.rangeCount ? sel.getRangeAt(0).cloneRange() : null;
6146
6146
  });
6147
6147
  const disposer = on(select, "change", (e) => {
@@ -6150,7 +6150,7 @@
6150
6150
  if (!value || selectedOpt.disabled) return;
6151
6151
  this.context.invoke("editor.focus");
6152
6152
  if (_savedRange) try {
6153
- const sel = window.getSelection();
6153
+ const sel = globalThis.getSelection();
6154
6154
  if (sel) {
6155
6155
  sel.removeAllRanges();
6156
6156
  sel.addRange(_savedRange);
@@ -6215,13 +6215,19 @@
6215
6215
  if (!this.el) return;
6216
6216
  const btnMap = this._btnMap || /* @__PURE__ */ new Map();
6217
6217
  this.el.querySelectorAll("button[data-btn]").forEach((btn) => {
6218
- const def = btnMap.get(btn.getAttribute("data-btn"));
6218
+ const def = btnMap.get(
6219
+ /** @type {HTMLElement} */
6220
+ btn.dataset.btn
6221
+ );
6219
6222
  if (def && typeof def.isActive === "function") btn.classList.toggle("active", !!def.isActive(this.context));
6220
6223
  if (def && typeof def.isDisabled === "function")
6221
6224
  /** @type {HTMLButtonElement} */ btn.disabled = !!def.isDisabled(this.context);
6222
6225
  });
6223
6226
  this.el.querySelectorAll("select[data-btn]").forEach((select) => {
6224
- const def = btnMap.get(select.getAttribute("data-btn"));
6227
+ const def = btnMap.get(
6228
+ /** @type {HTMLElement} */
6229
+ select.dataset.btn
6230
+ );
6225
6231
  if (!def || typeof def.getValue !== "function") return;
6226
6232
  let raw = (def.getValue(this.context) || "").replace(/["']/g, "").trim();
6227
6233
  if (!raw) raw = this.options.defaultFontFamily || this.options.fontFamilies && this.options.fontFamilies[0] || "";
@@ -6347,7 +6353,7 @@
6347
6353
  this._dragDisposers.forEach((d) => d());
6348
6354
  this._dragDisposers = null;
6349
6355
  }
6350
- if (this.el && this.el.parentNode) this.el.parentNode.removeChild(this.el);
6356
+ this.el?.remove();
6351
6357
  this.el = null;
6352
6358
  }
6353
6359
  _bindResize(handle) {
@@ -6411,7 +6417,7 @@
6411
6417
  if (!this._wordCountEl || !this._charCountEl) return;
6412
6418
  const text = this.context.layoutInfo.editable.textContent || "";
6413
6419
  const words = _countWords(text);
6414
- const chars = text.replace(/\n/g, "").length;
6420
+ const chars = text.replaceAll("\n", "").length;
6415
6421
  const maxWords = this.options.maxWords || 0;
6416
6422
  const maxChars = this.options.maxChars || 0;
6417
6423
  const LS = this.context.locale.statusbar;
@@ -6433,7 +6439,7 @@
6433
6439
  * @returns {number}
6434
6440
  */
6435
6441
  getCharCount() {
6436
- return (this.context.layoutInfo.editable.innerText || "").replace(/\n/g, "").length;
6442
+ return (this.context.layoutInfo.editable.innerText || "").replaceAll("\n", "").length;
6437
6443
  }
6438
6444
  };
6439
6445
  //#endregion
@@ -6526,7 +6532,7 @@
6526
6532
  if (el.querySelector("a, strong, em, b, i, ul, ol, li, table, img, blockquote, pre, code, h1, h2, h3, h4, h5, h6")) continue;
6527
6533
  const parent = el.parentNode;
6528
6534
  while (el.firstChild) parent.insertBefore(el.firstChild, el);
6529
- parent.removeChild(el);
6535
+ el.remove();
6530
6536
  }
6531
6537
  doc.querySelectorAll("*").forEach((el) => {
6532
6538
  el.removeAttribute("class");
@@ -6568,7 +6574,7 @@
6568
6574
  this._forcePlain = !!val;
6569
6575
  }
6570
6576
  _onPaste(event) {
6571
- const clipboardData = event.clipboardData || window.clipboardData;
6577
+ const clipboardData = event.clipboardData || globalThis.clipboardData;
6572
6578
  if (!clipboardData) return;
6573
6579
  const forcePlain = this._forcePlain;
6574
6580
  this._forcePlain = false;
@@ -6612,7 +6618,6 @@
6612
6618
  if (this.options.pasteStripAttributes) html = this._stripAttributes(html);
6613
6619
  execCommand("insertHTML", html);
6614
6620
  this.context.invoke("editor.afterCommand");
6615
- return;
6616
6621
  }
6617
6622
  }
6618
6623
  _onDragover(event) {
@@ -6644,17 +6649,17 @@
6644
6649
  this.options.onImageUpload(files);
6645
6650
  return;
6646
6651
  }
6647
- const UNSUPPORTED = [
6652
+ const UNSUPPORTED = new Set([
6648
6653
  "image/tiff",
6649
6654
  "image/x-tiff",
6650
6655
  "image/bmp",
6651
6656
  "image/x-bmp",
6652
6657
  "image/x-ms-bmp"
6653
- ];
6658
+ ]);
6654
6659
  const maxBytes = (this.options.maxImageSize || 5) * 1024 * 1024;
6655
6660
  files.forEach((file) => {
6656
6661
  if (!file || !file.type.startsWith("image/")) return;
6657
- if (UNSUPPORTED.includes(file.type)) {
6662
+ if (UNSUPPORTED.has(file.type)) {
6658
6663
  const message = `Image format "${file.type}" is not supported for display in web browsers. Please convert to PNG, JPEG, or WebP first.`;
6659
6664
  this.context.triggerEvent("imageError", {
6660
6665
  file,
@@ -6706,10 +6711,10 @@
6706
6711
  */
6707
6712
  _dataUrlToBlob(dataUrl) {
6708
6713
  const [header, b64] = dataUrl.split(",");
6709
- const mime = header.match(/:(.*?);/)?.[1] ?? "image/png";
6714
+ const mime = /:(.*?);/.exec(header)?.[1] ?? "image/png";
6710
6715
  const binary = atob(b64);
6711
6716
  const arr = new Uint8Array(binary.length);
6712
- for (let i = 0; i < binary.length; i++) arr[i] = binary.charCodeAt(i);
6717
+ for (let i = 0; i < binary.length; i++) arr[i] = binary.codePointAt(i);
6713
6718
  return new Blob([arr], { type: mime });
6714
6719
  }
6715
6720
  /**
@@ -6777,7 +6782,7 @@
6777
6782
  }
6778
6783
  }
6779
6784
  if (!range) return;
6780
- const sel = window.getSelection();
6785
+ const sel = globalThis.getSelection();
6781
6786
  if (sel) {
6782
6787
  sel.removeAllRanges();
6783
6788
  sel.addRange(range);
@@ -6789,7 +6794,7 @@
6789
6794
  * @returns {string}
6790
6795
  */
6791
6796
  _escapeHTML(str) {
6792
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
6797
+ return str.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&#039;");
6793
6798
  }
6794
6799
  };
6795
6800
  //#endregion
@@ -6826,7 +6831,7 @@
6826
6831
  _update() {
6827
6832
  const editable = this.context.layoutInfo.editable;
6828
6833
  const isFocused = document.activeElement === editable;
6829
- const isEmpty = !(editable.textContent.replace(/\u200B/g, "").trim().length > 0) && !editable.querySelector("img, table, hr, .an-video-wrapper");
6834
+ const isEmpty = !(editable.textContent.replaceAll("​", "").trim().length > 0) && !editable.querySelector("img, table, hr, .an-video-wrapper");
6830
6835
  editable.classList.toggle("an-placeholder", isEmpty && !isFocused);
6831
6836
  }
6832
6837
  };
@@ -6854,7 +6859,7 @@
6854
6859
  destroy() {
6855
6860
  this._disposers.forEach((d) => d());
6856
6861
  this._disposers = [];
6857
- if (this._textarea && this._textarea.parentNode) this._textarea.parentNode.removeChild(this._textarea);
6862
+ this._textarea?.remove();
6858
6863
  this._textarea = null;
6859
6864
  }
6860
6865
  toggle() {
@@ -6885,7 +6890,7 @@
6885
6890
  if (!this._active || !this._textarea) return;
6886
6891
  const { editable } = this.context.layoutInfo;
6887
6892
  editable.innerHTML = sanitiseHTML(this._textarea.value, { allowIframes: true });
6888
- this._textarea.parentNode.removeChild(this._textarea);
6893
+ this._textarea.remove();
6889
6894
  this._textarea = null;
6890
6895
  editable.style.display = "";
6891
6896
  this._active = false;
@@ -6909,7 +6914,7 @@
6909
6914
  }).split("\n").map((line) => {
6910
6915
  const stripped = line.trim();
6911
6916
  if (!stripped) return "";
6912
- if (/^<\//.test(stripped)) indent = Math.max(0, indent - 1);
6917
+ if (stripped.startsWith("</")) indent = Math.max(0, indent - 1);
6913
6918
  const out = " ".repeat(indent) + stripped;
6914
6919
  if (/^<[^/!][^>]*[^/]>/.test(stripped) && !INLINE_RE.test(stripped) && !/^<(br|hr|img|input|link|meta)/.test(stripped)) indent++;
6915
6920
  return out;
@@ -6973,15 +6978,13 @@
6973
6978
  }
6974
6979
  };
6975
6980
  //#endregion
6976
- //#region src/js/module/LinkDialog.js
6981
+ //#region src/js/module/BaseDialog.js
6977
6982
  /**
6978
- * LinkDialog.js - Dialog for inserting / editing hyperlinks
6979
- * Inspired by Summernote's LinkDialog rewritten without jQuery
6983
+ * Shared lifecycle and shell-building logic for all modal dialogs.
6984
+ * Subclasses implement _buildDialog() for their specific form fields.
6980
6985
  */
6981
- var LinkDialog = class {
6982
- /**
6983
- * @param {import('../Context.js').Context} context
6984
- */
6986
+ var BaseDialog = class {
6987
+ /** @param {import('../Context.js').Context} context */
6985
6988
  constructor(context) {
6986
6989
  this.context = context;
6987
6990
  this.options = context.options;
@@ -6989,6 +6992,9 @@
6989
6992
  this._dialog = null;
6990
6993
  this._disposers = [];
6991
6994
  this._savedRange = null;
6995
+ /** @type {HTMLElement|null} First focusable input; set by subclass in _buildDialog(). */
6996
+ this._firstInput = null;
6997
+ this._removeTrap = null;
6992
6998
  }
6993
6999
  initialize() {
6994
7000
  this._dialog = this._buildDialog();
@@ -6998,36 +7004,113 @@
6998
7004
  destroy() {
6999
7005
  this._disposers.forEach((d) => d());
7000
7006
  this._disposers = [];
7001
- if (this._dialog && this._dialog.parentNode) this._dialog.parentNode.removeChild(this._dialog);
7007
+ if (this._dialog?.parentNode) this._dialog.remove();
7002
7008
  this._dialog = null;
7003
7009
  }
7004
- /**
7005
- * Opens the link dialog.
7006
- * Pre-fills with the currently selected link if present.
7007
- */
7008
- show() {
7010
+ /** Saves the current selection range before opening the dialog. */
7011
+ _saveRange() {
7009
7012
  withSavedRange((range) => {
7010
7013
  this._savedRange = range;
7011
7014
  });
7012
- this._prefill();
7013
- this._open();
7014
7015
  }
7015
- _buildDialog() {
7016
- const L = this.context.locale.linkDialog;
7016
+ _open() {
7017
+ if (this._dialog) {
7018
+ this._dialog.style.display = "flex";
7019
+ this._removeTrap = trapFocus(this._dialog, () => this._close());
7020
+ setTimeout(() => this._firstInput && this._firstInput.focus(), 50);
7021
+ }
7022
+ }
7023
+ _close() {
7024
+ if (this._dialog) this._dialog.style.display = "none";
7025
+ if (this._removeTrap) {
7026
+ this._removeTrap();
7027
+ this._removeTrap = null;
7028
+ }
7029
+ this._savedRange = null;
7030
+ }
7031
+ /**
7032
+ * Builds the overlay + box + header shell common to all dialogs.
7033
+ * Also wires up draggable and overlay-click-to-close.
7034
+ * @param {string} ariaLabel
7035
+ * @param {string} iconHtml Raw SVG string for the dialog icon
7036
+ * @param {string} titleText
7037
+ * @returns {{ overlay: HTMLElement, box: HTMLElement }}
7038
+ */
7039
+ _buildDialogShell(ariaLabel, iconHtml, titleText) {
7017
7040
  const overlay = createElement("div", {
7018
7041
  class: "an-dialog-overlay",
7019
7042
  role: "dialog",
7020
7043
  "aria-modal": "true",
7021
- "aria-label": L.ariaLabel
7044
+ "aria-label": ariaLabel
7022
7045
  });
7023
7046
  const box = createElement("div", { class: "an-dialog-box" });
7024
7047
  const header = createElement("div", { class: "an-dialog-header" });
7025
7048
  const iconEl = createElement("span", { class: "an-dialog-icon" });
7026
- iconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>`;
7027
- const title = createElement("h3", { class: "an-dialog-title" });
7028
- title.textContent = L.title;
7049
+ iconEl.innerHTML = iconHtml;
7050
+ const titleEl = createElement("h3", { class: "an-dialog-title" });
7051
+ titleEl.textContent = titleText;
7029
7052
  header.appendChild(iconEl);
7030
- header.appendChild(title);
7053
+ header.appendChild(titleEl);
7054
+ box.appendChild(header);
7055
+ overlay.appendChild(box);
7056
+ makeDraggable(header, box);
7057
+ const d = on(overlay, "click", (e) => {
7058
+ if (e.target === overlay) this._close();
7059
+ });
7060
+ this._disposers.push(d);
7061
+ return {
7062
+ overlay,
7063
+ box
7064
+ };
7065
+ }
7066
+ /**
7067
+ * Builds an action button row with a primary insert button and a cancel button.
7068
+ * Disposers are registered automatically.
7069
+ * @param {string} insertLabel
7070
+ * @param {string} cancelLabel
7071
+ * @param {() => void} onInsert
7072
+ * @returns {HTMLElement}
7073
+ */
7074
+ _buildButtonRow(insertLabel, cancelLabel, onInsert) {
7075
+ const btnRow = createElement("div", { class: "an-dialog-actions" });
7076
+ const insertBtn = createElement("button", {
7077
+ type: "button",
7078
+ class: "an-btn an-btn-primary"
7079
+ });
7080
+ insertBtn.textContent = insertLabel;
7081
+ const cancelBtn = createElement("button", {
7082
+ type: "button",
7083
+ class: "an-btn"
7084
+ });
7085
+ cancelBtn.textContent = cancelLabel;
7086
+ btnRow.appendChild(insertBtn);
7087
+ btnRow.appendChild(cancelBtn);
7088
+ const d1 = on(insertBtn, "click", onInsert);
7089
+ const d2 = on(cancelBtn, "click", () => this._close());
7090
+ this._disposers.push(d1, d2);
7091
+ return btnRow;
7092
+ }
7093
+ };
7094
+ //#endregion
7095
+ //#region src/js/module/LinkDialog.js
7096
+ /**
7097
+ * LinkDialog.js - Dialog for inserting / editing hyperlinks
7098
+ * Inspired by Summernote's LinkDialog — rewritten without jQuery
7099
+ */
7100
+ var ICON_SVG$2 = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>`;
7101
+ var LinkDialog = class extends BaseDialog {
7102
+ /**
7103
+ * Opens the link dialog.
7104
+ * Pre-fills with the currently selected link if present.
7105
+ */
7106
+ show() {
7107
+ this._saveRange();
7108
+ this._prefill();
7109
+ this._open();
7110
+ }
7111
+ _buildDialog() {
7112
+ const L = this.context.locale.linkDialog;
7113
+ const { overlay, box } = this._buildDialogShell(L.ariaLabel, ICON_SVG$2, L.title);
7031
7114
  const urlLabel = createElement("label", { class: "an-label" });
7032
7115
  urlLabel.textContent = L.url;
7033
7116
  const urlInput = createElement("input", {
@@ -7039,6 +7122,7 @@
7039
7122
  autocomplete: "off"
7040
7123
  });
7041
7124
  this._urlInput = urlInput;
7125
+ this._firstInput = urlInput;
7042
7126
  const textLabel = createElement("label", { class: "an-label" });
7043
7127
  textLabel.textContent = L.displayText;
7044
7128
  const textInput = createElement("input", {
@@ -7059,27 +7143,8 @@
7059
7143
  this._tabCheckbox = tabCheckbox;
7060
7144
  tabLabel.appendChild(tabCheckbox);
7061
7145
  tabLabel.appendChild(document.createTextNode(" " + L.openInNewTab));
7062
- const btnRow = createElement("div", { class: "an-dialog-actions" });
7063
- const insertBtn = createElement("button", {
7064
- type: "button",
7065
- class: "an-btn an-btn-primary"
7066
- });
7067
- insertBtn.textContent = L.insertBtn;
7068
- const cancelBtn = createElement("button", {
7069
- type: "button",
7070
- class: "an-btn"
7071
- });
7072
- cancelBtn.textContent = L.cancelBtn;
7073
- btnRow.appendChild(insertBtn);
7074
- btnRow.appendChild(cancelBtn);
7075
- box.append(header, urlLabel, urlInput, textLabel, textInput, tabLabel, btnRow);
7076
- overlay.appendChild(box);
7077
- makeDraggable(header, box);
7078
- const d1 = on(insertBtn, "click", () => this._onInsert());
7079
- const d2 = on(cancelBtn, "click", () => this._close());
7080
- const d3 = on(overlay, "click", (e) => {
7081
- if (e.target === overlay) this._close();
7082
- });
7146
+ const btnRow = this._buildButtonRow(L.insertBtn, L.cancelBtn, () => this._onInsert());
7147
+ box.append(urlLabel, urlInput, textLabel, textInput, tabLabel, btnRow);
7083
7148
  const d4 = on(urlInput, "keydown", (e) => {
7084
7149
  if (e.key === "Enter") {
7085
7150
  e.preventDefault();
@@ -7092,11 +7157,11 @@
7092
7157
  this._onInsert();
7093
7158
  }
7094
7159
  });
7095
- this._disposers.push(d1, d2, d3, d4, d5);
7160
+ this._disposers.push(d4, d5);
7096
7161
  return overlay;
7097
7162
  }
7098
7163
  _prefill() {
7099
- const sel = window.getSelection();
7164
+ const sel = globalThis.getSelection();
7100
7165
  let anchor = null;
7101
7166
  if (sel && sel.rangeCount > 0) {
7102
7167
  let node = sel.getRangeAt(0).startContainer;
@@ -7141,21 +7206,6 @@
7141
7206
  this.context.invoke("editor.insertLink", url, text, newTab);
7142
7207
  this._close();
7143
7208
  }
7144
- _open() {
7145
- if (this._dialog) {
7146
- this._dialog.style.display = "flex";
7147
- this._removeTrap = trapFocus(this._dialog, () => this._close());
7148
- setTimeout(() => this._urlInput && this._urlInput.focus(), 50);
7149
- }
7150
- }
7151
- _close() {
7152
- if (this._dialog) this._dialog.style.display = "none";
7153
- if (this._removeTrap) {
7154
- this._removeTrap();
7155
- this._removeTrap = null;
7156
- }
7157
- this._savedRange = null;
7158
- }
7159
7209
  };
7160
7210
  //#endregion
7161
7211
  //#region src/js/module/ImageDialog.js
@@ -7163,33 +7213,10 @@
7163
7213
  * ImageDialog.js - Dialog for inserting images (by URL or file upload)
7164
7214
  * Inspired by Summernote's ImageDialog — rewritten without jQuery
7165
7215
  */
7166
- var ImageDialog = class {
7167
- /**
7168
- * @param {import('../Context.js').Context} context
7169
- */
7170
- constructor(context) {
7171
- this.context = context;
7172
- this.options = context.options;
7173
- /** @type {HTMLElement|null} */
7174
- this._dialog = null;
7175
- this._disposers = [];
7176
- this._savedRange = null;
7177
- }
7178
- initialize() {
7179
- this._dialog = this._buildDialog();
7180
- document.body.appendChild(this._dialog);
7181
- return this;
7182
- }
7183
- destroy() {
7184
- this._disposers.forEach((d) => d());
7185
- this._disposers = [];
7186
- if (this._dialog && this._dialog.parentNode) this._dialog.parentNode.removeChild(this._dialog);
7187
- this._dialog = null;
7188
- }
7216
+ var ICON_SVG$1 = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>`;
7217
+ var ImageDialog = class extends BaseDialog {
7189
7218
  show() {
7190
- withSavedRange((range) => {
7191
- this._savedRange = range;
7192
- });
7219
+ this._saveRange();
7193
7220
  this._urlInput.value = "";
7194
7221
  this._altInput.value = "";
7195
7222
  if (this._fileInput) this._fileInput.value = "";
@@ -7197,20 +7224,7 @@
7197
7224
  }
7198
7225
  _buildDialog() {
7199
7226
  const L = this.context.locale.imageDialog;
7200
- const overlay = createElement("div", {
7201
- class: "an-dialog-overlay",
7202
- role: "dialog",
7203
- "aria-modal": "true",
7204
- "aria-label": L.ariaLabel
7205
- });
7206
- const box = createElement("div", { class: "an-dialog-box" });
7207
- const header = createElement("div", { class: "an-dialog-header" });
7208
- const iconEl = createElement("span", { class: "an-dialog-icon" });
7209
- iconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>`;
7210
- const title = createElement("h3", { class: "an-dialog-title" });
7211
- title.textContent = L.title;
7212
- header.appendChild(iconEl);
7213
- header.appendChild(title);
7227
+ const { overlay, box } = this._buildDialogShell(L.ariaLabel, ICON_SVG$1, L.title);
7214
7228
  const urlLabel = createElement("label", { class: "an-label" });
7215
7229
  urlLabel.textContent = L.imageUrl;
7216
7230
  const urlInput = createElement("input", {
@@ -7220,6 +7234,7 @@
7220
7234
  autocomplete: "off"
7221
7235
  });
7222
7236
  this._urlInput = urlInput;
7237
+ this._firstInput = urlInput;
7223
7238
  const altLabel = createElement("label", { class: "an-label" });
7224
7239
  altLabel.textContent = L.altText;
7225
7240
  const altInput = createElement("input", {
@@ -7229,7 +7244,7 @@
7229
7244
  autocomplete: "off"
7230
7245
  });
7231
7246
  this._altInput = altInput;
7232
- box.append(header, urlLabel, urlInput, altLabel, altInput);
7247
+ box.append(urlLabel, urlInput, altLabel, altInput);
7233
7248
  const alignLabel = createElement("label", { class: "an-label" });
7234
7249
  alignLabel.textContent = L.alignment;
7235
7250
  const alignRow = createElement("div", { class: "an-align-row" });
@@ -7283,27 +7298,8 @@
7283
7298
  this._disposers.push(d);
7284
7299
  box.append(fileLabel, fileInput, fileHint);
7285
7300
  }
7286
- const btnRow = createElement("div", { class: "an-dialog-actions" });
7287
- const insertBtn = createElement("button", {
7288
- type: "button",
7289
- class: "an-btn an-btn-primary"
7290
- });
7291
- insertBtn.textContent = L.insertBtn;
7292
- const cancelBtn = createElement("button", {
7293
- type: "button",
7294
- class: "an-btn"
7295
- });
7296
- cancelBtn.textContent = L.cancelBtn;
7297
- btnRow.appendChild(insertBtn);
7298
- btnRow.appendChild(cancelBtn);
7301
+ const btnRow = this._buildButtonRow(L.insertBtn, L.cancelBtn, () => this._onInsert());
7299
7302
  box.append(btnRow);
7300
- overlay.appendChild(box);
7301
- makeDraggable(header, box);
7302
- const d1 = on(insertBtn, "click", () => this._onInsert());
7303
- const d2 = on(cancelBtn, "click", () => this._close());
7304
- const d3 = on(overlay, "click", (e) => {
7305
- if (e.target === overlay) this._close();
7306
- });
7307
7303
  const d4 = on(urlInput, "keydown", (e) => {
7308
7304
  if (e.key === "Enter") {
7309
7305
  e.preventDefault();
@@ -7316,7 +7312,7 @@
7316
7312
  this._onInsert();
7317
7313
  }
7318
7314
  });
7319
- this._disposers.push(d1, d2, d3, d4, d5);
7315
+ this._disposers.push(d4, d5);
7320
7316
  return overlay;
7321
7317
  }
7322
7318
  _onFileChange() {
@@ -7371,21 +7367,6 @@
7371
7367
  this.context.invoke("editor.insertImage", src, alt, align);
7372
7368
  this._close();
7373
7369
  }
7374
- _open() {
7375
- if (this._dialog) {
7376
- this._dialog.style.display = "flex";
7377
- this._removeTrap = trapFocus(this._dialog, () => this._close());
7378
- setTimeout(() => this._urlInput && this._urlInput.focus(), 50);
7379
- }
7380
- }
7381
- _close() {
7382
- if (this._dialog) this._dialog.style.display = "none";
7383
- if (this._removeTrap) {
7384
- this._removeTrap();
7385
- this._removeTrap = null;
7386
- }
7387
- this._savedRange = null;
7388
- }
7389
7370
  };
7390
7371
  //#endregion
7391
7372
  //#region src/js/module/VideoDialog.js
@@ -7397,31 +7378,10 @@
7397
7378
  * • Vimeo URLs → <iframe> embed
7398
7379
  * • Direct video URLs → <video> element (.mp4 / .webm / .ogg)
7399
7380
  */
7400
- var VideoDialog = class {
7401
- /** @param {import('../Context.js').Context} context */
7402
- constructor(context) {
7403
- this.context = context;
7404
- this.options = context.options;
7405
- /** @type {HTMLElement|null} */
7406
- this._dialog = null;
7407
- this._disposers = [];
7408
- this._savedRange = null;
7409
- }
7410
- initialize() {
7411
- this._dialog = this._buildDialog();
7412
- document.body.appendChild(this._dialog);
7413
- return this;
7414
- }
7415
- destroy() {
7416
- this._disposers.forEach((d) => d());
7417
- this._disposers = [];
7418
- if (this._dialog && this._dialog.parentNode) this._dialog.parentNode.removeChild(this._dialog);
7419
- this._dialog = null;
7420
- }
7381
+ var ICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>`;
7382
+ var VideoDialog = class extends BaseDialog {
7421
7383
  show() {
7422
- withSavedRange((range) => {
7423
- this._savedRange = range;
7424
- });
7384
+ this._saveRange();
7425
7385
  this._urlInput.value = "";
7426
7386
  this._widthInput.value = "560";
7427
7387
  this._hintEl.textContent = "";
@@ -7429,20 +7389,7 @@
7429
7389
  }
7430
7390
  _buildDialog() {
7431
7391
  const L = this.context.locale.videoDialog;
7432
- const overlay = createElement("div", {
7433
- class: "an-dialog-overlay",
7434
- role: "dialog",
7435
- "aria-modal": "true",
7436
- "aria-label": L.ariaLabel
7437
- });
7438
- const box = createElement("div", { class: "an-dialog-box" });
7439
- const header = createElement("div", { class: "an-dialog-header" });
7440
- const iconEl = createElement("span", { class: "an-dialog-icon" });
7441
- iconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>`;
7442
- const title = createElement("h3", { class: "an-dialog-title" });
7443
- title.textContent = L.title;
7444
- header.appendChild(iconEl);
7445
- header.appendChild(title);
7392
+ const { overlay, box } = this._buildDialogShell(L.ariaLabel, ICON_SVG, L.title);
7446
7393
  const urlLabel = createElement("label", { class: "an-label" });
7447
7394
  urlLabel.textContent = L.videoUrl;
7448
7395
  const urlInput = createElement("input", {
@@ -7452,6 +7399,7 @@
7452
7399
  autocomplete: "off"
7453
7400
  });
7454
7401
  this._urlInput = urlInput;
7402
+ this._firstInput = urlInput;
7455
7403
  const hintEl = createElement("p", { class: "an-dialog-hint" });
7456
7404
  this._hintEl = hintEl;
7457
7405
  const widthLabel = createElement("label", { class: "an-label" });
@@ -7465,43 +7413,24 @@
7465
7413
  value: "560"
7466
7414
  });
7467
7415
  this._widthInput = widthInput;
7468
- const btnRow = createElement("div", { class: "an-dialog-actions" });
7469
- const insertBtn = createElement("button", {
7470
- type: "button",
7471
- class: "an-btn an-btn-primary"
7472
- });
7473
- insertBtn.textContent = L.insertBtn;
7474
- const cancelBtn = createElement("button", {
7475
- type: "button",
7476
- class: "an-btn"
7477
- });
7478
- cancelBtn.textContent = L.cancelBtn;
7479
- btnRow.appendChild(insertBtn);
7480
- btnRow.appendChild(cancelBtn);
7481
- box.append(header, urlLabel, urlInput, hintEl, widthLabel, widthInput, btnRow);
7482
- overlay.appendChild(box);
7483
- makeDraggable(header, box);
7416
+ const btnRow = this._buildButtonRow(L.insertBtn, L.cancelBtn, () => this._onInsert());
7417
+ box.append(urlLabel, urlInput, hintEl, widthLabel, widthInput, btnRow);
7484
7418
  const d0 = on(urlInput, "input", () => {
7485
7419
  const info = this._parseVideoUrl(urlInput.value.trim());
7486
7420
  hintEl.textContent = info ? this.context.locale.videoDialog.detected(info.type) : urlInput.value ? this.context.locale.videoDialog.unknownFormat : "";
7487
7421
  });
7488
- const d1 = on(insertBtn, "click", () => this._onInsert());
7489
- const d2 = on(cancelBtn, "click", () => this._close());
7490
- const d3 = on(overlay, "click", (e) => {
7491
- if (e.target === overlay) this._close();
7492
- });
7493
7422
  const d4 = on(urlInput, "keydown", (e) => {
7494
7423
  if (e.key === "Enter") {
7495
7424
  e.preventDefault();
7496
7425
  this._onInsert();
7497
7426
  }
7498
7427
  });
7499
- this._disposers.push(d0, d1, d2, d3, d4);
7428
+ this._disposers.push(d0, d4);
7500
7429
  return overlay;
7501
7430
  }
7502
7431
  _onInsert() {
7503
7432
  const rawUrl = this._urlInput.value.trim();
7504
- const width = Math.max(80, parseInt(this._widthInput.value, 10) || 560);
7433
+ const width = Math.max(80, Number.parseInt(this._widthInput.value, 10) || 560);
7505
7434
  if (!rawUrl) {
7506
7435
  this._urlInput.focus();
7507
7436
  return;
@@ -7516,21 +7445,6 @@
7516
7445
  this.context.invoke("editor.insertVideo", html);
7517
7446
  this._close();
7518
7447
  }
7519
- _open() {
7520
- if (this._dialog) {
7521
- this._dialog.style.display = "flex";
7522
- this._removeTrap = trapFocus(this._dialog, () => this._close());
7523
- setTimeout(() => this._urlInput && this._urlInput.focus(), 50);
7524
- }
7525
- }
7526
- _close() {
7527
- if (this._dialog) this._dialog.style.display = "none";
7528
- if (this._removeTrap) {
7529
- this._removeTrap();
7530
- this._removeTrap = null;
7531
- }
7532
- this._savedRange = null;
7533
- }
7534
7448
  /**
7535
7449
  * Parses a video URL and returns { type, embedUrl } or null.
7536
7450
  * @param {string} url
@@ -7544,22 +7458,22 @@
7544
7458
  } catch {
7545
7459
  return null;
7546
7460
  }
7547
- const ytWatch = url.match(/(?:youtube\.com\/watch\?(?:.*&)?v=|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/);
7461
+ const ytWatch = /(?:youtube\.com\/watch\?(?:.*&)?v=|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/.exec(url);
7548
7462
  if (ytWatch) return {
7549
7463
  type: "YouTube",
7550
7464
  embedUrl: `https://www.youtube.com/embed/${ytWatch[1]}`
7551
7465
  };
7552
- const ytShort = url.match(/youtu\.be\/([a-zA-Z0-9_-]{11})/);
7466
+ const ytShort = /youtu\.be\/([a-zA-Z0-9_-]{11})/.exec(url);
7553
7467
  if (ytShort) return {
7554
7468
  type: "YouTube",
7555
7469
  embedUrl: `https://www.youtube.com/embed/${ytShort[1]}`
7556
7470
  };
7557
- const ytShorts = url.match(/youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/);
7471
+ const ytShorts = /youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/.exec(url);
7558
7472
  if (ytShorts) return {
7559
7473
  type: "YouTube Shorts",
7560
7474
  embedUrl: `https://www.youtube.com/embed/${ytShorts[1]}`
7561
7475
  };
7562
- const vimeo = url.match(/vimeo\.com\/(\d+)/);
7476
+ const vimeo = /vimeo\.com\/(\d+)/.exec(url);
7563
7477
  if (vimeo) return {
7564
7478
  type: "Vimeo",
7565
7479
  embedUrl: `https://player.vimeo.com/video/${vimeo[1]}`
@@ -7583,7 +7497,7 @@
7583
7497
  const iframeTitle = `${info.type} video player`;
7584
7498
  return `<div class="an-video-wrapper" style="position:relative;display:block;width:${width}px;max-width:100%"><iframe src="${info.embedUrl}" width="${width}" height="${height}" title="${iframeTitle}" frameborder="0" allowfullscreen allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" style="display:block;max-width:100%"></iframe><div class="an-video-shield"></div></div>`;
7585
7499
  }
7586
- if (info && info.type === "Direct video") return `<div class="an-video-wrapper" style="position:relative;display:block;width:${width}px;max-width:100%"><video src="${info.embedUrl.replace(/"/g, "%22")}" width="${width}" height="${height}" controls style="display:block;max-width:100%"></video><div class="an-video-shield"></div></div>`;
7500
+ if (info && info.type === "Direct video") return `<div class="an-video-wrapper" style="position:relative;display:block;width:${width}px;max-width:100%"><video src="${info.embedUrl.replaceAll("\"", "%22")}" width="${width}" height="${height}" controls style="display:block;max-width:100%"></video><div class="an-video-shield"></div></div>`;
7587
7501
  const safeSrc = (() => {
7588
7502
  try {
7589
7503
  const p = new URL(url);
@@ -7594,7 +7508,7 @@
7594
7508
  }
7595
7509
  })();
7596
7510
  if (!safeSrc) return null;
7597
- return `<div class="an-video-wrapper" style="position:relative;display:block;width:${width}px;max-width:100%"><video src="${safeSrc.replace(/"/g, "%22")}" width="${width}" height="${height}" controls style="display:block;max-width:100%"></video><div class="an-video-shield"></div></div>`;
7511
+ return `<div class="an-video-wrapper" style="position:relative;display:block;width:${width}px;max-width:100%"><video src="${safeSrc.replaceAll("\"", "%22")}" width="${width}" height="${height}" controls style="display:block;max-width:100%"></video><div class="an-video-shield"></div></div>`;
7598
7512
  }
7599
7513
  };
7600
7514
  //#endregion
@@ -7665,7 +7579,7 @@
7665
7579
  if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
7666
7580
  const img = e.target?.closest("img");
7667
7581
  if (img) this._select(img);
7668
- }), on(document, "click", (e) => this._onDocClick(e)), on(window, "scroll", () => this._updateOverlayPosition(), { passive: true }), on(window, "resize", onWindowResize, { passive: true }), on(editable, "scroll", () => this._updateOverlayPosition(), { passive: true }));
7582
+ }), on(document, "click", (e) => this._onDocClick(e)), on(globalThis, "scroll", () => this._updateOverlayPosition(), { passive: true }), on(globalThis, "resize", onWindowResize, { passive: true }), on(editable, "scroll", () => this._updateOverlayPosition(), { passive: true }));
7669
7583
  return this;
7670
7584
  }
7671
7585
  destroy() {
@@ -7680,7 +7594,7 @@
7680
7594
  this._positionRaf = null;
7681
7595
  }
7682
7596
  this._deselect();
7683
- if (this._overlay && this._overlay.parentNode) this._overlay.parentNode.removeChild(this._overlay);
7597
+ if (this._overlay && this._overlay.parentNode) this._overlay.remove();
7684
7598
  this._overlay = null;
7685
7599
  }
7686
7600
  /** @returns {HTMLImageElement|null} */
@@ -7882,7 +7796,7 @@
7882
7796
  if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
7883
7797
  const wrapper = this._findWrapper(e.target);
7884
7798
  if (wrapper) this._select(wrapper);
7885
- }), on(document, "click", (e) => this._onDocClick(e)), on(window, "scroll", () => this._updateOverlayPosition(), { passive: true }), on(window, "resize", onWindowResize), on(editable, "scroll", () => this._updateOverlayPosition(), { passive: true }), on(editable, "dragstart", (e) => {
7799
+ }), on(document, "click", (e) => this._onDocClick(e)), on(globalThis, "scroll", () => this._updateOverlayPosition(), { passive: true }), on(globalThis, "resize", onWindowResize), on(editable, "scroll", () => this._updateOverlayPosition(), { passive: true }), on(editable, "dragstart", (e) => {
7886
7800
  if (e.target instanceof Element && e.target.closest(".an-video-wrapper")) e.preventDefault();
7887
7801
  }));
7888
7802
  return this;
@@ -7899,7 +7813,7 @@
7899
7813
  this._positionRaf = null;
7900
7814
  }
7901
7815
  this._deselect();
7902
- if (this._overlay && this._overlay.parentNode) this._overlay.parentNode.removeChild(this._overlay);
7816
+ this._overlay?.remove();
7903
7817
  this._overlay = null;
7904
7818
  }
7905
7819
  /** @returns {HTMLElement|null} */
@@ -7920,7 +7834,7 @@
7920
7834
  */
7921
7835
  _findWrapper(el) {
7922
7836
  if (!el || !(el instanceof Element)) return null;
7923
- if (el.classList && el.classList.contains("an-video-wrapper")) return el;
7837
+ if (el.classList?.contains("an-video-wrapper")) return el;
7924
7838
  const w = el.closest(".an-video-wrapper");
7925
7839
  if (w) return w;
7926
7840
  return null;
@@ -7953,7 +7867,7 @@
7953
7867
  _onDocClick(e) {
7954
7868
  if (!this._activeWrapper) return;
7955
7869
  if (this._activeWrapper.contains(e.target)) return;
7956
- if (this._overlay && this._overlay.contains(e.target)) return;
7870
+ if (this._overlay?.contains(e.target)) return;
7957
7871
  if (e.target.closest(".an-contextmenu")) return;
7958
7872
  this._deselect();
7959
7873
  }
@@ -8078,14 +7992,14 @@
8078
7992
  }), on(editable, "mouseout", (e) => {
8079
7993
  const to = e.relatedTarget;
8080
7994
  if (!to || !editable.contains(to) && !this._el.contains(to)) this._scheduleHide();
8081
- }), on(window, "scroll", () => this._hide(), { passive: true }), on(window, "resize", () => this._hide(), { passive: true }));
7995
+ }), on(globalThis, "scroll", () => this._hide(), { passive: true }), on(globalThis, "resize", () => this._hide(), { passive: true }));
8082
7996
  return this;
8083
7997
  }
8084
7998
  destroy() {
8085
7999
  this._clearTimers();
8086
8000
  this._disposers.forEach((d) => d());
8087
8001
  this._disposers = [];
8088
- if (this._el && this._el.parentNode) this._el.parentNode.removeChild(this._el);
8002
+ if (this._el && this._el.parentNode) this._el.remove();
8089
8003
  this._el = null;
8090
8004
  }
8091
8005
  _buildTooltip() {
@@ -8170,8 +8084,8 @@
8170
8084
  const margin = 6;
8171
8085
  let top = rect.bottom + margin;
8172
8086
  let left = rect.left;
8173
- if (top + tipH > window.innerHeight - margin) top = rect.top - tipH - margin;
8174
- if (left + tipW > window.innerWidth - margin) left = window.innerWidth - tipW - margin;
8087
+ if (top + tipH > globalThis.innerHeight - margin) top = rect.top - tipH - margin;
8088
+ if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
8175
8089
  if (left < margin) left = margin;
8176
8090
  this._el.style.top = `${top}px`;
8177
8091
  this._el.style.left = `${left}px`;
@@ -8186,12 +8100,12 @@
8186
8100
  }
8187
8101
  }
8188
8102
  _openLink() {
8189
- const url = this._activeAnchor && this._activeAnchor.getAttribute("href");
8190
- if (url) window.open(url, "_blank", "noopener,noreferrer");
8103
+ const url = this._activeAnchor?.getAttribute("href");
8104
+ if (url) globalThis.open(url, "_blank", "noopener,noreferrer");
8191
8105
  this._hide();
8192
8106
  }
8193
8107
  _copyLink() {
8194
- const url = this._activeAnchor && this._activeAnchor.getAttribute("href");
8108
+ const url = this._activeAnchor?.getAttribute("href");
8195
8109
  if (url) navigator.clipboard.writeText(url).catch(() => {
8196
8110
  const ta = document.createElement("textarea");
8197
8111
  ta.value = url;
@@ -8200,7 +8114,7 @@
8200
8114
  document.body.appendChild(ta);
8201
8115
  ta.select();
8202
8116
  document.execCommand("copy");
8203
- document.body.removeChild(ta);
8117
+ ta.remove();
8204
8118
  });
8205
8119
  if (this._copyBtn) {
8206
8120
  this._copyBtn.classList.add("an-link-tooltip-btn--copied");
@@ -8211,7 +8125,7 @@
8211
8125
  const anchor = this._activeAnchor;
8212
8126
  if (!anchor) return;
8213
8127
  this._hide();
8214
- const sel = window.getSelection();
8128
+ const sel = globalThis.getSelection();
8215
8129
  const range = document.createRange();
8216
8130
  range.selectNodeContents(anchor);
8217
8131
  sel.removeAllRanges();
@@ -8222,7 +8136,7 @@
8222
8136
  const anchor = this._activeAnchor;
8223
8137
  if (!anchor) return;
8224
8138
  this._hide();
8225
- const sel = window.getSelection();
8139
+ const sel = globalThis.getSelection();
8226
8140
  const range = document.createRange();
8227
8141
  range.selectNode(anchor);
8228
8142
  sel.removeAllRanges();
@@ -8271,14 +8185,14 @@
8271
8185
  }, { passive: true }), on(document, "click", (e) => {
8272
8186
  const et = e.target;
8273
8187
  if (this._activeImg && !this._activeImg.contains(et) && !this._el.contains(et)) this._hide();
8274
- }), on(window, "scroll", () => this._hide(), { passive: true }), on(window, "resize", () => this._hide(), { passive: true }));
8188
+ }), on(globalThis, "scroll", () => this._hide(), { passive: true }), on(globalThis, "resize", () => this._hide(), { passive: true }));
8275
8189
  return this;
8276
8190
  }
8277
8191
  destroy() {
8278
8192
  this._clearTimers();
8279
8193
  this._disposers.forEach((d) => d());
8280
8194
  this._disposers = [];
8281
- if (this._el && this._el.parentNode) this._el.parentNode.removeChild(this._el);
8195
+ this._el?.remove();
8282
8196
  this._el = null;
8283
8197
  }
8284
8198
  _buildTooltip() {
@@ -8379,8 +8293,8 @@
8379
8293
  const margin = 6;
8380
8294
  let top = rect.bottom + margin;
8381
8295
  let left = rect.left + (rect.width - tipW) / 2;
8382
- if (top + tipH > window.innerHeight - margin) top = rect.top - tipH - margin;
8383
- if (left + tipW > window.innerWidth - margin) left = window.innerWidth - tipW - margin;
8296
+ if (top + tipH > globalThis.innerHeight - margin) top = rect.top - tipH - margin;
8297
+ if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
8384
8298
  if (left < margin) left = margin;
8385
8299
  this._el.style.top = `${top}px`;
8386
8300
  this._el.style.left = `${left}px`;
@@ -8436,8 +8350,8 @@
8436
8350
  const img = this._activeImg;
8437
8351
  if (!img) return;
8438
8352
  const current = img.style.transform || "";
8439
- const match = current.match(/rotate\((-?[\d.]+)deg\)/);
8440
- const next = ((match ? parseFloat(match[1]) : 0) + delta + 360) % 360;
8353
+ const match = /rotate\((-?[\d.]+)deg\)/.exec(current);
8354
+ const next = ((match ? Number.parseFloat(match[1]) : 0) + delta + 360) % 360;
8441
8355
  const cleaned = current.replace(/rotate\(-?[\d.]+deg\)/, "").trim();
8442
8356
  img.style.transform = cleaned ? `${cleaned} rotate(${next}deg)` : next === 0 ? "" : `rotate(${next}deg)`;
8443
8357
  this.context.invoke("editor.afterCommand");
@@ -8452,8 +8366,8 @@
8452
8366
  this._hide();
8453
8367
  this.context.invoke("imageResizer.deselect");
8454
8368
  const figure = img.closest("figure.an-figure");
8455
- if (figure && figure.parentNode) figure.parentNode.removeChild(figure);
8456
- else if (img.parentNode) img.parentNode.removeChild(img);
8369
+ if (figure) figure.remove();
8370
+ else img.remove();
8457
8371
  this.context.invoke("editor.afterCommand");
8458
8372
  }
8459
8373
  _crop() {
@@ -8472,7 +8386,7 @@
8472
8386
  this._hide();
8473
8387
  const range = document.createRange();
8474
8388
  range.selectNodeContents(cap);
8475
- const sel = window.getSelection();
8389
+ const sel = globalThis.getSelection();
8476
8390
  if (sel) {
8477
8391
  sel.removeAllRanges();
8478
8392
  sel.addRange(range);
@@ -8506,7 +8420,7 @@
8506
8420
  figure.appendChild(figcaption);
8507
8421
  const range = document.createRange();
8508
8422
  range.selectNodeContents(figcaption);
8509
- const sel = window.getSelection();
8423
+ const sel = globalThis.getSelection();
8510
8424
  if (sel) {
8511
8425
  sel.removeAllRanges();
8512
8426
  sel.addRange(range);
@@ -8547,8 +8461,7 @@
8547
8461
  const editable = this.context.layoutInfo.editable;
8548
8462
  this._disposers.push(on(editable, "mouseover", (e) => {
8549
8463
  if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
8550
- const target = e.target;
8551
- const wrapper = target && target.closest ? target.closest(".an-video-wrapper") : null;
8464
+ const wrapper = e.target?.closest(".an-video-wrapper");
8552
8465
  if (wrapper && editable.contains(wrapper)) this._scheduleShow(wrapper);
8553
8466
  }, { passive: true }), on(editable, "mouseout", (e) => {
8554
8467
  const to = e.relatedTarget;
@@ -8556,7 +8469,7 @@
8556
8469
  }, { passive: true }), on(document, "click", (e) => {
8557
8470
  const target = e.target;
8558
8471
  if (this._activeWrapper && !this._activeWrapper.contains(target) && !this._el.contains(target)) this._hide();
8559
- }), on(window, "scroll", () => this._hide(), { passive: true }), on(window, "resize", () => this._hide(), { passive: true }));
8472
+ }), on(globalThis, "scroll", () => this._hide(), { passive: true }), on(globalThis, "resize", () => this._hide(), { passive: true }));
8560
8473
  return this;
8561
8474
  }
8562
8475
  destroy() {
@@ -8564,7 +8477,7 @@
8564
8477
  this._clearTimers();
8565
8478
  this._disposers.forEach((d) => d());
8566
8479
  this._disposers = [];
8567
- if (this._el && this._el.parentNode) this._el.parentNode.removeChild(this._el);
8480
+ this._el?.remove();
8568
8481
  this._el = null;
8569
8482
  }
8570
8483
  _buildTooltip() {
@@ -8661,8 +8574,8 @@
8661
8574
  const margin = 6;
8662
8575
  let top = rect.bottom + margin;
8663
8576
  let left = rect.left + (rect.width - tipW) / 2;
8664
- if (top + tipH > window.innerHeight - margin) top = rect.top - tipH - margin;
8665
- if (left + tipW > window.innerWidth - margin) left = window.innerWidth - tipW - margin;
8577
+ if (top + tipH > globalThis.innerHeight - margin) top = rect.top - tipH - margin;
8578
+ if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
8666
8579
  if (left < margin) left = margin;
8667
8580
  this._el.style.top = `${top}px`;
8668
8581
  this._el.style.left = `${left}px`;
@@ -8716,7 +8629,7 @@
8716
8629
  if (!wrapper) return;
8717
8630
  this._hide();
8718
8631
  this.context.invoke("videoResizer.deselect");
8719
- if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper);
8632
+ wrapper.remove();
8720
8633
  this.context.invoke("editor.afterCommand");
8721
8634
  }
8722
8635
  _togglePreview() {
@@ -8958,12 +8871,12 @@
8958
8871
  }, { passive: true }), on(editable, "mouseout", (e) => {
8959
8872
  if (this._selectMode) return;
8960
8873
  const to = e.relatedTarget;
8961
- if (!to || !editable.contains(to) && !this._el.contains(to) && !(this._sizePopover && this._sizePopover.contains(to))) this._scheduleHide();
8874
+ if (!to || !editable.contains(to) && !this._el.contains(to) && !this._sizePopover?.contains(to)) this._scheduleHide();
8962
8875
  }, { passive: true }), on(document, "click", (e) => {
8963
8876
  const et = e.target;
8964
- if (this._selectMode && this._activeTable && this._activeTable.contains(et)) return;
8965
- if (this._activeTable && !this._activeTable.contains(et) && !this._el.contains(et) && !(this._sizePopover && this._sizePopover.contains(et))) this._hide();
8966
- }), on(document, "selectionchange", () => this._syncShadeStrip()), on(window, "scroll", () => this._hide(), { passive: true }), on(window, "resize", () => this._hide(), { passive: true }));
8877
+ if (this._selectMode && this._activeTable?.contains(et)) return;
8878
+ if (this._activeTable && !this._activeTable.contains(et) && !this._el.contains(et) && !this._sizePopover?.contains(et)) this._hide();
8879
+ }), on(document, "selectionchange", () => this._syncShadeStrip()), on(globalThis, "scroll", () => this._hide(), { passive: true }), on(globalThis, "resize", () => this._hide(), { passive: true }));
8967
8880
  this._initResize();
8968
8881
  return this;
8969
8882
  }
@@ -9089,11 +9002,11 @@
9089
9002
  this._clearTimers();
9090
9003
  this._disposers.forEach((d) => d());
9091
9004
  this._disposers = [];
9092
- if (this._el && this._el.parentNode) this._el.parentNode.removeChild(this._el);
9005
+ if (this._el && this._el.parentNode) this._el.remove();
9093
9006
  this._el = null;
9094
- if (this._sizePopover && this._sizePopover.parentNode) this._sizePopover.parentNode.removeChild(this._sizePopover);
9007
+ if (this._sizePopover && this._sizePopover.parentNode) this._sizePopover.remove();
9095
9008
  this._sizePopover = null;
9096
- if (this._shadePopover && this._shadePopover.parentNode) this._shadePopover.parentNode.removeChild(this._shadePopover);
9009
+ if (this._shadePopover && this._shadePopover.parentNode) this._shadePopover.remove();
9097
9010
  this._shadePopover = null;
9098
9011
  }
9099
9012
  _buildTooltip() {
@@ -9203,7 +9116,7 @@
9203
9116
  _syncShadeStrip() {
9204
9117
  if (!this._shadeColorStrip || !this._el || this._el.style.display === "none") return;
9205
9118
  const cell = this._getCell();
9206
- this._shadeColorStrip.style.background = cell && cell.style.backgroundColor || "transparent";
9119
+ this._shadeColorStrip.style.background = cell?.style.backgroundColor || "transparent";
9207
9120
  }
9208
9121
  _hide() {
9209
9122
  this._el.style.display = "none";
@@ -9233,20 +9146,20 @@
9233
9146
  let left = rect.left + (rect.width - tipW) / 2;
9234
9147
  let top = rect.top - tipH - margin;
9235
9148
  if (top < margin) top = rect.bottom + margin;
9236
- if (left + tipW > window.innerWidth - margin) left = window.innerWidth - tipW - margin;
9149
+ if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
9237
9150
  if (left < margin) left = margin;
9238
9151
  this._el.style.left = `${left}px`;
9239
9152
  this._el.style.top = `${top}px`;
9240
9153
  }
9241
9154
  _getCell() {
9242
- const sel = window.getSelection();
9155
+ const sel = globalThis.getSelection();
9243
9156
  if (sel && sel.rangeCount) {
9244
9157
  let container = sel.getRangeAt(0).commonAncestorContainer;
9245
9158
  if (container.nodeType === 3) container = container.parentElement;
9246
- const cellFromSel = container && container.closest("td, th");
9247
- if (cellFromSel && this._activeTable && this._activeTable.contains(cellFromSel)) return cellFromSel;
9159
+ const cellFromSel = container?.closest("td, th");
9160
+ if (cellFromSel && this._activeTable?.contains(cellFromSel)) return cellFromSel;
9248
9161
  }
9249
- return this._activeCell || this._activeTable && this._activeTable.querySelector("td, th");
9162
+ return this._activeCell || this._activeTable?.querySelector("td, th");
9250
9163
  }
9251
9164
  _toggleSelectMode() {
9252
9165
  this._selectMode = !this._selectMode;
@@ -9345,11 +9258,12 @@
9345
9258
  const table = cells[0].closest("table");
9346
9259
  if (!table) return;
9347
9260
  const allRows = Array.from(table.querySelectorAll("tr"));
9348
- const refRow = [...new Set(cells.map((c) => c.closest("tr")).filter(Boolean))].reduce((best, r) => {
9261
+ const selectedRows = [...new Set(cells.map((c) => c.closest("tr")).filter(Boolean))];
9262
+ const refRow = selectedRows.reduce((best, r) => {
9349
9263
  const bi = allRows.indexOf(best);
9350
9264
  const ri = allRows.indexOf(r);
9351
9265
  return position === "above" ? ri < bi ? r : best : ri > bi ? r : best;
9352
- });
9266
+ }, selectedRows[0]);
9353
9267
  const colCount = Array.from(refRow.cells).reduce((sum, c) => sum + (c.colSpan || 1), 0);
9354
9268
  const newRow = document.createElement("tr");
9355
9269
  const refCells = Array.from(refRow.cells);
@@ -9392,7 +9306,7 @@
9392
9306
  if (selectedRows.filter((r) => r.closest("tbody")).length >= totalBodyRows) return;
9393
9307
  this._activeCell = null;
9394
9308
  this._clearSelection();
9395
- selectedRows.forEach((r) => r.parentElement?.removeChild(r));
9309
+ selectedRows.forEach((r) => r.remove());
9396
9310
  requestAnimationFrame(() => this._positionNear(this._activeTable));
9397
9311
  this.context.invoke("editor.afterCommand");
9398
9312
  }
@@ -9414,7 +9328,7 @@
9414
9328
  });
9415
9329
  this._activeCell = null;
9416
9330
  this._clearSelection();
9417
- cellsToDelete.forEach((c) => c.parentElement?.removeChild(c));
9331
+ cellsToDelete.forEach((c) => c.remove());
9418
9332
  requestAnimationFrame(() => this._positionNear(this._activeTable));
9419
9333
  this.context.invoke("editor.afterCommand");
9420
9334
  }
@@ -9425,7 +9339,7 @@
9425
9339
  if (!table) return;
9426
9340
  let selected = this._getSelectedCells().filter((c) => table.contains(c));
9427
9341
  if (selected.length < 2) {
9428
- const sel = window.getSelection();
9342
+ const sel = globalThis.getSelection();
9429
9343
  if (!sel || sel.rangeCount === 0) return;
9430
9344
  const range = sel.getRangeAt(0);
9431
9345
  selected = Array.from(table.querySelectorAll("td, th")).filter((c) => {
@@ -9467,7 +9381,7 @@
9467
9381
  first.rowSpan = maxR - minR + 1;
9468
9382
  first.style.verticalAlign = "middle";
9469
9383
  first.innerHTML = rectCells.map((c) => c.innerHTML).join("");
9470
- rectCells.slice(1).forEach((c) => c.parentElement?.removeChild(c));
9384
+ rectCells.slice(1).forEach((c) => c.remove());
9471
9385
  this._clearSelection();
9472
9386
  this.context.invoke("editor.afterCommand");
9473
9387
  }
@@ -9475,7 +9389,7 @@
9475
9389
  const table = this._activeTable;
9476
9390
  if (!table) return;
9477
9391
  this._hide();
9478
- if (table.parentNode) table.parentNode.removeChild(table);
9392
+ if (table.parentNode) table.remove();
9479
9393
  this.context.invoke("editor.afterCommand");
9480
9394
  }
9481
9395
  _unmergeCells() {
@@ -9564,7 +9478,7 @@
9564
9478
  this._sizeInputEl = inputEl;
9565
9479
  this._sizeApply = null;
9566
9480
  const d1 = on(applyBtn, "click", () => {
9567
- const val = parseInt(this._sizeInputEl.value, 10);
9481
+ const val = Number.parseInt(this._sizeInputEl.value, 10);
9568
9482
  if (val > 0 && typeof this._sizeApply === "function") this._sizeApply(val);
9569
9483
  this._hideSizePopover();
9570
9484
  });
@@ -9593,7 +9507,7 @@
9593
9507
  const table = cell.closest("table");
9594
9508
  if (!table) return;
9595
9509
  const firstCell = table.querySelector("td, th");
9596
- const currentPx = firstCell ? parseInt(firstCell.style.borderWidth, 10) || parseInt(window.getComputedStyle(firstCell).borderWidth, 10) || 1 : 1;
9510
+ const currentPx = firstCell ? Number.parseInt(firstCell.style.borderWidth, 10) || Number.parseInt(globalThis.getComputedStyle(firstCell).borderWidth, 10) || 1 : 1;
9597
9511
  this._sizeTitleEl.textContent = this.context.locale.tooltips.table.tableBorderWidthPx;
9598
9512
  this._sizeInputEl.min = "0";
9599
9513
  this._sizeInputEl.max = "10";
@@ -9652,8 +9566,8 @@
9652
9566
  const ph = this._sizePopover.offsetHeight || 110;
9653
9567
  let left = tipRect.left;
9654
9568
  let top = tipRect.bottom + 6;
9655
- if (left + pw > window.innerWidth - 8) left = window.innerWidth - pw - 8;
9656
- if (top + ph > window.innerHeight - 8) top = tipRect.top - ph - 6;
9569
+ if (left + pw > globalThis.innerWidth - 8) left = globalThis.innerWidth - pw - 8;
9570
+ if (top + ph > globalThis.innerHeight - 8) top = tipRect.top - ph - 6;
9657
9571
  this._sizePopover.style.left = `${left}px`;
9658
9572
  this._sizePopover.style.top = `${top}px`;
9659
9573
  if (this._sizeInputEl) {
@@ -9707,11 +9621,10 @@
9707
9621
  customRow.appendChild(colorInput);
9708
9622
  customRow.appendChild(customLabel);
9709
9623
  pop.appendChild(customRow);
9710
- this._disposers.push(on(pop, "mousedown", (e) => e.preventDefault()));
9711
- this._disposers.push(on(pop, "mouseenter", () => this._clearTimers()), on(pop, "mouseleave", () => this._scheduleHide()));
9624
+ this._disposers.push(on(pop, "mousedown", (e) => e.preventDefault()), on(pop, "mouseenter", () => this._clearTimers()), on(pop, "mouseleave", () => this._scheduleHide()));
9712
9625
  this._disposers.push(on(document, "click", (e) => {
9713
9626
  const et = e.target;
9714
- if (this._shadePopover && this._shadePopover.style.display !== "none" && !this._shadePopover.contains(et) && !(this._el && this._el.contains(et))) this._hideCellShadePopover();
9627
+ if (this._shadePopover && this._shadePopover.style.display !== "none" && !this._shadePopover.contains(et) && !this._el?.contains(et)) this._hideCellShadePopover();
9715
9628
  }));
9716
9629
  return pop;
9717
9630
  }
@@ -9728,8 +9641,8 @@
9728
9641
  const tipRect = this._el.getBoundingClientRect();
9729
9642
  let left = tipRect.left;
9730
9643
  let top = tipRect.bottom + 6;
9731
- if (left + pw > window.innerWidth - 8) left = window.innerWidth - pw - 8;
9732
- if (top + ph > window.innerHeight - 8) top = tipRect.top - ph - 6;
9644
+ if (left + pw > globalThis.innerWidth - 8) left = globalThis.innerWidth - pw - 8;
9645
+ if (top + ph > globalThis.innerHeight - 8) top = tipRect.top - ph - 6;
9733
9646
  this._shadePopover.style.left = `${Math.max(8, left)}px`;
9734
9647
  this._shadePopover.style.top = `${Math.max(8, top)}px`;
9735
9648
  });
@@ -9792,7 +9705,7 @@
9792
9705
  this._clearTimers();
9793
9706
  this._disposers.forEach((d) => d());
9794
9707
  this._disposers = [];
9795
- if (this._el && this._el.parentNode) this._el.parentNode.removeChild(this._el);
9708
+ this._el?.remove();
9796
9709
  this._el = null;
9797
9710
  }
9798
9711
  _buildTooltip() {
@@ -9918,21 +9831,21 @@
9918
9831
  let top = rect.top - tipH - margin;
9919
9832
  let left = rect.left + (rect.width - tipW) / 2;
9920
9833
  if (top < margin) top = rect.bottom + margin;
9921
- if (left + tipW > window.innerWidth - margin) left = window.innerWidth - tipW - margin;
9834
+ if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
9922
9835
  if (left < margin) left = margin;
9923
9836
  this._el.style.top = `${top}px`;
9924
9837
  this._el.style.left = `${left}px`;
9925
9838
  }
9926
9839
  _syncWrapBtn() {
9927
9840
  if (!this._activePre || !this._wrapBtn) return;
9928
- const wrapped = (this._activePre.style.whiteSpace || "").includes("pre-wrap") || window.getComputedStyle(this._activePre).whiteSpace === "pre-wrap";
9841
+ const wrapped = (this._activePre.style.whiteSpace || "").includes("pre-wrap") || globalThis.getComputedStyle(this._activePre).whiteSpace === "pre-wrap";
9929
9842
  this._wrapBtn.classList.toggle("active", wrapped);
9930
9843
  this._wrapBtn.title = wrapped ? this.context.locale.tooltips.code.disableWordWrap : this.context.locale.tooltips.code.enableWordWrap;
9931
9844
  }
9932
9845
  _syncLangSelect() {
9933
9846
  if (!this._activePre || !this._langSelect) return;
9934
9847
  const codeEl = this._activePre.querySelector("code");
9935
- const fromAttr = this._activePre.getAttribute("data-language") || "";
9848
+ const fromAttr = this._activePre.dataset.language || "";
9936
9849
  const fromClass = codeEl ? (_LANG_CLASS_RE.exec(codeEl.className) || [])[1] || "" : "";
9937
9850
  this._langSelect.value = fromAttr || fromClass || "";
9938
9851
  }
@@ -9951,7 +9864,7 @@
9951
9864
  document.execCommand("copy");
9952
9865
  this._flashCopied();
9953
9866
  } catch (_) {}
9954
- document.body.removeChild(ta);
9867
+ ta.remove();
9955
9868
  }
9956
9869
  }
9957
9870
  _flashCopied() {
@@ -9984,7 +9897,6 @@
9984
9897
  applyLanguage(pre, lang) {
9985
9898
  if (!pre || !lang) return;
9986
9899
  const savedPre = this._activePre;
9987
- this._langSelect && this._langSelect.value;
9988
9900
  this._activePre = pre;
9989
9901
  if (this._langSelect) this._langSelect.value = lang;
9990
9902
  this._onLangChange();
@@ -9995,7 +9907,7 @@
9995
9907
  const pre = this._activePre;
9996
9908
  if (!pre) return;
9997
9909
  const lang = this._langSelect.value;
9998
- const _w = window;
9910
+ const _w = globalThis;
9999
9911
  let codeEl = pre.querySelector("code");
10000
9912
  if (!codeEl) {
10001
9913
  codeEl = document.createElement("code");
@@ -10005,15 +9917,15 @@
10005
9917
  }
10006
9918
  codeEl.className = lang ? `language-${lang}` : "";
10007
9919
  pre.className = lang ? `language-${lang}` : "";
10008
- if (lang) pre.setAttribute("data-language", lang);
10009
- else pre.removeAttribute("data-language");
9920
+ if (lang) pre.dataset.language = lang;
9921
+ else delete pre.dataset.language;
10010
9922
  const applyPrism = () => {
10011
9923
  codeEl.querySelectorAll("br").forEach((br) => br.replaceWith("\n"));
10012
9924
  _w.Prism.highlightElement(codeEl);
10013
9925
  this.context.invoke("editor.afterCommand");
10014
9926
  };
10015
9927
  if (lang) {
10016
- if (typeof _w.Prism !== "undefined") {
9928
+ if (_w.Prism !== void 0) {
10017
9929
  if (_w.Prism.languages[lang]) {
10018
9930
  applyPrism();
10019
9931
  return;
@@ -10035,7 +9947,7 @@
10035
9947
  * Called once at initialize time. Fire-and-forget; errors are silent.
10036
9948
  */
10037
9949
  _ensurePrism() {
10038
- const _w = window;
9950
+ const _w = globalThis;
10039
9951
  if (!this.context.options.codeHighlight || _w.Prism) return;
10040
9952
  const cdn = this.context.options.codeHighlightCDN;
10041
9953
  const themeHref = `${cdn}/themes/prism-tomorrow.min.css`;
@@ -10068,11 +9980,11 @@
10068
9980
  * @param {Function} cb – called once the grammar is ready
10069
9981
  */
10070
9982
  _loadPrismComponent(lang, cb) {
10071
- const _w = window;
9983
+ const _w = globalThis;
10072
9984
  const src = `${this.context.options.codeHighlightCDN}/components/prism-${lang}.min.js`;
10073
9985
  if (document.querySelector(`script[src="${src}"]`)) {
10074
9986
  const poll = setInterval(() => {
10075
- if (_w.Prism && _w.Prism.languages[lang]) {
9987
+ if (_w.Prism?.languages[lang]) {
10076
9988
  clearInterval(poll);
10077
9989
  cb();
10078
9990
  }
@@ -10103,7 +10015,7 @@
10103
10015
  const pre = this._activePre;
10104
10016
  if (!pre) return;
10105
10017
  this._hide();
10106
- if (pre.parentNode) pre.parentNode.removeChild(pre);
10018
+ pre.remove();
10107
10019
  this.context.invoke("editor.afterCommand");
10108
10020
  }
10109
10021
  };
@@ -12458,7 +12370,7 @@
12458
12370
  destroy() {
12459
12371
  this._disposers.forEach((d) => d());
12460
12372
  this._disposers = [];
12461
- if (this._dialog && this._dialog.parentNode) this._dialog.parentNode.removeChild(this._dialog);
12373
+ if (this._dialog && this._dialog.parentNode) this._dialog.remove();
12462
12374
  this._dialog = null;
12463
12375
  }
12464
12376
  show() {
@@ -12519,7 +12431,7 @@
12519
12431
  class: "an-icon-cat",
12520
12432
  "data-cat": id
12521
12433
  });
12522
- tab.textContent = L.categories && L.categories[id] || label;
12434
+ tab.textContent = L.categories?.[id] || label;
12523
12435
  catBar.appendChild(tab);
12524
12436
  });
12525
12437
  this._catBar = catBar;
@@ -12600,7 +12512,7 @@
12600
12512
  const savedRange = this._savedRange;
12601
12513
  const editable = this.context.layoutInfo.editable;
12602
12514
  if (savedRange) savedRange.select();
12603
- const sel = window.getSelection();
12515
+ const sel = globalThis.getSelection();
12604
12516
  let range = sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
12605
12517
  if (!range) {
12606
12518
  range = document.createRange();
@@ -12610,7 +12522,7 @@
12610
12522
  const _sc = range.startContainer;
12611
12523
  const _tdAnchor = (_sc.nodeType === 1 ? _sc : _sc.parentElement)?.closest("td, th");
12612
12524
  range.deleteContents();
12613
- if (_tdAnchor && _tdAnchor.isConnected && !_tdAnchor.contains(range.startContainer)) {
12525
+ if (_tdAnchor?.isConnected && !_tdAnchor.contains(range.startContainer)) {
12614
12526
  range.setStart(_tdAnchor, 0);
12615
12527
  range.collapse(true);
12616
12528
  }
@@ -12630,7 +12542,7 @@
12630
12542
  if (this._dialog) {
12631
12543
  this._dialog.style.display = "flex";
12632
12544
  this._removeTrap = trapFocus(this._dialog, () => this._close());
12633
- setTimeout(() => this._searchInput && this._searchInput.focus(), 50);
12545
+ setTimeout(() => this._searchInput?.focus(), 50);
12634
12546
  }
12635
12547
  }
12636
12548
  _close() {
@@ -12937,7 +12849,7 @@
12937
12849
  destroy() {
12938
12850
  this._disposers.forEach((d) => d());
12939
12851
  this._disposers = [];
12940
- if (this._dialog && this._dialog.parentNode) this._dialog.parentNode.removeChild(this._dialog);
12852
+ this._dialog?.remove();
12941
12853
  this._dialog = null;
12942
12854
  }
12943
12855
  show() {
@@ -13002,7 +12914,7 @@
13002
12914
  class: "an-icon-cat",
13003
12915
  "data-cat": id
13004
12916
  });
13005
- tab.textContent = L.categories && L.categories[id] || label;
12917
+ tab.textContent = L.categories?.[id] || label;
13006
12918
  catBar.appendChild(tab);
13007
12919
  });
13008
12920
  this._catBar = catBar;
@@ -13170,17 +13082,17 @@
13170
13082
  this._preview.innerHTML = "<span class=\"an-icon-preview-hint\">Select an icon</span>";
13171
13083
  return;
13172
13084
  }
13173
- const cls = this._styleSelect && this._styleSelect.value || "fa-solid";
13174
- const size = this._sizeSelect && this._sizeSelect.value || "1em";
13175
- const color = (this._useColorCb ? this._useColorCb.checked : false) && this._colorInput ? this._colorInput.value : "";
13085
+ const cls = this._styleSelect?.value || "fa-solid";
13086
+ const size = this._sizeSelect?.value || "1em";
13087
+ const color = this._useColorCb?.checked ?? false ? this._colorInput?.value ?? "" : "";
13176
13088
  const styleAttr = [size ? `font-size:${size}` : "", color ? `color:${color}` : ""].filter(Boolean).join(";");
13177
13089
  this._preview.innerHTML = `<i class="${cls} fa-${name}" aria-hidden="true"${styleAttr ? ` style="${styleAttr}"` : ""}></i><div class="an-icon-preview-name">${cls} fa-${name}</div>`;
13178
13090
  }
13179
13091
  _onInsert() {
13180
13092
  if (!this._selectedIcon) return;
13181
- const cls = this._styleSelect && this._styleSelect.value || "fa-solid";
13182
- const size = this._sizeSelect && this._sizeSelect.value || "";
13183
- const color = (this._useColorCb ? this._useColorCb.checked : false) && this._colorInput ? this._colorInput.value : "";
13093
+ const cls = this._styleSelect?.value || "fa-solid";
13094
+ const size = this._sizeSelect?.value || "";
13095
+ const color = this._useColorCb?.checked ?? false ? this._colorInput?.value ?? "" : "";
13184
13096
  const styleParts = [size ? `font-size:${size}` : "", color ? `color:${color}` : ""].filter(Boolean);
13185
13097
  const iconEl = document.createElement("i");
13186
13098
  iconEl.className = `${cls} fa-${this._selectedIcon}`;
@@ -13190,8 +13102,8 @@
13190
13102
  const savedRange = this._savedRange;
13191
13103
  const editable = this.context.layoutInfo.editable;
13192
13104
  if (savedRange) savedRange.select();
13193
- const sel = window.getSelection();
13194
- let range = sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
13105
+ const sel = globalThis.getSelection();
13106
+ let range = (sel?.rangeCount ?? 0) > 0 ? sel.getRangeAt(0) : null;
13195
13107
  if (!range) {
13196
13108
  range = document.createRange();
13197
13109
  range.selectNodeContents(editable);
@@ -13230,7 +13142,7 @@
13230
13142
  if (this._dialog) {
13231
13143
  this._dialog.style.display = "flex";
13232
13144
  this._removeTrap = trapFocus(this._dialog, () => this._close());
13233
- setTimeout(() => this._searchInput && this._searchInput.focus(), 50);
13145
+ setTimeout(() => this._searchInput?.focus(), 50);
13234
13146
  }
13235
13147
  }
13236
13148
  _close() {
@@ -13331,7 +13243,7 @@
13331
13243
  icon: ICONS.paste,
13332
13244
  action: (ctx) => {
13333
13245
  if (!navigator.clipboard) return;
13334
- const editable = ctx.layoutInfo && ctx.layoutInfo.editable;
13246
+ const editable = ctx.layoutInfo?.editable;
13335
13247
  if (!editable) return;
13336
13248
  const doInsert = (html, text) => {
13337
13249
  editable.focus();
@@ -13456,13 +13368,13 @@
13456
13368
  this.el.style.display = "none";
13457
13369
  document.body.appendChild(this.el);
13458
13370
  this._renderItems(this._items);
13459
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
13371
+ const editable = this.context.layoutInfo?.editable;
13460
13372
  if (editable) this._disposers.push(on(editable, "contextmenu", (e) => this._onContextMenu(e)));
13461
13373
  this._disposers.push(on(document, "click", (e) => this._maybeHide(e)));
13462
13374
  this._disposers.push(on(document, "keydown", (e) => {
13463
13375
  if (e.key === "Escape") this.hide();
13464
13376
  }));
13465
- this._disposers.push(on(window, "scroll", () => this.hide(), { passive: true }));
13377
+ this._disposers.push(on(globalThis, "scroll", () => this.hide(), { passive: true }));
13466
13378
  return this;
13467
13379
  }
13468
13380
  destroy() {
@@ -13478,7 +13390,7 @@
13478
13390
  } catch (_e) {}
13479
13391
  });
13480
13392
  this._disposers = [];
13481
- if (this.el && this.el.parentNode) this.el.parentNode.removeChild(this.el);
13393
+ if (this.el) this.el.remove();
13482
13394
  this.el = null;
13483
13395
  }
13484
13396
  _renderItems(items) {
@@ -13506,8 +13418,8 @@
13506
13418
  backBtn.appendChild(createElement("span", { class: "an-context-label" }, [backLabel]));
13507
13419
  const off = on(backBtn, "click", (e) => {
13508
13420
  e.stopPropagation();
13509
- const curLeft = parseFloat(this.el.style.left);
13510
- const curTop = parseFloat(this.el.style.top);
13421
+ const curLeft = Number.parseFloat(this.el.style.left);
13422
+ const curTop = Number.parseFloat(this.el.style.top);
13511
13423
  this._renderItems(it.navigate());
13512
13424
  this._reposition(curLeft, curTop);
13513
13425
  });
@@ -13550,8 +13462,8 @@
13550
13462
  btn.appendChild(chevron);
13551
13463
  const off = on(btn, "click", (e) => {
13552
13464
  e.stopPropagation();
13553
- const curLeft = parseFloat(this.el.style.left);
13554
- const curTop = parseFloat(this.el.style.top);
13465
+ const curLeft = Number.parseFloat(this.el.style.left);
13466
+ const curTop = Number.parseFloat(this.el.style.top);
13555
13467
  this._renderItems(it.navigate());
13556
13468
  this._reposition(curLeft, curTop);
13557
13469
  });
@@ -13676,10 +13588,10 @@
13676
13588
  if (!cell) return;
13677
13589
  const rows = +cell.dataset.row;
13678
13590
  const cols = +cell.dataset.col;
13679
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
13591
+ const editable = this.context.layoutInfo?.editable;
13680
13592
  if (editable && this._savedRange) {
13681
13593
  editable.focus();
13682
- const sel = window.getSelection();
13594
+ const sel = globalThis.getSelection();
13683
13595
  sel.removeAllRanges();
13684
13596
  sel.addRange(this._savedRange.cloneRange());
13685
13597
  }
@@ -13721,12 +13633,12 @@
13721
13633
  });
13722
13634
  }
13723
13635
  _onContextMenu(event) {
13724
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
13636
+ const editable = this.context.layoutInfo?.editable;
13725
13637
  if (!editable) return;
13726
13638
  if (!editable.contains(event.target)) return;
13727
13639
  if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
13728
13640
  event.preventDefault();
13729
- const winSel = window.getSelection();
13641
+ const winSel = globalThis.getSelection();
13730
13642
  this._savedRange = winSel && winSel.rangeCount > 0 ? winSel.getRangeAt(0).cloneRange() : null;
13731
13643
  this._renderItems(this._items);
13732
13644
  const openX = event.clientX;
@@ -13758,9 +13670,9 @@
13758
13670
  const h = this.el.offsetHeight;
13759
13671
  let left = rx;
13760
13672
  let top = ry;
13761
- if (left + w > window.innerWidth - 8) left = window.innerWidth - w - 8;
13673
+ if (left + w > globalThis.innerWidth - 8) left = globalThis.innerWidth - w - 8;
13762
13674
  if (left < 8) left = 8;
13763
- if (top + h > window.innerHeight - 8) top = window.innerHeight - h - 8;
13675
+ if (top + h > globalThis.innerHeight - 8) top = globalThis.innerHeight - h - 8;
13764
13676
  if (top < 8) top = 8;
13765
13677
  this.el.style.left = `${left}px`;
13766
13678
  this.el.style.top = `${top}px`;
@@ -13781,17 +13693,17 @@
13781
13693
  let node = range.startContainer;
13782
13694
  if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
13783
13695
  if (!node) return type === "foreColor" ? "#000000" : "transparent";
13784
- const cs = window.getComputedStyle(node);
13696
+ const cs = globalThis.getComputedStyle(node);
13785
13697
  if (type === "foreColor") return cs.color || "#000000";
13786
13698
  const bg = cs.backgroundColor;
13787
13699
  return !bg || bg === "rgba(0, 0, 0, 0)" || bg === "transparent" ? "transparent" : bg;
13788
13700
  }
13789
13701
  /** Restore selection, apply a color command, then hide the menu. */
13790
13702
  _applyColor(type, color) {
13791
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
13703
+ const editable = this.context.layoutInfo?.editable;
13792
13704
  if (!editable || !this._savedRange) return;
13793
13705
  editable.focus();
13794
- const sel = window.getSelection();
13706
+ const sel = globalThis.getSelection();
13795
13707
  sel.removeAllRanges();
13796
13708
  sel.addRange(this._savedRange.cloneRange());
13797
13709
  document.execCommand(type, false, color);
@@ -13806,15 +13718,15 @@
13806
13718
  copyFormat() {
13807
13719
  const range = this._savedRange;
13808
13720
  if (!range) return;
13809
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
13721
+ const editable = this.context.layoutInfo?.editable;
13810
13722
  let node = range.startContainer;
13811
13723
  if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
13812
13724
  if (!node || !editable || !editable.contains(node)) return;
13813
- const cs = window.getComputedStyle(node);
13725
+ const cs = globalThis.getComputedStyle(node);
13814
13726
  const explicitFontFamily = this._findExplicitStyle(node, editable, "fontFamily");
13815
13727
  const explicitFontSize = this._findExplicitStyle(node, editable, "fontSize");
13816
13728
  this._copiedFormat = {
13817
- bold: parseInt(cs.fontWeight, 10) >= 700,
13729
+ bold: Number.parseInt(cs.fontWeight, 10) >= 700,
13818
13730
  italic: cs.fontStyle === "italic" || cs.fontStyle === "oblique",
13819
13731
  underline: (cs.textDecorationLine || "").includes("underline"),
13820
13732
  strikethrough: (cs.textDecorationLine || "").includes("line-through"),
@@ -13845,10 +13757,10 @@
13845
13757
  pasteFormat() {
13846
13758
  if (!this._copiedFormat || !this._savedRange) return;
13847
13759
  const fmt = this._copiedFormat;
13848
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
13760
+ const editable = this.context.layoutInfo?.editable;
13849
13761
  if (!editable) return;
13850
13762
  editable.focus();
13851
- const sel = window.getSelection();
13763
+ const sel = globalThis.getSelection();
13852
13764
  sel.removeAllRanges();
13853
13765
  sel.addRange(this._savedRange.cloneRange());
13854
13766
  document.execCommand("removeFormat");
@@ -13865,14 +13777,14 @@
13865
13777
  const preExisting = new Set(editable.querySelectorAll("font[size=\"7\"]"));
13866
13778
  document.execCommand("fontSize", false, "7");
13867
13779
  editable.querySelectorAll("font[size=\"7\"]").forEach((el) => {
13868
- if (!preExisting.has(el)) el.setAttribute("data-an-tmp", marker);
13780
+ if (!preExisting.has(el)) /** @type {HTMLElement} */ el.dataset.anTmp = marker;
13869
13781
  });
13870
13782
  editable.querySelectorAll(`[data-an-tmp="${marker}"]`).forEach((el) => {
13871
13783
  const span = document.createElement("span");
13872
13784
  span.style.fontSize = fmt.fontSize;
13873
13785
  el.parentNode.insertBefore(span, el);
13874
13786
  while (el.firstChild) span.appendChild(el.firstChild);
13875
- el.parentNode.removeChild(el);
13787
+ el.remove();
13876
13788
  });
13877
13789
  }
13878
13790
  this.context.invoke("editor.afterCommand");
@@ -13880,10 +13792,10 @@
13880
13792
  /** Strip all inline formatting from the saved selection. */
13881
13793
  removeFormat() {
13882
13794
  if (!this._savedRange) return;
13883
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
13795
+ const editable = this.context.layoutInfo?.editable;
13884
13796
  if (!editable) return;
13885
13797
  editable.focus();
13886
- const sel = window.getSelection();
13798
+ const sel = globalThis.getSelection();
13887
13799
  sel.removeAllRanges();
13888
13800
  sel.addRange(this._savedRange.cloneRange());
13889
13801
  document.execCommand("removeFormat");
@@ -13997,14 +13909,14 @@
13997
13909
  destroy() {
13998
13910
  this._disposers.forEach((d) => d());
13999
13911
  this._disposers = [];
14000
- if (this._dialog && this._dialog.parentNode) this._dialog.parentNode.removeChild(this._dialog);
13912
+ this._dialog?.remove();
14001
13913
  this._dialog = null;
14002
13914
  }
14003
13915
  show() {
14004
13916
  if (this._dialog) {
14005
13917
  this._dialog.style.display = "flex";
14006
13918
  this._removeTrap = trapFocus(this._dialog, () => this._close());
14007
- setTimeout(() => this._closeBtn && this._closeBtn.focus(), 50);
13919
+ setTimeout(() => this._closeBtn?.focus(), 50);
14008
13920
  }
14009
13921
  }
14010
13922
  _close() {
@@ -14110,7 +14022,7 @@
14110
14022
  this._clearHighlights();
14111
14023
  this._disposers.forEach((d) => d());
14112
14024
  this._disposers = [];
14113
- if (this._dialog && this._dialog.parentNode) this._dialog.parentNode.removeChild(this._dialog);
14025
+ if (this._dialog && this._dialog.parentNode) this._dialog.remove();
14114
14026
  this._dialog = null;
14115
14027
  }
14116
14028
  /**
@@ -14353,15 +14265,19 @@
14353
14265
  const re = this._queryRegex;
14354
14266
  const MAX_RESULTS = 500;
14355
14267
  const walker = document.createTreeWalker(root, 4);
14356
- let node;
14357
- while ((node = walker.nextNode()) && results.length < MAX_RESULTS) {
14268
+ let node = walker.nextNode();
14269
+ while (node && results.length < MAX_RESULTS) {
14358
14270
  re.lastIndex = 0;
14359
14271
  let m;
14360
- while ((m = re.exec(node.textContent)) !== null && results.length < MAX_RESULTS) results.push({
14272
+ while ((m = re.exec(
14273
+ /** @type {Text} */
14274
+ node.textContent
14275
+ )) !== null && results.length < MAX_RESULTS) results.push({
14361
14276
  node,
14362
14277
  start: m.index,
14363
14278
  end: m.index + m[0].length
14364
14279
  });
14280
+ node = walker.nextNode();
14365
14281
  }
14366
14282
  return results;
14367
14283
  }
@@ -14396,7 +14312,7 @@
14396
14312
  const parent = match.mark.parentNode;
14397
14313
  const textNode = document.createTextNode(replacement);
14398
14314
  parent.insertBefore(textNode, match.mark);
14399
- parent.removeChild(match.mark);
14315
+ match.mark.remove();
14400
14316
  parent.normalize();
14401
14317
  this.context.invoke("editor.afterCommand");
14402
14318
  const savedIndex = this._currentIndex;
@@ -14414,7 +14330,7 @@
14414
14330
  if (!mark || !mark.parentNode) return;
14415
14331
  const textNode = document.createTextNode(replacement);
14416
14332
  mark.parentNode.insertBefore(textNode, mark);
14417
- mark.parentNode.removeChild(mark);
14333
+ mark.remove();
14418
14334
  });
14419
14335
  if (this.context.layoutInfo.editable) this.context.layoutInfo.editable.normalize();
14420
14336
  this._matches = [];
@@ -14433,7 +14349,7 @@
14433
14349
  const parent = mark.parentNode;
14434
14350
  if (!parent) return;
14435
14351
  while (mark.firstChild) parent.insertBefore(mark.firstChild, mark);
14436
- parent.removeChild(mark);
14352
+ mark.remove();
14437
14353
  });
14438
14354
  editable.normalize();
14439
14355
  this._matches = [];
@@ -14484,7 +14400,7 @@
14484
14400
  resolve(null);
14485
14401
  }
14486
14402
  };
14487
- if (img.src.startsWith("data:") || img.src.startsWith("blob:") || img.src.startsWith(window.location.origin)) {
14403
+ if (img.src.startsWith("data:") || img.src.startsWith("blob:") || img.src.startsWith(globalThis.location.origin)) {
14488
14404
  tryDraw(img);
14489
14405
  return;
14490
14406
  }
@@ -14742,8 +14658,8 @@
14742
14658
  this._cropBox.style.top = `${y}px`;
14743
14659
  this._cropBox.style.width = `${w}px`;
14744
14660
  this._cropBox.style.height = `${h}px`;
14745
- const vw = window.innerWidth;
14746
- const vh = window.innerHeight;
14661
+ const vw = globalThis.innerWidth;
14662
+ const vh = globalThis.innerHeight;
14747
14663
  this._scrim.style.clipPath = [
14748
14664
  `polygon(`,
14749
14665
  `0 0, ${vw}px 0, ${vw}px ${vh}px, 0 ${vh}px, 0 0,`,
@@ -14767,7 +14683,7 @@
14767
14683
  }
14768
14684
  const margin = 8;
14769
14685
  let tbTop = y + h + margin;
14770
- if (tbTop + 40 > window.innerHeight - margin) tbTop = y - 40 - margin;
14686
+ if (tbTop + 40 > globalThis.innerHeight - margin) tbTop = y - 40 - margin;
14771
14687
  this._toolbar.style.left = `${x}px`;
14772
14688
  this._toolbar.style.top = `${tbTop}px`;
14773
14689
  }
@@ -14894,7 +14810,7 @@
14894
14810
  this._close(false);
14895
14811
  return;
14896
14812
  }
14897
- const fmt = img.src.match(/^data:image\/(jpe?g)/i) ? "image/jpeg" : "image/png";
14813
+ const fmt = /^data:image\/(jpe?g)/i.exec(img.src) ? "image/jpeg" : "image/png";
14898
14814
  const quality = fmt === "image/jpeg" ? .92 : void 0;
14899
14815
  const newSrc = canvas.toDataURL(fmt, quality);
14900
14816
  this._close(false);
@@ -14934,7 +14850,7 @@
14934
14850
  banner.textContent = msg;
14935
14851
  document.body.appendChild(banner);
14936
14852
  setTimeout(() => {
14937
- if (banner.parentNode) banner.parentNode.removeChild(banner);
14853
+ banner.remove();
14938
14854
  }, 4e3);
14939
14855
  }
14940
14856
  /**
@@ -14949,7 +14865,7 @@
14949
14865
  this._cropBox,
14950
14866
  this._toolbar
14951
14867
  ].forEach((el) => {
14952
- if (el && el.parentNode) el.parentNode.removeChild(el);
14868
+ el?.remove();
14953
14869
  });
14954
14870
  this._scrim = null;
14955
14871
  this._cropBox = null;
@@ -14970,7 +14886,7 @@
14970
14886
  *
14971
14887
  * Activated when both `autoSave` and `autoSaveRestore` options are true.
14972
14888
  * On initialize it checks localStorage for a draft that is within the
14973
- * `autoSaveRestoreTimeout` day window. If one is found a dismissible banner
14889
+ * `autoSaveRestoreTimeout` day globalThis. If one is found a dismissible banner
14974
14890
  * is prepended to the editor container.
14975
14891
  */
14976
14892
  var AutoSaveRestore = class {
@@ -15056,7 +14972,7 @@
15056
14972
  this._removeBanner();
15057
14973
  }
15058
14974
  _removeBanner() {
15059
- if (this._banner && this._banner.parentNode) this._banner.parentNode.removeChild(this._banner);
14975
+ this._banner?.remove();
15060
14976
  this._banner = null;
15061
14977
  }
15062
14978
  };
@@ -15119,8 +15035,8 @@
15119
15035
  * @returns {{ text: string, range: Range, lineNode: Node } | null}
15120
15036
  */
15121
15037
  _getLineContext() {
15122
- const sel = window.getSelection();
15123
- if (!sel || !sel.rangeCount) return null;
15038
+ const sel = globalThis.getSelection();
15039
+ if (!sel?.rangeCount) return null;
15124
15040
  const range = sel.getRangeAt(0);
15125
15041
  if (!range.collapsed) return null;
15126
15042
  const editable = this.context.layoutInfo.editable;
@@ -15139,7 +15055,7 @@
15139
15055
  }
15140
15056
  _isBlock(node) {
15141
15057
  if (node.nodeType !== Node.ELEMENT_NODE) return false;
15142
- const display = window.getComputedStyle(node).display;
15058
+ const display = globalThis.getComputedStyle(node).display;
15143
15059
  return display === "block" || display === "list-item" || display === "table-cell";
15144
15060
  }
15145
15061
  /** Applies block rule on Space key. Returns true if a rule fired. */
@@ -15170,7 +15086,7 @@
15170
15086
  }
15171
15087
  ];
15172
15088
  for (const { re, handler } of blockPatterns) {
15173
- const m = text.match(re);
15089
+ const m = re.exec(text);
15174
15090
  if (m) {
15175
15091
  handler(m);
15176
15092
  return true;
@@ -15194,8 +15110,8 @@
15194
15110
  return false;
15195
15111
  }
15196
15112
  _selectLineAndDelete() {
15197
- const sel = window.getSelection();
15198
- if (!sel || !sel.rangeCount) return;
15113
+ const sel = globalThis.getSelection();
15114
+ if (!sel?.rangeCount) return;
15199
15115
  const range = sel.getRangeAt(0);
15200
15116
  const startRange = document.createRange();
15201
15117
  startRange.setStart(range.startContainer.parentNode || range.startContainer, 0);
@@ -15233,8 +15149,8 @@
15233
15149
  this.context.triggerEvent("change", this.context.getHTML());
15234
15150
  }
15235
15151
  _onInput() {
15236
- const sel = window.getSelection();
15237
- if (!sel || !sel.rangeCount) return;
15152
+ const sel = globalThis.getSelection();
15153
+ if (!sel?.rangeCount) return;
15238
15154
  const range = sel.getRangeAt(0);
15239
15155
  if (!range.collapsed) return;
15240
15156
  if (!this.context.layoutInfo.editable.contains(range.startContainer)) return;
@@ -15262,7 +15178,7 @@
15262
15178
  ];
15263
15179
  const upToCursor = text.slice(0, offset);
15264
15180
  for (const { re, tag } of inlineRules) {
15265
- const m = upToCursor.match(re);
15181
+ const m = re.exec(upToCursor);
15266
15182
  if (!m) continue;
15267
15183
  const matchStart = upToCursor.length - m[0].length;
15268
15184
  const matchEnd = offset;
@@ -15273,11 +15189,8 @@
15273
15189
  el.textContent = innerText;
15274
15190
  const beforeNode = document.createTextNode(before);
15275
15191
  const afterNode = document.createTextNode("​" + after);
15276
- const parent = node.parentNode;
15277
- parent.insertBefore(beforeNode, node);
15278
- parent.insertBefore(el, node);
15279
- parent.insertBefore(afterNode, node);
15280
- parent.removeChild(node);
15192
+ /** @type {ChildNode} */ node.before(beforeNode, el, afterNode);
15193
+ /** @type {ChildNode} */ node.remove();
15281
15194
  const newRange = document.createRange();
15282
15195
  newRange.setStart(afterNode, 1);
15283
15196
  newRange.collapse(true);
@@ -15348,12 +15261,12 @@
15348
15261
  strikethrough: (ctx) => ctx.invoke("editor.strikethrough"),
15349
15262
  link: (ctx) => ctx.invoke("linkDialog.show"),
15350
15263
  removeFormat: (ctx) => {
15351
- const editable = ctx.layoutInfo && ctx.layoutInfo.editable;
15264
+ const editable = ctx.layoutInfo?.editable;
15352
15265
  if (!editable) return;
15353
15266
  editable.focus();
15354
15267
  document.execCommand("removeFormat");
15355
- const sel = window.getSelection();
15356
- if (sel && sel.rangeCount > 0 && !sel.getRangeAt(0).collapsed) {
15268
+ const sel = globalThis.getSelection();
15269
+ if (sel?.rangeCount > 0 && !sel.getRangeAt(0).collapsed) {
15357
15270
  const range = sel.getRangeAt(0);
15358
15271
  const ancestor = range.commonAncestorContainer;
15359
15272
  const root = ancestor.nodeType === 1 ? ancestor : ancestor.parentElement;
@@ -15411,15 +15324,15 @@
15411
15324
  const d6 = this.context.on("contextMenu:hide", () => {
15412
15325
  this._contextMenuOpen = false;
15413
15326
  });
15414
- const d7 = on(window, "scroll", () => this._hide(), { passive: true });
15415
- const d8 = on(window, "resize", () => this._hide(), { passive: true });
15327
+ const d7 = on(globalThis, "scroll", () => this._hide(), { passive: true });
15328
+ const d8 = on(globalThis, "resize", () => this._hide(), { passive: true });
15416
15329
  this._disposers.push(d1, d2, d3, d4, d5, d6, d7, d8);
15417
15330
  return this;
15418
15331
  }
15419
15332
  destroy() {
15420
- if (this._el && this._el.parentNode) this._el.parentNode.removeChild(this._el);
15333
+ this._el?.remove();
15421
15334
  this._el = null;
15422
- if (this._picker && this._picker.parentNode) this._picker.parentNode.removeChild(this._picker);
15335
+ this._picker?.remove();
15423
15336
  this._picker = null;
15424
15337
  this._disposers.forEach((d) => d());
15425
15338
  this._disposers = [];
@@ -15533,15 +15446,15 @@
15533
15446
  pickerAny._colorInput = colorInput;
15534
15447
  }
15535
15448
  _openColorPicker(type, anchorBtn) {
15536
- const sel = window.getSelection();
15537
- if (sel && sel.rangeCount > 0) this._savedRange = sel.getRangeAt(0).cloneRange();
15449
+ const sel = globalThis.getSelection();
15450
+ if (sel?.rangeCount > 0) this._savedRange = sel.getRangeAt(0).cloneRange();
15538
15451
  this._pickerType = type;
15539
15452
  const pickerAny = this._picker;
15540
15453
  const palette = pickerAny._paletteEl;
15541
15454
  const noColorBtn = pickerAny._noColorBtn;
15542
15455
  if (type === "hiliteColor") {
15543
15456
  if (!palette.contains(noColorBtn)) palette.appendChild(noColorBtn);
15544
- } else if (palette.contains(noColorBtn)) palette.removeChild(noColorBtn);
15457
+ } else if (palette.contains(noColorBtn)) noColorBtn.remove();
15545
15458
  /** @type {any} */ this._picker._colorInput.value = type === "foreColor" ? "#000000" : "#ffff00";
15546
15459
  this._picker.style.display = "block";
15547
15460
  const pw = this._picker.offsetWidth;
@@ -15550,7 +15463,7 @@
15550
15463
  let top = toolbarRect.top - ph - 6;
15551
15464
  if (top < 8) top = toolbarRect.bottom + 6;
15552
15465
  let left = anchorBtn.getBoundingClientRect().left;
15553
- left = Math.max(8, Math.min(left, window.innerWidth - pw - 8));
15466
+ left = Math.max(8, Math.min(left, globalThis.innerWidth - pw - 8));
15554
15467
  this._picker.style.left = `${left}px`;
15555
15468
  this._picker.style.top = `${top}px`;
15556
15469
  }
@@ -15560,10 +15473,10 @@
15560
15473
  }
15561
15474
  /** Restore the saved selection, apply execCommand, update the color strip, then close the picker. */
15562
15475
  _applyColor(type, color) {
15563
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
15476
+ const editable = this.context.layoutInfo?.editable;
15564
15477
  if (!editable || !this._savedRange) return;
15565
15478
  editable.focus();
15566
- const sel = window.getSelection();
15479
+ const sel = globalThis.getSelection();
15567
15480
  sel.removeAllRanges();
15568
15481
  try {
15569
15482
  sel.addRange(this._savedRange.cloneRange());
@@ -15574,8 +15487,7 @@
15574
15487
  if (!document.execCommand(cmd, false, color) && cmd === "hiliteColor") document.execCommand("backColor", false, color);
15575
15488
  this.context.invoke("editor.afterCommand");
15576
15489
  const name = type === "hiliteColor" ? "hiliteColor" : "foreColor";
15577
- const btn = this._el && this._el.querySelector(`[data-name="${name}"]`);
15578
- const strip = btn && btn.querySelector(".an-bubble-color-strip");
15490
+ const strip = (this._el?.querySelector(`[data-name="${name}"]`))?.querySelector(".an-bubble-color-strip");
15579
15491
  if (strip) /** @type {HTMLElement} */ strip.style.background = color === "transparent" ? "transparent" : color;
15580
15492
  this._closeColorPicker();
15581
15493
  this._syncActive();
@@ -15590,14 +15502,14 @@
15590
15502
  const gap = 8;
15591
15503
  let left = rect.left + rect.width / 2 - bw / 2;
15592
15504
  let top = rect.top - bh - gap;
15593
- left = Math.max(8, Math.min(left, window.innerWidth - bw - 8));
15505
+ left = Math.max(8, Math.min(left, globalThis.innerWidth - bw - 8));
15594
15506
  if (top < 8) top = rect.bottom + gap;
15595
15507
  const tableTooltipEl = document.querySelector(".an-table-tooltip");
15596
15508
  if (tableTooltipEl && tableTooltipEl.style.display !== "none") {
15597
15509
  const ttRect = tableTooltipEl.getBoundingClientRect();
15598
15510
  if (top < ttRect.bottom + gap && top + bh > ttRect.top - gap) {
15599
15511
  top = rect.bottom + gap;
15600
- if (top + bh > window.innerHeight - 8) top = ttRect.bottom + gap;
15512
+ if (top + bh > globalThis.innerHeight - 8) top = ttRect.bottom + gap;
15601
15513
  }
15602
15514
  }
15603
15515
  el.style.top = `${top}px`;
@@ -15623,17 +15535,15 @@
15623
15535
  /** Read the current selection's color and update the color-strip indicators. */
15624
15536
  _syncColorStrips() {
15625
15537
  if (!this._el) return;
15626
- const sel = window.getSelection();
15538
+ const sel = globalThis.getSelection();
15627
15539
  if (!sel || !sel.rangeCount) return;
15628
15540
  let node = sel.getRangeAt(0).startContainer;
15629
15541
  if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
15630
15542
  if (!node) return;
15631
- const cs = window.getComputedStyle(node);
15632
- const foreBtn = this._el.querySelector("[data-name=\"foreColor\"]");
15633
- const foreStrip = foreBtn && foreBtn.querySelector(".an-bubble-color-strip");
15543
+ const cs = globalThis.getComputedStyle(node);
15544
+ const foreStrip = this._el.querySelector("[data-name=\"foreColor\"]")?.querySelector(".an-bubble-color-strip");
15634
15545
  if (foreStrip) /** @type {HTMLElement} */ foreStrip.style.background = cs.color || "#000000";
15635
- const hiliteBtn = this._el.querySelector("[data-name=\"hiliteColor\"]");
15636
- const hiliteStrip = hiliteBtn && hiliteBtn.querySelector(".an-bubble-color-strip");
15546
+ const hiliteStrip = this._el.querySelector("[data-name=\"hiliteColor\"]")?.querySelector(".an-bubble-color-strip");
15637
15547
  if (hiliteStrip) {
15638
15548
  const bg = cs.backgroundColor;
15639
15549
  /** @type {HTMLElement} */ hiliteStrip.style.background = !bg || bg === "rgba(0, 0, 0, 0)" || bg === "transparent" ? "transparent" : bg;
@@ -15644,7 +15554,7 @@
15644
15554
  this._rafId = requestAnimationFrame(() => {
15645
15555
  if (this._contextMenuOpen) return;
15646
15556
  if (this._picker && this._picker.style.display !== "none") return;
15647
- const sel = window.getSelection();
15557
+ const sel = globalThis.getSelection();
15648
15558
  if (!sel || sel.isCollapsed || !sel.rangeCount) {
15649
15559
  this._hide();
15650
15560
  return;
@@ -15667,8 +15577,8 @@
15667
15577
  }
15668
15578
  _onMousedown(e) {
15669
15579
  if (!this._visible) return;
15670
- if (this._el && this._el.contains(e.target)) return;
15671
- if (this._picker && this._picker.contains(e.target)) return;
15580
+ if (this._el?.contains(e.target)) return;
15581
+ if (this._picker?.contains(e.target)) return;
15672
15582
  if (this.context.layoutInfo.editable.contains(e.target)) return;
15673
15583
  this._hide();
15674
15584
  }
@@ -15753,7 +15663,7 @@
15753
15663
  }
15754
15664
  destroy() {
15755
15665
  clearTimeout(this._debounceTimer);
15756
- if (this._dropdown && this._dropdown.parentNode) this._dropdown.parentNode.removeChild(this._dropdown);
15666
+ this._dropdown?.remove();
15757
15667
  this._dropdown = null;
15758
15668
  this._disposers.forEach((d) => d());
15759
15669
  this._disposers = [];
@@ -15817,8 +15727,8 @@
15817
15727
  const ddw = dd.offsetWidth;
15818
15728
  let top = rect.bottom + 4;
15819
15729
  let left = rect.left;
15820
- if (rect.bottom + ddh + 8 > window.innerHeight) top = rect.top - ddh - 4;
15821
- left = Math.max(8, Math.min(left, window.innerWidth - ddw - 8));
15730
+ if (rect.bottom + ddh + 8 > globalThis.innerHeight) top = rect.top - ddh - 4;
15731
+ left = Math.max(8, Math.min(left, globalThis.innerWidth - ddw - 8));
15822
15732
  dd.style.top = `${top}px`;
15823
15733
  dd.style.left = `${left}px`;
15824
15734
  dd.style.visibility = "";
@@ -15842,7 +15752,7 @@
15842
15752
  * collapsed range is reliable at this point but often empty inside async callbacks.
15843
15753
  */
15844
15754
  _captureCaretRect() {
15845
- if (this._triggerNode && this._triggerNode.isConnected) try {
15755
+ if (this._triggerNode?.isConnected) try {
15846
15756
  const r = document.createRange();
15847
15757
  const end = Math.min(this._triggerOffset + 1, this._triggerNode.textContent.length);
15848
15758
  r.setStart(this._triggerNode, this._triggerOffset);
@@ -15853,13 +15763,13 @@
15853
15763
  return;
15854
15764
  }
15855
15765
  } catch (_) {}
15856
- const sel = window.getSelection();
15766
+ const sel = globalThis.getSelection();
15857
15767
  if (!sel || !sel.rangeCount) return;
15858
15768
  const rects = sel.getRangeAt(0).getClientRects();
15859
15769
  if (rects.length > 0) this._caretRect = rects[rects.length - 1];
15860
15770
  }
15861
15771
  _getQueryAtCursor() {
15862
- const sel = window.getSelection();
15772
+ const sel = globalThis.getSelection();
15863
15773
  if (!sel || !sel.rangeCount) return null;
15864
15774
  const range = sel.getRangeAt(0);
15865
15775
  if (!range.collapsed) return null;
@@ -15916,7 +15826,7 @@
15916
15826
  }
15917
15827
  _onDocClick(e) {
15918
15828
  if (!this._open) return;
15919
- if (this._dropdown && this._dropdown.contains(e.target)) return;
15829
+ if (this._dropdown?.contains(e.target)) return;
15920
15830
  this._hideDropdown();
15921
15831
  }
15922
15832
  _select(index) {
@@ -15925,7 +15835,7 @@
15925
15835
  if (this._triggerNode) {
15926
15836
  const node = this._triggerNode;
15927
15837
  node.textContent = node.textContent.slice(0, this._triggerOffset) + node.textContent.slice(this._triggerOffset + this._cfg.trigger.length + this._query.length);
15928
- const sel = window.getSelection();
15838
+ const sel = globalThis.getSelection();
15929
15839
  const range = document.createRange();
15930
15840
  range.setStart(node, this._triggerOffset);
15931
15841
  range.collapse(true);
@@ -16028,7 +15938,7 @@
16028
15938
  register("markdownShortcuts", MarkdownShortcuts);
16029
15939
  register("bubbleToolbar", BubbleToolbar);
16030
15940
  register("mention", Mention);
16031
- for (const [name, ModuleClass] of _customModules) register(name, ModuleClass);
15941
+ if (_customModules.size > 0) for (const [name, ModuleClass] of _customModules) register(name, ModuleClass);
16032
15942
  }
16033
15943
  /**
16034
15944
  * Registers and initialises a custom module on this instance.
@@ -16081,6 +15991,7 @@
16081
15991
  });
16082
15992
  }
16083
15993
  _applyGlobalPlugins() {
15994
+ if (_globalPlugins.size === 0) return;
16084
15995
  for (const { plugin, options } of _globalPlugins.values()) this._installPlugin(plugin, options);
16085
15996
  }
16086
15997
  _bindEditorEvents(editable) {
@@ -16286,23 +16197,27 @@
16286
16197
  a.style.display = "none";
16287
16198
  document.body.appendChild(a);
16288
16199
  a.click();
16289
- document.body.removeChild(a);
16200
+ a.remove();
16290
16201
  URL.revokeObjectURL(url);
16291
16202
  }
16292
16203
  /**
16293
- * Opens the editor content in a new window and triggers the browser print dialog.
16204
+ * Opens the editor content in a new globalThis and triggers the browser print dialog.
16294
16205
  * @param {string} [title='']
16295
16206
  */
16296
16207
  print(title = "") {
16297
16208
  const content = this.getHTML();
16298
- const safeTitle = (title || "").replace(/</g, "&lt;").replace(/>/g, "&gt;");
16299
- const w = window.open("", "_blank");
16300
- if (!w) return;
16301
- w.document.write(`<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>${safeTitle}</title><style>body{font-family:system-ui,-apple-system,"Segoe UI",Roboto,Arial,sans-serif;font-size:14px;line-height:1.6;padding:20mm;color:#111827;}ul.an-checklist{list-style:none;padding-left:0;}ul.an-checklist li{padding-left:24px;position:relative;margin:2px 0;}ul.an-checklist li input[type="checkbox"]{position:absolute;left:0;top:3px;}code{background:#f3f4f6;border-radius:3px;padding:.1em .35em;font-family:monospace;}pre{background:#f3f4f6;padding:.75em 1em;border-radius:4px;overflow-x:auto;}table{border-collapse:collapse;}td,th{border:1px solid #d1d5db;padding:4px 8px;}</style></head><body>${content}</body></html>`);
16302
- w.document.close();
16303
- w.onload = () => {
16209
+ const markup = `<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>${(title || "").replace(/[<>&"']/g, (c) => `&#${c.charCodeAt(0)};`)}</title><style>body{font-family:system-ui,-apple-system,"Segoe UI",Roboto,Arial,sans-serif;font-size:14px;line-height:1.6;padding:20mm;color:#111827;}ul.an-checklist{list-style:none;padding-left:0;}ul.an-checklist li{padding-left:24px;position:relative;margin:2px 0;}ul.an-checklist li input[type="checkbox"]{position:absolute;left:0;top:3px;}code{background:#f3f4f6;border-radius:3px;padding:.1em .35em;font-family:monospace;}pre{background:#f3f4f6;padding:.75em 1em;border-radius:4px;overflow-x:auto;}table{border-collapse:collapse;}td,th{border:1px solid #d1d5db;padding:4px 8px;}</style></head><body>${content}</body></html>`;
16210
+ const blob = new Blob([markup], { type: "text/html" });
16211
+ const url = URL.createObjectURL(blob);
16212
+ const w = globalThis.open(url, "_blank");
16213
+ if (!w) {
16214
+ URL.revokeObjectURL(url);
16215
+ return;
16216
+ }
16217
+ w.addEventListener("load", () => {
16304
16218
  w.print();
16305
- };
16219
+ URL.revokeObjectURL(url);
16220
+ });
16306
16221
  }
16307
16222
  /**
16308
16223
  * Sets whether the editor is disabled (readonly).
@@ -16340,10 +16255,10 @@
16340
16255
  this._disposers.forEach((d) => d());
16341
16256
  this._disposers = [];
16342
16257
  const container = this.layoutInfo.container;
16343
- const wasDark = container && container.classList.contains("an-theme-dark");
16344
- if (container && container.parentNode) {
16258
+ const wasDark = container?.classList.contains("an-theme-dark");
16259
+ if (container?.parentNode) {
16345
16260
  this.targetEl.style.display = "";
16346
- container.parentNode.removeChild(container);
16261
+ container.remove();
16347
16262
  }
16348
16263
  if (wasDark && !document.querySelector(".an-container.an-theme-dark")) document.body.classList.remove("an-theme-dark");
16349
16264
  if (typeof this.options.onDestroy === "function") this.options.onDestroy(this);
@@ -16365,7 +16280,7 @@
16365
16280
  * Inspired by Summernote's env.js
16366
16281
  */
16367
16282
  var userAgent = navigator.userAgent;
16368
- /Chrome\//.test(userAgent), /Firefox\//.test(userAgent), /^((?!chrome|android).)*safari/i.test(userAgent), /Edg\//.test(userAgent), /Macintosh/.test(userAgent), /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent), "ontouchstart" in window || navigator.maxTouchPoints, /Macintosh/.test(userAgent);
16283
+ /Chrome\//.test(userAgent), /Firefox\//.test(userAgent), /^((?!chrome|android).)*safari/i.test(userAgent), /Edg\//.test(userAgent), /Macintosh/.test(userAgent), /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent), "ontouchstart" in globalThis || navigator.maxTouchPoints, /Macintosh/.test(userAgent);
16369
16284
  //#endregion
16370
16285
  //#region src/js/index.js
16371
16286
  var _originalDefaults = { ...defaultOptions };
@@ -16473,7 +16388,7 @@
16473
16388
  return this;
16474
16389
  },
16475
16390
  /** Library version */
16476
- version: "1.5.0"
16391
+ version: "1.6.2"
16477
16392
  };
16478
16393
  /**
16479
16394
  * @param {string|Element|NodeList|Element[]} selector