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
@@ -29,7 +29,7 @@ function debounce(fn, delay) {
29
29
  /**
30
30
  * Create a wrapper that limits how often `fn` can be invoked while ensuring the last call in a burst is executed.
31
31
  * @param {Function} fn - Function to be throttled.
32
- * @param {number} limit - Time window in milliseconds during which at most one call is allowed.
32
+ * @param {number} limit - Time globalThis in milliseconds during which at most one call is allowed.
33
33
  * @returns {Function} A wrapper function that invokes `fn` at most once per `limit` milliseconds; calls preserve `this` and original arguments and schedule a trailing invocation for the final call in a burst.
34
34
  */
35
35
  function throttle(fn, limit) {
@@ -252,7 +252,8 @@ function createElement(tag, attrs = {}, childNodes = []) {
252
252
  * @param {Node} node
253
253
  */
254
254
  function remove(node) {
255
- if (node && node.parentNode) node.parentNode.removeChild(node);
255
+ if (node && node.parentNode)
256
+ /** @type {ChildNode} */ node.remove();
256
257
  }
257
258
  /**
258
259
  * Unwraps a node — replaces the node with its children.
@@ -262,7 +263,7 @@ function unwrap(node) {
262
263
  const parent = node.parentNode;
263
264
  if (!parent) return;
264
265
  while (node.firstChild) parent.insertBefore(node.firstChild, node);
265
- parent.removeChild(node);
266
+ /** @type {ChildNode} */ node.remove();
266
267
  }
267
268
  /**
268
269
  * Wraps a node with a wrapper element.
@@ -321,7 +322,7 @@ function placeCaret(el) {
321
322
  const range = document.createRange();
322
323
  range.selectNodeContents(el);
323
324
  range.collapse(false);
324
- const sel = window.getSelection();
325
+ const sel = globalThis.getSelection();
325
326
  if (sel) {
326
327
  sel.removeAllRanges();
327
328
  sel.addRange(range);
@@ -364,14 +365,14 @@ function trapFocus(container, onEscape) {
364
365
  const handler = (e) => {
365
366
  if (e.key === "Escape") {
366
367
  e.stopPropagation();
367
- onEscape && onEscape();
368
+ onEscape?.();
368
369
  return;
369
370
  }
370
371
  if (e.key !== "Tab") return;
371
372
  const els = getFocusable();
372
373
  if (!els.length) return;
373
374
  const first = els[0];
374
- const last = els[els.length - 1];
375
+ const last = els.at(-1);
375
376
  if (e.shiftKey) {
376
377
  if (document.activeElement === first) {
377
378
  e.preventDefault();
@@ -409,14 +410,14 @@ function makeDraggable(handle, box) {
409
410
  box.style.top = `${r.top}px`;
410
411
  box.dataset.anDragPinned = "1";
411
412
  }
412
- const startX = e.clientX - parseFloat(box.style.left);
413
- const startY = e.clientY - parseFloat(box.style.top);
413
+ const startX = e.clientX - Number.parseFloat(box.style.left);
414
+ const startY = e.clientY - Number.parseFloat(box.style.top);
414
415
  handle.style.cursor = "grabbing";
415
416
  const onMove = (ev) => {
416
417
  const bw = box.offsetWidth;
417
418
  const bh = box.offsetHeight;
418
- box.style.left = `${Math.max(0, Math.min(ev.clientX - startX, window.innerWidth - bw))}px`;
419
- box.style.top = `${Math.max(0, Math.min(ev.clientY - startY, window.innerHeight - bh))}px`;
419
+ box.style.left = `${Math.max(0, Math.min(ev.clientX - startX, globalThis.innerWidth - bw))}px`;
420
+ box.style.top = `${Math.max(0, Math.min(ev.clientY - startY, globalThis.innerHeight - bh))}px`;
420
421
  };
421
422
  const onUp = () => {
422
423
  handle.style.cursor = "grab";
@@ -462,10 +463,10 @@ var WrappedRange = class {
462
463
  return range;
463
464
  }
464
465
  /**
465
- * Select this wrapped range in the window.
466
+ * Select this wrapped range in the globalThis.
466
467
  */
467
468
  select() {
468
- const sel = window.getSelection();
469
+ const sel = globalThis.getSelection();
469
470
  if (!sel) return;
470
471
  sel.removeAllRanges();
471
472
  sel.addRange(this.toNativeRange());
@@ -518,13 +519,13 @@ function fromNativeRange(range) {
518
519
  return new WrappedRange(range.startContainer, range.startOffset, range.endContainer, range.endOffset);
519
520
  }
520
521
  /**
521
- * Returns a WrappedRange for the current window selection,
522
+ * Returns a WrappedRange for the current globalThis selection,
522
523
  * optionally restricted to a given editable element.
523
524
  * @param {HTMLElement} [editable]
524
525
  * @returns {WrappedRange|null}
525
526
  */
526
527
  function currentRange(editable) {
527
- const sel = window.getSelection();
528
+ const sel = globalThis.getSelection();
528
529
  if (!sel || sel.rangeCount === 0) return null;
529
530
  const native = sel.getRangeAt(0);
530
531
  if (editable && !editable.contains(native.commonAncestorContainer)) return null;
@@ -553,7 +554,7 @@ function collapsedRange(node, offset = 0) {
553
554
  * @returns {boolean}
554
555
  */
555
556
  function isSelectionInside(el) {
556
- const sel = window.getSelection();
557
+ const sel = globalThis.getSelection();
557
558
  if (!sel || sel.rangeCount === 0) return false;
558
559
  return el.contains(sel.getRangeAt(0).commonAncestorContainer);
559
560
  }
@@ -562,7 +563,7 @@ function isSelectionInside(el) {
562
563
  * @param {Function} fn
563
564
  */
564
565
  function withSavedRange(fn) {
565
- const sel = window.getSelection();
566
+ const sel = globalThis.getSelection();
566
567
  if (!sel || sel.rangeCount === 0) {
567
568
  fn(null);
568
569
  return;
@@ -606,16 +607,16 @@ var italic = () => execCommand("italic");
606
607
  * execCommand's state detection is unreliable.
607
608
  */
608
609
  function underline() {
609
- const sel = window.getSelection();
610
+ const sel = globalThis.getSelection();
610
611
  if (!sel || !sel.rangeCount) return;
611
612
  let container = sel.getRangeAt(0).commonAncestorContainer;
612
613
  if (container.nodeType === 3) container = container.parentElement;
613
- const uEl = container && container.closest("u");
614
+ const uEl = container?.closest("u");
614
615
  const nativeState = document.queryCommandState("underline");
615
616
  if (uEl && !nativeState) {
616
617
  const parent = uEl.parentNode;
617
618
  while (uEl.firstChild) parent.insertBefore(uEl.firstChild, uEl);
618
- parent.removeChild(uEl);
619
+ uEl.remove();
619
620
  return;
620
621
  }
621
622
  execCommand("underline");
@@ -626,16 +627,16 @@ function underline() {
626
627
  * execCommand's state detection is unreliable (mirrors underline() logic).
627
628
  */
628
629
  function strikethrough() {
629
- const sel = window.getSelection();
630
+ const sel = globalThis.getSelection();
630
631
  if (!sel || !sel.rangeCount) return;
631
632
  let sc = sel.getRangeAt(0).startContainer;
632
633
  if (sc.nodeType === 3) sc = sc.parentElement;
633
- const sEl = sc && (sc.closest("s") || sc.closest("strike"));
634
+ const sEl = sc?.closest("s") || sc?.closest("strike");
634
635
  const nativeState = document.queryCommandState("strikeThrough");
635
636
  if (sEl && !nativeState) {
636
637
  const parent = sEl.parentNode;
637
638
  while (sEl.firstChild) parent.insertBefore(sEl.firstChild, sEl);
638
- parent.removeChild(sEl);
639
+ sEl.remove();
639
640
  return;
640
641
  }
641
642
  execCommand("strikeThrough");
@@ -670,7 +671,7 @@ var fontName = (name) => execCommand("fontName", name);
670
671
  * @param {HTMLElement|Document} [editable] - scoping element to avoid touching nodes outside this editor
671
672
  */
672
673
  function fontSize(size, editable = document) {
673
- const sel = window.getSelection();
674
+ const sel = globalThis.getSelection();
674
675
  const wasCollapsed = !sel || !sel.rangeCount || sel.getRangeAt(0).collapsed;
675
676
  if (wasCollapsed && sel && sel.rangeCount > 0) {
676
677
  try {
@@ -696,12 +697,12 @@ function fontSize(size, editable = document) {
696
697
  span.style.fontSize = size;
697
698
  el.parentNode.insertBefore(span, el);
698
699
  while (el.firstChild) span.appendChild(el.firstChild);
699
- el.parentNode.removeChild(el);
700
+ el.remove();
700
701
  newSpans.push(span);
701
702
  });
702
703
  if (!wasCollapsed && sel && newSpans.length > 0) {
703
704
  const first = newSpans[0];
704
- const last = newSpans[newSpans.length - 1];
705
+ const last = newSpans.at(-1);
705
706
  try {
706
707
  const nr = document.createRange();
707
708
  const startNode = first.firstChild || first;
@@ -745,11 +746,11 @@ var indent = () => execCommand("indent");
745
746
  * (which would destroy the ul > li checklist structure).
746
747
  */
747
748
  function outdent() {
748
- const sel = window.getSelection();
749
+ const sel = globalThis.getSelection();
749
750
  if (sel && sel.rangeCount) {
750
751
  let container = sel.getRangeAt(0).commonAncestorContainer;
751
752
  if (container.nodeType === 3) container = container.parentElement;
752
- const checkLi = container && container.closest(".an-checklist li");
753
+ const checkLi = container?.closest(".an-checklist li");
753
754
  if (checkLi) {
754
755
  _checklistItemToP(checkLi);
755
756
  return;
@@ -779,7 +780,7 @@ function _checklistItemToP(checkLi) {
779
780
  if (child.nodeType === 1 && child.tagName === "INPUT") continue;
780
781
  p.appendChild(child.cloneNode(true));
781
782
  }
782
- p.innerHTML = p.innerHTML.replace(/\u200B/g, "");
783
+ p.innerHTML = p.innerHTML.replaceAll("​", "");
783
784
  if (!p.hasChildNodes() || !p.textContent.trim()) {
784
785
  p.innerHTML = "";
785
786
  p.appendChild(document.createTextNode("\xA0"));
@@ -791,14 +792,14 @@ function _checklistItemToP(checkLi) {
791
792
  checkUl.parentNode.insertBefore(newUl, checkUl.nextSibling);
792
793
  }
793
794
  checkUl.parentNode.insertBefore(p, checkUl.nextSibling);
794
- checkUl.removeChild(checkLi);
795
- if (checkUl.children.length === 0) checkUl.parentNode.removeChild(checkUl);
795
+ checkLi.remove();
796
+ if (checkUl.children.length === 0) checkUl.remove();
796
797
  try {
797
798
  const nr = document.createRange();
798
799
  const firstChild = p.firstChild;
799
800
  nr.setStart(firstChild && firstChild.nodeType === 3 ? firstChild : p, 0);
800
801
  nr.collapse(true);
801
- const s = window.getSelection();
802
+ const s = globalThis.getSelection();
802
803
  if (s) {
803
804
  s.removeAllRanges();
804
805
  s.addRange(nr);
@@ -822,7 +823,7 @@ var insertOrderedList = () => execCommand("insertOrderedList");
822
823
  * @param {string} value - Line-height value to apply; typically a unitless multiplier (for example, "1.5").
823
824
  */
824
825
  function lineHeight(value) {
825
- const sel = window.getSelection();
826
+ const sel = globalThis.getSelection();
826
827
  if (!sel || sel.rangeCount === 0) return;
827
828
  const range = sel.getRangeAt(0);
828
829
  const BLOCK_TAGS = new Set([
@@ -874,22 +875,22 @@ function lineHeight(value) {
874
875
  * @param {HTMLElement} [_editable]
875
876
  */
876
877
  function toggleInlineCode(_editable) {
877
- const sel = window.getSelection();
878
+ const sel = globalThis.getSelection();
878
879
  if (!sel || !sel.rangeCount) return;
879
880
  const range = sel.getRangeAt(0);
880
881
  let container = range.commonAncestorContainer;
881
882
  if (container.nodeType === 3) container = container.parentElement;
882
- const codeEl = container && container.closest("code");
883
+ const codeEl = container?.closest("code");
883
884
  if (codeEl && !codeEl.closest("pre")) {
884
885
  const parent = codeEl.parentNode;
885
886
  const prevSibling = codeEl.previousSibling;
886
887
  const movedChildren = Array.from(codeEl.childNodes);
887
888
  while (codeEl.firstChild) parent.insertBefore(codeEl.firstChild, codeEl);
888
- parent.removeChild(codeEl);
889
- if (parent && parent.normalize) parent.normalize();
889
+ codeEl.remove();
890
+ parent?.normalize();
890
891
  if (movedChildren.length > 0) try {
891
892
  const firstMoved = movedChildren[0];
892
- const lastMoved = movedChildren[movedChildren.length - 1];
893
+ const lastMoved = movedChildren.at(-1);
893
894
  const nr = document.createRange();
894
895
  const anchorNode = firstMoved.parentNode === parent ? firstMoved : prevSibling ? prevSibling.nextSibling : parent.firstChild;
895
896
  if (anchorNode) {
@@ -930,11 +931,11 @@ function toggleInlineCode(_editable) {
930
931
  * @returns {boolean}
931
932
  */
932
933
  function isInlineCode() {
933
- const sel = window.getSelection();
934
+ const sel = globalThis.getSelection();
934
935
  if (!sel || !sel.rangeCount) return false;
935
936
  let sc = sel.getRangeAt(0).startContainer;
936
937
  if (sc.nodeType === 3) sc = sc.parentElement;
937
- const code = sc && sc.closest("code");
938
+ const code = sc?.closest("code");
938
939
  return !!(code && !code.closest("pre"));
939
940
  }
940
941
  /**
@@ -952,12 +953,12 @@ function isInlineCode() {
952
953
  * Empty or whitespace-only selections do not create a checklist.
953
954
  */
954
955
  function toggleChecklist() {
955
- const sel = window.getSelection();
956
+ const sel = globalThis.getSelection();
956
957
  if (!sel || !sel.rangeCount) return;
957
958
  const range = sel.getRangeAt(0);
958
959
  let container = range.commonAncestorContainer;
959
960
  if (container.nodeType === 3) container = container.parentElement;
960
- const ul = container && container.closest(".an-checklist");
961
+ const ul = container?.closest(".an-checklist");
961
962
  if (ul) {
962
963
  const selectedLis = Array.from(ul.querySelectorAll("li")).filter((li) => sel.containsNode(li, true));
963
964
  if (selectedLis.length > 0) {
@@ -968,14 +969,14 @@ function toggleChecklist() {
968
969
  if (child.nodeType === 1 && child.tagName === "INPUT") continue;
969
970
  p.appendChild(child.cloneNode(true));
970
971
  }
971
- p.innerHTML = p.innerHTML.replace(/\u200b/g, "");
972
+ p.innerHTML = p.innerHTML.replaceAll("​", "");
972
973
  if (!p.hasChildNodes() || !p.textContent.trim()) {
973
974
  p.innerHTML = "";
974
975
  p.appendChild(document.createTextNode("\xA0"));
975
976
  }
976
977
  ul.parentNode.insertBefore(p, ul);
977
978
  if (!firstP) firstP = p;
978
- ul.removeChild(li);
979
+ li.remove();
979
980
  });
980
981
  if (ul.children.length === 0) ul.remove();
981
982
  if (firstP) {
@@ -1003,7 +1004,7 @@ function toggleChecklist() {
1003
1004
  ]);
1004
1005
  let block = container;
1005
1006
  while (block && block.parentNode && !BLOCK_TAGS.has(block.tagName)) block = block.parentNode;
1006
- const itemText = block && BLOCK_TAGS.has(block.tagName) ? Array.from(block.childNodes).map((n) => n.textContent).join("").replace(/\u00a0/g, " ") : "";
1007
+ const itemText = block && BLOCK_TAGS.has(block.tagName) ? Array.from(block.childNodes).map((n) => n.textContent).join("").replaceAll("\xA0", " ") : "";
1007
1008
  const ul = document.createElement("ul");
1008
1009
  ul.className = "an-checklist";
1009
1010
  const li = document.createElement("li");
@@ -1074,7 +1075,7 @@ function toggleChecklist() {
1074
1075
  });
1075
1076
  const firstBlock = blocks[0];
1076
1077
  firstBlock.parentNode.insertBefore(newUl, firstBlock);
1077
- blocks.forEach((block) => block.parentNode && block.parentNode.removeChild(block));
1078
+ blocks.forEach((block) => block.remove());
1078
1079
  if (lastTextNode) {
1079
1080
  const nr = document.createRange();
1080
1081
  nr.setStart(lastTextNode, lastTextNode.textContent.length);
@@ -1088,11 +1089,11 @@ function toggleChecklist() {
1088
1089
  * @returns {boolean}
1089
1090
  */
1090
1091
  function isInChecklist() {
1091
- const sel = window.getSelection();
1092
+ const sel = globalThis.getSelection();
1092
1093
  if (!sel || !sel.rangeCount) return false;
1093
1094
  let container = sel.getRangeAt(0).commonAncestorContainer;
1094
1095
  if (container.nodeType === 3) container = container.parentElement;
1095
- return !!(container && container.closest(".an-checklist li"));
1096
+ return !!container?.closest(".an-checklist li");
1096
1097
  }
1097
1098
  //#endregion
1098
1099
  //#region src/js/module/Buttons.js
@@ -1174,7 +1175,7 @@ var boldBtn = btn("bold", "bold", "Bold (Ctrl+B)", () => bold(), () => document.
1174
1175
  var italicBtn = btn("italic", "italic", "Italic (Ctrl+I)", () => italic(), () => document.queryCommandState("italic"));
1175
1176
  var underlineBtn = btn("underline", "underline", "Underline (Ctrl+U)", () => underline(), () => {
1176
1177
  if (document.queryCommandState("underline")) return true;
1177
- const sel = window.getSelection();
1178
+ const sel = globalThis.getSelection();
1178
1179
  if (!sel || !sel.rangeCount) return false;
1179
1180
  let sc = sel.getRangeAt(0).startContainer;
1180
1181
  if (sc.nodeType === 3) sc = sc.parentElement;
@@ -1237,7 +1238,7 @@ var fontSizeBtn = {
1237
1238
  action: (ctx, value) => fontSize(value, ctx.layoutInfo.editable),
1238
1239
  getValue: (ctx) => {
1239
1240
  try {
1240
- const sel = window.getSelection();
1241
+ const sel = globalThis.getSelection();
1241
1242
  if (sel && sel.rangeCount) {
1242
1243
  let el = sel.getRangeAt(0).startContainer;
1243
1244
  if (el && el.nodeType === 3) el = el.parentElement;
@@ -1245,7 +1246,7 @@ var fontSizeBtn = {
1245
1246
  const size = el && el.style.fontSize ? el.style.fontSize : "";
1246
1247
  if (size) return size;
1247
1248
  }
1248
- const editable = ctx && ctx.layoutInfo && ctx.layoutInfo.editable;
1249
+ const editable = ctx?.layoutInfo?.editable;
1249
1250
  if (editable) return editable.style.fontSize || "";
1250
1251
  return "";
1251
1252
  } catch {
@@ -1349,7 +1350,7 @@ var lineHeightBtn = {
1349
1350
  action: (_ctx, value) => lineHeight(value),
1350
1351
  getValue: () => {
1351
1352
  try {
1352
- const sel = window.getSelection();
1353
+ const sel = globalThis.getSelection();
1353
1354
  if (!sel || !sel.rangeCount) return "";
1354
1355
  const BLOCKS = new Set([
1355
1356
  "P",
@@ -4474,7 +4475,7 @@ function renderLayout(targetEl, options) {
4474
4475
  } catch (_) {}
4475
4476
  if (!initialContent) initialContent = targetEl.tagName === "TEXTAREA" ? (targetEl.value || "").trim() : (targetEl.innerHTML || "").trim();
4476
4477
  editable.innerHTML = sanitiseHTML(initialContent, { allowIframes: true });
4477
- const defaultFont = options.defaultFontFamily || options.fontFamilies && options.fontFamilies[0];
4478
+ const defaultFont = options.defaultFontFamily || options.fontFamilies?.[0];
4478
4479
  if (defaultFont) editable.style.fontFamily = defaultFont;
4479
4480
  if (options.defaultFontSize) editable.style.fontSize = options.defaultFontSize;
4480
4481
  if (options.height) editable.style.minHeight = `${options.height}px`;
@@ -4536,7 +4537,7 @@ var History = class {
4536
4537
  * @returns {{ start: number, end: number }|null}
4537
4538
  */
4538
4539
  _serializeSelection() {
4539
- const sel = window.getSelection();
4540
+ const sel = globalThis.getSelection();
4540
4541
  if (!sel || sel.rangeCount === 0) return null;
4541
4542
  const range = sel.getRangeAt(0);
4542
4543
  if (!this.editable.contains(range.startContainer)) return null;
@@ -4602,7 +4603,7 @@ var History = class {
4602
4603
  const range = document.createRange();
4603
4604
  range.setStart(startNode, startOff);
4604
4605
  range.setEnd(endNode, endOff);
4605
- const sel = window.getSelection();
4606
+ const sel = globalThis.getSelection();
4606
4607
  sel.removeAllRanges();
4607
4608
  sel.addRange(range);
4608
4609
  } catch (_) {
@@ -4610,7 +4611,7 @@ var History = class {
4610
4611
  const fb = document.createRange();
4611
4612
  fb.setStart(this.editable, 0);
4612
4613
  fb.collapse(true);
4613
- const s = window.getSelection();
4614
+ const s = globalThis.getSelection();
4614
4615
  if (s) {
4615
4616
  s.removeAllRanges();
4616
4617
  s.addRange(fb);
@@ -4674,8 +4675,7 @@ var History = class {
4674
4675
  recordUndo() {
4675
4676
  const current = this._serialize();
4676
4677
  const { html: tokenized } = this._tokenizeImages(current);
4677
- const prev = this.stack[this.stackOffset];
4678
- if (prev && prev.html === tokenized) return;
4678
+ if (this.stack[this.stackOffset]?.html === tokenized) return;
4679
4679
  this._savePoint();
4680
4680
  }
4681
4681
  /**
@@ -4759,7 +4759,7 @@ function createTable(cols, rows, opts = {}) {
4759
4759
  function insertTable(cols, rows, opts = {}) {
4760
4760
  if (cols <= 0 || rows <= 0) return;
4761
4761
  const table = createTable(cols, rows, opts);
4762
- const sel = window.getSelection();
4762
+ const sel = globalThis.getSelection();
4763
4763
  if (!sel || sel.rangeCount === 0) return;
4764
4764
  const range = sel.getRangeAt(0);
4765
4765
  range.deleteContents();
@@ -4777,7 +4777,7 @@ function insertTable(cols, rows, opts = {}) {
4777
4777
  "PRE"
4778
4778
  ]);
4779
4779
  let anchor = range.startContainer;
4780
- if (anchor && anchor.nodeType === 3) anchor = anchor.parentElement;
4780
+ if (anchor?.nodeType === 3) anchor = anchor.parentElement;
4781
4781
  while (anchor && !BLOCK.has(anchor.tagName?.toUpperCase()) && anchor.parentElement) anchor = anchor.parentElement;
4782
4782
  if (anchor && BLOCK.has(anchor.tagName?.toUpperCase()) && anchor.parentNode) {
4783
4783
  anchor.after(table);
@@ -4867,8 +4867,8 @@ function isModifier(event, keyName) {
4867
4867
  * Inspired by Summernote's Typing module
4868
4868
  */
4869
4869
  var _FA_PATTERN = /\bfa-/;
4870
- var isFAIcon = (n) => !!(n && n.nodeName === "I" && _FA_PATTERN.test(n.className || ""));
4871
- var isZwsAnchor = (n) => !!(n && n.nodeType === Node.TEXT_NODE && (n.textContent === "​" || n.textContent === ""));
4870
+ var isFAIcon = (n) => !!(n?.nodeName === "I" && _FA_PATTERN.test(n.className || ""));
4871
+ var isZwsAnchor = (n) => !!(n?.nodeType === Node.TEXT_NODE && (n.textContent === "​" || n.textContent === ""));
4872
4872
  /**
4873
4873
  * Handles special keydown behaviour inside the editor.
4874
4874
  * @param {KeyboardEvent} event
@@ -4878,7 +4878,7 @@ var isZwsAnchor = (n) => !!(n && n.nodeType === Node.TEXT_NODE && (n.textContent
4878
4878
  */
4879
4879
  function handleKeydown(event, editable, options = {}) {
4880
4880
  const moveCaret = (setFn) => {
4881
- const sel = window.getSelection();
4881
+ const sel = globalThis.getSelection();
4882
4882
  if (!sel) return false;
4883
4883
  const nr = document.createRange();
4884
4884
  setFn(nr);
@@ -4888,8 +4888,8 @@ function handleKeydown(event, editable, options = {}) {
4888
4888
  return true;
4889
4889
  };
4890
4890
  if (isKey(event, key.BACKSPACE)) {
4891
- const sel = window.getSelection();
4892
- if (sel && sel.rangeCount > 0) {
4891
+ const sel = globalThis.getSelection();
4892
+ if (sel?.rangeCount > 0) {
4893
4893
  const r = sel.getRangeAt(0);
4894
4894
  if (r.collapsed && r.startContainer.nodeType === Node.TEXT_NODE) {
4895
4895
  const textNode = r.startContainer;
@@ -4919,7 +4919,7 @@ function handleKeydown(event, editable, options = {}) {
4919
4919
  return false;
4920
4920
  }
4921
4921
  if (isKey(event, key.LEFT) || isKey(event, key.RIGHT)) {
4922
- const sel = window.getSelection();
4922
+ const sel = globalThis.getSelection();
4923
4923
  if (!sel || sel.rangeCount === 0) return false;
4924
4924
  const r = sel.getRangeAt(0);
4925
4925
  if (!r.collapsed) return false;
@@ -5007,7 +5007,7 @@ function handleKeydown(event, editable, options = {}) {
5007
5007
  else execCommand("indent");
5008
5008
  return true;
5009
5009
  }
5010
- if (para && para.nodeName.toUpperCase() === "PRE") {
5010
+ if (para?.nodeName.toUpperCase() === "PRE") {
5011
5011
  if (event.shiftKey) return false;
5012
5012
  event.preventDefault();
5013
5013
  execCommand("insertText", " ".repeat(options.tabSize || 4));
@@ -5030,18 +5030,18 @@ function handleKeydown(event, editable, options = {}) {
5030
5030
  if (!range) return false;
5031
5031
  const sc = range.sc;
5032
5032
  const el = sc.nodeType === 3 ? sc.parentElement : sc;
5033
- if (el && el.nodeName === "I" && /\bfa-/.test(el.className || "")) {
5033
+ if (el?.nodeName === "I" && /\bfa-/.test(el.className || "")) {
5034
5034
  const nr = document.createRange();
5035
5035
  nr.setStartAfter(el);
5036
5036
  nr.collapse(true);
5037
- const selI = window.getSelection();
5037
+ const selI = globalThis.getSelection();
5038
5038
  if (selI) {
5039
5039
  selI.removeAllRanges();
5040
5040
  selI.addRange(nr);
5041
5041
  }
5042
5042
  return false;
5043
5043
  }
5044
- const videoWrapper = el && el.closest(".an-video-wrapper");
5044
+ const videoWrapper = el?.closest(".an-video-wrapper");
5045
5045
  if (videoWrapper) {
5046
5046
  event.preventDefault();
5047
5047
  const p = document.createElement("p");
@@ -5050,16 +5050,16 @@ function handleKeydown(event, editable, options = {}) {
5050
5050
  const nr = document.createRange();
5051
5051
  nr.setStart(p, 0);
5052
5052
  nr.collapse(true);
5053
- const sel = window.getSelection();
5053
+ const sel = globalThis.getSelection();
5054
5054
  sel.removeAllRanges();
5055
5055
  sel.addRange(nr);
5056
5056
  return true;
5057
5057
  }
5058
- const checkLi = el && el.closest(".an-checklist li");
5058
+ const checkLi = el?.closest(".an-checklist li");
5059
5059
  if (checkLi) {
5060
5060
  event.preventDefault();
5061
5061
  const ul = checkLi.closest(".an-checklist");
5062
- const sel = window.getSelection();
5062
+ const sel = globalThis.getSelection();
5063
5063
  let nativeRange = sel.getRangeAt(0);
5064
5064
  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();
5065
5065
  if (!liText(checkLi)) {
@@ -5103,12 +5103,12 @@ function handleKeydown(event, editable, options = {}) {
5103
5103
  return true;
5104
5104
  }
5105
5105
  const para = closestPara(range.sc, editable);
5106
- if (para && para.nodeName.toUpperCase() === "PRE") {
5106
+ if (para?.nodeName.toUpperCase() === "PRE") {
5107
5107
  event.preventDefault();
5108
5108
  execCommand("insertText", "\n");
5109
5109
  return true;
5110
5110
  }
5111
- if (para && para.nodeName.toUpperCase() === "BLOCKQUOTE") {
5111
+ if (para?.nodeName.toUpperCase() === "BLOCKQUOTE") {
5112
5112
  const native = range.toNativeRange();
5113
5113
  native.setEnd(para, para.childNodes.length);
5114
5114
  if (native.toString() === "" && range.isCollapsed()) {
@@ -5182,7 +5182,7 @@ function _domToMd(node, depth = 0) {
5182
5182
  return `\`${inner()}\``;
5183
5183
  case "pre": {
5184
5184
  const codeEl = el.querySelector("code");
5185
- const langMatch = (codeEl && codeEl.className || "").match(/language-(\S+)/);
5185
+ const langMatch = /language-(\S+)/.exec(codeEl && codeEl.className || "");
5186
5186
  return `\n\n\`\`\`${langMatch ? langMatch[1] : ""}\n${(codeEl || el).textContent || ""}\n\`\`\`\n\n`;
5187
5187
  }
5188
5188
  case "blockquote": return `\n\n${inner().trim().split("\n").map((l) => `> ${l}`).join("\n")}\n\n`;
@@ -5213,7 +5213,7 @@ function _domToMd(node, depth = 0) {
5213
5213
  case "table": {
5214
5214
  const rows = Array.from(el.querySelectorAll("tr"));
5215
5215
  if (!rows.length) return inner();
5216
- const cellTexts = rows.map((tr) => Array.from(tr.querySelectorAll("th, td")).map((c) => c.textContent.trim().replace(/\|/g, "\\|")));
5216
+ const cellTexts = rows.map((tr) => Array.from(tr.querySelectorAll("th, td")).map((c) => c.textContent.trim().replaceAll("|", "\\|")));
5217
5217
  const cols = Math.max(...cellTexts.map((r) => r.length));
5218
5218
  const padRow = (row) => {
5219
5219
  const r = [...row];
@@ -5222,7 +5222,7 @@ function _domToMd(node, depth = 0) {
5222
5222
  };
5223
5223
  let md = "\n\n";
5224
5224
  md += `| ${padRow(cellTexts[0]).join(" | ")} |\n`;
5225
- md += `| ${Array(cols).fill("---").join(" | ")} |\n`;
5225
+ md += `| ${new Array(cols).fill("---").join(" | ")} |\n`;
5226
5226
  for (let r = 1; r < cellTexts.length; r++) md += `| ${padRow(cellTexts[r]).join(" | ")} |\n`;
5227
5227
  return md + "\n";
5228
5228
  }
@@ -5246,12 +5246,12 @@ function isMarkdown(text) {
5246
5246
  * @returns {string}
5247
5247
  */
5248
5248
  function markdownToHTML(text) {
5249
- const lines = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
5249
+ const lines = text.replaceAll("\r\n", "\n").replaceAll("\r", "\n").split("\n");
5250
5250
  const out = [];
5251
5251
  let i = 0;
5252
5252
  while (i < lines.length) {
5253
5253
  const line = lines[i];
5254
- const fenceMatch = line.match(/^```(\S*)$/);
5254
+ const fenceMatch = /^```(\S*)$/.exec(line);
5255
5255
  if (fenceMatch) {
5256
5256
  const lang = fenceMatch[1];
5257
5257
  const codeLines = [];
@@ -5270,7 +5270,7 @@ function markdownToHTML(text) {
5270
5270
  i++;
5271
5271
  continue;
5272
5272
  }
5273
- const hMatch = line.match(/^(#{1,6})\s+(.+)$/);
5273
+ const hMatch = /^(#{1,6})\s+(.+)$/.exec(line);
5274
5274
  if (hMatch) {
5275
5275
  const level = hMatch[1].length;
5276
5276
  out.push(`<h${level}>${_inline(hMatch[2])}</h${level}>`);
@@ -5317,7 +5317,8 @@ function markdownToHTML(text) {
5317
5317
  i++;
5318
5318
  }
5319
5319
  const thead = `<thead><tr>${headerCells.map((c) => `<th>${_inline(c)}</th>`).join("")}</tr></thead>`;
5320
- const tbody = bodyRows.length ? `<tbody>${bodyRows.map((row) => `<tr>${row.map((c) => `<td>${_inline(c)}</td>`).join("")}</tr>`).join("")}</tbody>` : "";
5320
+ const renderRow = (row) => `<tr>${row.map((c) => `<td>${_inline(c)}</td>`).join("")}</tr>`;
5321
+ const tbody = bodyRows.length ? `<tbody>${bodyRows.map(renderRow).join("")}</tbody>` : "";
5321
5322
  out.push(`<table>${thead}${tbody}</table>`);
5322
5323
  continue;
5323
5324
  }
@@ -5353,10 +5354,10 @@ function _inline(text) {
5353
5354
  return text;
5354
5355
  }
5355
5356
  function _esc(v) {
5356
- return String(v).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5357
+ return String(v).replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
5357
5358
  }
5358
5359
  function _escAttr(v) {
5359
- return String(v).replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5360
+ return String(v).replaceAll("&", "&amp;").replaceAll("\"", "&quot;").replaceAll("'", "&#39;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
5360
5361
  }
5361
5362
  //#endregion
5362
5363
  //#region src/js/core/detectLang.js
@@ -5438,7 +5439,7 @@ var Editor = class {
5438
5439
  const onBeforeInput = (event) => this._enforceLimit(event);
5439
5440
  const onSelChange = () => {
5440
5441
  if (!this.context._alive) return;
5441
- const sel = window.getSelection();
5442
+ const sel = globalThis.getSelection();
5442
5443
  if (sel && sel.rangeCount > 0 && editable.contains(sel.anchorNode)) {
5443
5444
  this.context.invoke("toolbar.refresh");
5444
5445
  if (typeof this.options.onSelectionChange === "function") this.options.onSelectionChange(this.context);
@@ -5448,7 +5449,7 @@ var Editor = class {
5448
5449
  if (e.target.type === "checkbox" && e.target.closest(".an-checklist")) this.afterCommand();
5449
5450
  };
5450
5451
  const fixChecklistCursor = (event) => {
5451
- const sel = window.getSelection();
5452
+ const sel = globalThis.getSelection();
5452
5453
  if (!sel || !sel.rangeCount) return;
5453
5454
  const r = sel.getRangeAt(0);
5454
5455
  if (!r.collapsed) return;
@@ -5502,7 +5503,7 @@ var Editor = class {
5502
5503
  /** @type {string|null} 'superscript' | 'subscript' | null */
5503
5504
  let _compositionSupSub = null;
5504
5505
  const onCompositionStart = () => {
5505
- const sel = window.getSelection();
5506
+ const sel = globalThis.getSelection();
5506
5507
  if (!sel || !sel.rangeCount) {
5507
5508
  _compositionSupSub = null;
5508
5509
  return;
@@ -5520,12 +5521,12 @@ var Editor = class {
5520
5521
  const tag = _compositionSupSub;
5521
5522
  _compositionSupSub = null;
5522
5523
  if (!tag) return;
5523
- const sel = window.getSelection();
5524
+ const sel = globalThis.getSelection();
5524
5525
  if (!sel || !sel.rangeCount) return;
5525
5526
  let node = sel.getRangeAt(0).startContainer;
5526
5527
  if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
5527
5528
  const el = node;
5528
- if (!(el && (tag === "superscript" ? el.closest("sup") : el.closest("sub")))) document.execCommand(tag);
5529
+ if (!(tag === "superscript" ? el?.closest("sup") : el?.closest("sub"))) document.execCommand(tag);
5529
5530
  };
5530
5531
  this._disposers.push(on(editable, "compositionstart", onCompositionStart), on(editable, "compositionend", onCompositionEnd));
5531
5532
  }
@@ -5599,7 +5600,7 @@ var Editor = class {
5599
5600
  if (type === "insertFromPaste" || type === "insertFromDrop") return;
5600
5601
  if (!type.startsWith("insert")) return;
5601
5602
  const text = this.context.layoutInfo.editable.innerText || "";
5602
- const chars = text.replace(/\n/g, "").length;
5603
+ const chars = text.replaceAll("\n", "").length;
5603
5604
  if (maxChars && chars >= maxChars) {
5604
5605
  event.preventDefault();
5605
5606
  if (typeof this.options.onCharLimitReached === "function") this.options.onCharLimitReached(this.context);
@@ -5638,7 +5639,7 @@ var Editor = class {
5638
5639
  */
5639
5640
  _cleanOrphanedFigures() {
5640
5641
  this.context.layoutInfo.editable.querySelectorAll("figure.an-figure").forEach((fig) => {
5641
- if (!fig.querySelector("img")) fig.parentNode.removeChild(fig);
5642
+ if (!fig.querySelector("img")) fig.remove();
5642
5643
  });
5643
5644
  }
5644
5645
  /**
@@ -5674,7 +5675,7 @@ var Editor = class {
5674
5675
  * @returns {string}
5675
5676
  */
5676
5677
  getHTML() {
5677
- const raw = this.context.layoutInfo.editable.innerHTML.replace(/\u200B/g, "");
5678
+ const raw = this.context.layoutInfo.editable.innerHTML.replaceAll("​", "");
5678
5679
  return this.context.invoke("clipboard.resolveImages", raw) ?? raw;
5679
5680
  }
5680
5681
  /**
@@ -5719,7 +5720,7 @@ var Editor = class {
5719
5720
  * @returns {boolean}
5720
5721
  */
5721
5722
  isEmpty() {
5722
- const text = (this.context.layoutInfo.editable.innerText || "").trim().replace(/\u00a0/g, "");
5723
+ const text = (this.context.layoutInfo.editable.innerText || "").trim().replaceAll("\xA0", "");
5723
5724
  const hasMedia = !!this.context.layoutInfo.editable.querySelector("img, video, iframe, table");
5724
5725
  return !text && !hasMedia;
5725
5726
  }
@@ -5854,11 +5855,11 @@ var Editor = class {
5854
5855
  formatBlock(tagName) {
5855
5856
  formatBlock(tagName);
5856
5857
  if (tagName === "pre") {
5857
- const sel = window.getSelection();
5858
+ const sel = globalThis.getSelection();
5858
5859
  if (sel && sel.rangeCount > 0) {
5859
5860
  const container = sel.getRangeAt(0).commonAncestorContainer;
5860
5861
  const pre = container.nodeType === 1 ? container.closest("pre") : container.parentElement?.closest("pre");
5861
- if (pre && !pre.getAttribute("data-language")) {
5862
+ if (pre && !pre.dataset.language) {
5862
5863
  const lang = detectLang(pre.textContent || "");
5863
5864
  if (lang) {
5864
5865
  this.context.invoke("codeTooltip.applyLanguage", pre, lang);
@@ -5911,7 +5912,7 @@ var Editor = class {
5911
5912
  * @param {boolean} [openInNewTab=false]
5912
5913
  */
5913
5914
  insertLink(url, text, openInNewTab = false) {
5914
- const sel = window.getSelection();
5915
+ const sel = globalThis.getSelection();
5915
5916
  if (!sel || sel.rangeCount === 0) return;
5916
5917
  const safeUrl = sanitiseUrl(url);
5917
5918
  if (!safeUrl) return;
@@ -5974,7 +5975,7 @@ var Editor = class {
5974
5975
  this.afterCommand();
5975
5976
  }
5976
5977
  _getClosestAnchor() {
5977
- const sel = window.getSelection();
5978
+ const sel = globalThis.getSelection();
5978
5979
  if (!sel || sel.rangeCount === 0) return null;
5979
5980
  let node = sel.getRangeAt(0).startContainer;
5980
5981
  while (node) {
@@ -5989,7 +5990,7 @@ var Editor = class {
5989
5990
  * @returns {string}
5990
5991
  */
5991
5992
  _escapeAttr(str) {
5992
- return String(str ?? "").replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5993
+ return String(str ?? "").replaceAll("&", "&amp;").replaceAll("\"", "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
5993
5994
  }
5994
5995
  };
5995
5996
  //#endregion
@@ -6104,7 +6105,7 @@ var Toolbar = class {
6104
6105
  this._refreshRaf = null;
6105
6106
  this._disposers.forEach((d) => d());
6106
6107
  this._disposers = [];
6107
- if (this.el && this.el.parentNode) this.el.parentNode.removeChild(this.el);
6108
+ if (this.el && this.el.parentNode) this.el.remove();
6108
6109
  this.el = null;
6109
6110
  }
6110
6111
  _buildButtons() {
@@ -6172,8 +6173,8 @@ var Toolbar = class {
6172
6173
  let isOpen = false;
6173
6174
  const setHighlight = (rows, cols) => {
6174
6175
  cells.forEach((cell) => {
6175
- const r = +cell.getAttribute("data-row");
6176
- const c = +cell.getAttribute("data-col");
6176
+ const r = +cell.dataset.row;
6177
+ const c = +cell.dataset.col;
6177
6178
  cell.classList.toggle("active", r <= rows && c <= cols);
6178
6179
  });
6179
6180
  label.textContent = rows && cols ? `${rows} × ${cols}` : this.context.locale.toolbar.insertTableLabel || "Insert Table";
@@ -6187,8 +6188,8 @@ var Toolbar = class {
6187
6188
  const ph = popup.offsetHeight;
6188
6189
  let left = rect.left;
6189
6190
  let top = rect.bottom + 4;
6190
- if (left + pw > window.innerWidth - 8) left = Math.max(8, window.innerWidth - pw - 8);
6191
- if (top + ph > window.innerHeight - 8) top = rect.top - ph - 4;
6191
+ if (left + pw > globalThis.innerWidth - 8) left = Math.max(8, globalThis.innerWidth - pw - 8);
6192
+ if (top + ph > globalThis.innerHeight - 8) top = rect.top - ph - 4;
6192
6193
  popup.style.left = `${left}px`;
6193
6194
  popup.style.top = `${top}px`;
6194
6195
  popup.style.visibility = "";
@@ -6208,14 +6209,14 @@ var Toolbar = class {
6208
6209
  const d2 = on(grid, "mouseover", (e) => {
6209
6210
  const cell = e.target?.closest(".an-table-cell");
6210
6211
  if (!cell) return;
6211
- setHighlight(+cell.getAttribute("data-row"), +cell.getAttribute("data-col"));
6212
+ setHighlight(+cell.dataset.row, +cell.dataset.col);
6212
6213
  });
6213
6214
  const d3 = on(grid, "mouseleave", () => setHighlight(0, 0));
6214
6215
  const d4 = on(grid, "click", (e) => {
6215
6216
  const cell = e.target?.closest(".an-table-cell");
6216
6217
  if (!cell) return;
6217
- const rows = +cell.getAttribute("data-row");
6218
- const cols = +cell.getAttribute("data-col");
6218
+ const rows = +cell.dataset.row;
6219
+ const cols = +cell.dataset.col;
6219
6220
  closePopup();
6220
6221
  this.context.invoke("editor.focus");
6221
6222
  def.action(this.context, rows, cols);
@@ -6224,7 +6225,7 @@ var Toolbar = class {
6224
6225
  if (isOpen) closePopup();
6225
6226
  });
6226
6227
  this._disposers.push(d1, d2, d3, d4, d5, () => {
6227
- if (popup.parentNode) popup.parentNode.removeChild(popup);
6228
+ if (popup.parentNode) popup.remove();
6228
6229
  });
6229
6230
  wrap.appendChild(btn);
6230
6231
  document.body.appendChild(popup);
@@ -6314,13 +6315,13 @@ var Toolbar = class {
6314
6315
  /** @type {Range|null} saved selection range before popup opens */
6315
6316
  let savedRange = null;
6316
6317
  const saveSelection = () => {
6317
- const sel = window.getSelection();
6318
+ const sel = globalThis.getSelection();
6318
6319
  savedRange = sel && sel.rangeCount ? sel.getRangeAt(0).cloneRange() : null;
6319
6320
  };
6320
6321
  const restoreSelection = () => {
6321
6322
  if (!savedRange) return;
6322
6323
  try {
6323
- const sel = window.getSelection();
6324
+ const sel = globalThis.getSelection();
6324
6325
  if (!sel) return;
6325
6326
  sel.removeAllRanges();
6326
6327
  sel.addRange(savedRange);
@@ -6335,7 +6336,7 @@ var Toolbar = class {
6335
6336
  const rect = arrowBtn.getBoundingClientRect();
6336
6337
  const popupMinW = 184;
6337
6338
  let left = rect.left;
6338
- if (left + popupMinW > window.innerWidth) left = rect.right - popupMinW;
6339
+ if (left + popupMinW > globalThis.innerWidth) left = rect.right - popupMinW;
6339
6340
  popup.style.top = `${rect.bottom + 4}px`;
6340
6341
  popup.style.left = `${Math.max(4, left)}px`;
6341
6342
  popup.style.display = "block";
@@ -6398,9 +6399,9 @@ var Toolbar = class {
6398
6399
  passive: true,
6399
6400
  capture: true
6400
6401
  });
6401
- window.addEventListener("resize", onScrollResize, { passive: true });
6402
- this._disposers.push(d1, d2, d2b, d3, d3b, d4, d5, d6, () => document.removeEventListener("scroll", onScrollResize, { capture: true }), () => window.removeEventListener("resize", onScrollResize), () => {
6403
- if (popup.parentNode) popup.parentNode.removeChild(popup);
6402
+ globalThis.addEventListener("resize", onScrollResize, { passive: true });
6403
+ this._disposers.push(d1, d2, d2b, d3, d3b, d4, d5, d6, () => document.removeEventListener("scroll", onScrollResize, { capture: true }), () => globalThis.removeEventListener("resize", onScrollResize), () => {
6404
+ if (popup.parentNode) popup.remove();
6404
6405
  });
6405
6406
  this._colorPickerClosers.push(closePopup);
6406
6407
  this._disposers.push(() => {
@@ -6444,7 +6445,7 @@ var Toolbar = class {
6444
6445
  /** @type {Range|null} */
6445
6446
  let _savedRange = null;
6446
6447
  const dMousedown = on(select, "mousedown", () => {
6447
- const sel = window.getSelection();
6448
+ const sel = globalThis.getSelection();
6448
6449
  _savedRange = sel && sel.rangeCount ? sel.getRangeAt(0).cloneRange() : null;
6449
6450
  });
6450
6451
  const disposer = on(select, "change", (e) => {
@@ -6453,7 +6454,7 @@ var Toolbar = class {
6453
6454
  if (!value || selectedOpt.disabled) return;
6454
6455
  this.context.invoke("editor.focus");
6455
6456
  if (_savedRange) try {
6456
- const sel = window.getSelection();
6457
+ const sel = globalThis.getSelection();
6457
6458
  if (sel) {
6458
6459
  sel.removeAllRanges();
6459
6460
  sel.addRange(_savedRange);
@@ -6518,13 +6519,19 @@ var Toolbar = class {
6518
6519
  if (!this.el) return;
6519
6520
  const btnMap = this._btnMap || /* @__PURE__ */ new Map();
6520
6521
  this.el.querySelectorAll("button[data-btn]").forEach((btn) => {
6521
- const def = btnMap.get(btn.getAttribute("data-btn"));
6522
+ const def = btnMap.get(
6523
+ /** @type {HTMLElement} */
6524
+ btn.dataset.btn
6525
+ );
6522
6526
  if (def && typeof def.isActive === "function") btn.classList.toggle("active", !!def.isActive(this.context));
6523
6527
  if (def && typeof def.isDisabled === "function")
6524
6528
  /** @type {HTMLButtonElement} */ btn.disabled = !!def.isDisabled(this.context);
6525
6529
  });
6526
6530
  this.el.querySelectorAll("select[data-btn]").forEach((select) => {
6527
- const def = btnMap.get(select.getAttribute("data-btn"));
6531
+ const def = btnMap.get(
6532
+ /** @type {HTMLElement} */
6533
+ select.dataset.btn
6534
+ );
6528
6535
  if (!def || typeof def.getValue !== "function") return;
6529
6536
  let raw = (def.getValue(this.context) || "").replace(/["']/g, "").trim();
6530
6537
  if (!raw) raw = this.options.defaultFontFamily || this.options.fontFamilies && this.options.fontFamilies[0] || "";
@@ -6650,7 +6657,7 @@ var Statusbar = class {
6650
6657
  this._dragDisposers.forEach((d) => d());
6651
6658
  this._dragDisposers = null;
6652
6659
  }
6653
- if (this.el && this.el.parentNode) this.el.parentNode.removeChild(this.el);
6660
+ this.el?.remove();
6654
6661
  this.el = null;
6655
6662
  }
6656
6663
  _bindResize(handle) {
@@ -6714,7 +6721,7 @@ var Statusbar = class {
6714
6721
  if (!this._wordCountEl || !this._charCountEl) return;
6715
6722
  const text = this.context.layoutInfo.editable.textContent || "";
6716
6723
  const words = _countWords(text);
6717
- const chars = text.replace(/\n/g, "").length;
6724
+ const chars = text.replaceAll("\n", "").length;
6718
6725
  const maxWords = this.options.maxWords || 0;
6719
6726
  const maxChars = this.options.maxChars || 0;
6720
6727
  const LS = this.context.locale.statusbar;
@@ -6736,7 +6743,7 @@ var Statusbar = class {
6736
6743
  * @returns {number}
6737
6744
  */
6738
6745
  getCharCount() {
6739
- return (this.context.layoutInfo.editable.innerText || "").replace(/\n/g, "").length;
6746
+ return (this.context.layoutInfo.editable.innerText || "").replaceAll("\n", "").length;
6740
6747
  }
6741
6748
  };
6742
6749
  //#endregion
@@ -6829,7 +6836,7 @@ var Clipboard = class {
6829
6836
  if (el.querySelector("a, strong, em, b, i, ul, ol, li, table, img, blockquote, pre, code, h1, h2, h3, h4, h5, h6")) continue;
6830
6837
  const parent = el.parentNode;
6831
6838
  while (el.firstChild) parent.insertBefore(el.firstChild, el);
6832
- parent.removeChild(el);
6839
+ el.remove();
6833
6840
  }
6834
6841
  doc.querySelectorAll("*").forEach((el) => {
6835
6842
  el.removeAttribute("class");
@@ -6871,7 +6878,7 @@ var Clipboard = class {
6871
6878
  this._forcePlain = !!val;
6872
6879
  }
6873
6880
  _onPaste(event) {
6874
- const clipboardData = event.clipboardData || window.clipboardData;
6881
+ const clipboardData = event.clipboardData || globalThis.clipboardData;
6875
6882
  if (!clipboardData) return;
6876
6883
  const forcePlain = this._forcePlain;
6877
6884
  this._forcePlain = false;
@@ -6915,7 +6922,6 @@ var Clipboard = class {
6915
6922
  if (this.options.pasteStripAttributes) html = this._stripAttributes(html);
6916
6923
  execCommand("insertHTML", html);
6917
6924
  this.context.invoke("editor.afterCommand");
6918
- return;
6919
6925
  }
6920
6926
  }
6921
6927
  _onDragover(event) {
@@ -6947,17 +6953,17 @@ var Clipboard = class {
6947
6953
  this.options.onImageUpload(files);
6948
6954
  return;
6949
6955
  }
6950
- const UNSUPPORTED = [
6956
+ const UNSUPPORTED = new Set([
6951
6957
  "image/tiff",
6952
6958
  "image/x-tiff",
6953
6959
  "image/bmp",
6954
6960
  "image/x-bmp",
6955
6961
  "image/x-ms-bmp"
6956
- ];
6962
+ ]);
6957
6963
  const maxBytes = (this.options.maxImageSize || 5) * 1024 * 1024;
6958
6964
  files.forEach((file) => {
6959
6965
  if (!file || !file.type.startsWith("image/")) return;
6960
- if (UNSUPPORTED.includes(file.type)) {
6966
+ if (UNSUPPORTED.has(file.type)) {
6961
6967
  const message = `Image format "${file.type}" is not supported for display in web browsers. Please convert to PNG, JPEG, or WebP first.`;
6962
6968
  this.context.triggerEvent("imageError", {
6963
6969
  file,
@@ -7009,10 +7015,10 @@ var Clipboard = class {
7009
7015
  */
7010
7016
  _dataUrlToBlob(dataUrl) {
7011
7017
  const [header, b64] = dataUrl.split(",");
7012
- const mime = header.match(/:(.*?);/)?.[1] ?? "image/png";
7018
+ const mime = /:(.*?);/.exec(header)?.[1] ?? "image/png";
7013
7019
  const binary = atob(b64);
7014
7020
  const arr = new Uint8Array(binary.length);
7015
- for (let i = 0; i < binary.length; i++) arr[i] = binary.charCodeAt(i);
7021
+ for (let i = 0; i < binary.length; i++) arr[i] = binary.codePointAt(i);
7016
7022
  return new Blob([arr], { type: mime });
7017
7023
  }
7018
7024
  /**
@@ -7080,7 +7086,7 @@ var Clipboard = class {
7080
7086
  }
7081
7087
  }
7082
7088
  if (!range) return;
7083
- const sel = window.getSelection();
7089
+ const sel = globalThis.getSelection();
7084
7090
  if (sel) {
7085
7091
  sel.removeAllRanges();
7086
7092
  sel.addRange(range);
@@ -7092,7 +7098,7 @@ var Clipboard = class {
7092
7098
  * @returns {string}
7093
7099
  */
7094
7100
  _escapeHTML(str) {
7095
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
7101
+ return str.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&#039;");
7096
7102
  }
7097
7103
  };
7098
7104
  //#endregion
@@ -7129,7 +7135,7 @@ var Placeholder = class {
7129
7135
  _update() {
7130
7136
  const editable = this.context.layoutInfo.editable;
7131
7137
  const isFocused = document.activeElement === editable;
7132
- const isEmpty = !(editable.textContent.replace(/\u200B/g, "").trim().length > 0) && !editable.querySelector("img, table, hr, .an-video-wrapper");
7138
+ const isEmpty = !(editable.textContent.replaceAll("​", "").trim().length > 0) && !editable.querySelector("img, table, hr, .an-video-wrapper");
7133
7139
  editable.classList.toggle("an-placeholder", isEmpty && !isFocused);
7134
7140
  }
7135
7141
  };
@@ -7157,7 +7163,7 @@ var Codeview = class {
7157
7163
  destroy() {
7158
7164
  this._disposers.forEach((d) => d());
7159
7165
  this._disposers = [];
7160
- if (this._textarea && this._textarea.parentNode) this._textarea.parentNode.removeChild(this._textarea);
7166
+ this._textarea?.remove();
7161
7167
  this._textarea = null;
7162
7168
  }
7163
7169
  toggle() {
@@ -7188,7 +7194,7 @@ var Codeview = class {
7188
7194
  if (!this._active || !this._textarea) return;
7189
7195
  const { editable } = this.context.layoutInfo;
7190
7196
  editable.innerHTML = sanitiseHTML(this._textarea.value, { allowIframes: true });
7191
- this._textarea.parentNode.removeChild(this._textarea);
7197
+ this._textarea.remove();
7192
7198
  this._textarea = null;
7193
7199
  editable.style.display = "";
7194
7200
  this._active = false;
@@ -7212,7 +7218,7 @@ var Codeview = class {
7212
7218
  }).split("\n").map((line) => {
7213
7219
  const stripped = line.trim();
7214
7220
  if (!stripped) return "";
7215
- if (/^<\//.test(stripped)) indent = Math.max(0, indent - 1);
7221
+ if (stripped.startsWith("</")) indent = Math.max(0, indent - 1);
7216
7222
  const out = " ".repeat(indent) + stripped;
7217
7223
  if (/^<[^/!][^>]*[^/]>/.test(stripped) && !INLINE_RE.test(stripped) && !/^<(br|hr|img|input|link|meta)/.test(stripped)) indent++;
7218
7224
  return out;
@@ -7276,15 +7282,13 @@ var Fullscreen = class {
7276
7282
  }
7277
7283
  };
7278
7284
  //#endregion
7279
- //#region src/js/module/LinkDialog.js
7285
+ //#region src/js/module/BaseDialog.js
7280
7286
  /**
7281
- * LinkDialog.js - Dialog for inserting / editing hyperlinks
7282
- * Inspired by Summernote's LinkDialog rewritten without jQuery
7287
+ * Shared lifecycle and shell-building logic for all modal dialogs.
7288
+ * Subclasses implement _buildDialog() for their specific form fields.
7283
7289
  */
7284
- var LinkDialog = class {
7285
- /**
7286
- * @param {import('../Context.js').Context} context
7287
- */
7290
+ var BaseDialog = class {
7291
+ /** @param {import('../Context.js').Context} context */
7288
7292
  constructor(context) {
7289
7293
  this.context = context;
7290
7294
  this.options = context.options;
@@ -7292,6 +7296,9 @@ var LinkDialog = class {
7292
7296
  this._dialog = null;
7293
7297
  this._disposers = [];
7294
7298
  this._savedRange = null;
7299
+ /** @type {HTMLElement|null} First focusable input; set by subclass in _buildDialog(). */
7300
+ this._firstInput = null;
7301
+ this._removeTrap = null;
7295
7302
  }
7296
7303
  initialize() {
7297
7304
  this._dialog = this._buildDialog();
@@ -7301,36 +7308,113 @@ var LinkDialog = class {
7301
7308
  destroy() {
7302
7309
  this._disposers.forEach((d) => d());
7303
7310
  this._disposers = [];
7304
- if (this._dialog && this._dialog.parentNode) this._dialog.parentNode.removeChild(this._dialog);
7311
+ if (this._dialog?.parentNode) this._dialog.remove();
7305
7312
  this._dialog = null;
7306
7313
  }
7307
- /**
7308
- * Opens the link dialog.
7309
- * Pre-fills with the currently selected link if present.
7310
- */
7311
- show() {
7314
+ /** Saves the current selection range before opening the dialog. */
7315
+ _saveRange() {
7312
7316
  withSavedRange((range) => {
7313
7317
  this._savedRange = range;
7314
7318
  });
7315
- this._prefill();
7316
- this._open();
7317
7319
  }
7318
- _buildDialog() {
7319
- const L = this.context.locale.linkDialog;
7320
+ _open() {
7321
+ if (this._dialog) {
7322
+ this._dialog.style.display = "flex";
7323
+ this._removeTrap = trapFocus(this._dialog, () => this._close());
7324
+ setTimeout(() => this._firstInput && this._firstInput.focus(), 50);
7325
+ }
7326
+ }
7327
+ _close() {
7328
+ if (this._dialog) this._dialog.style.display = "none";
7329
+ if (this._removeTrap) {
7330
+ this._removeTrap();
7331
+ this._removeTrap = null;
7332
+ }
7333
+ this._savedRange = null;
7334
+ }
7335
+ /**
7336
+ * Builds the overlay + box + header shell common to all dialogs.
7337
+ * Also wires up draggable and overlay-click-to-close.
7338
+ * @param {string} ariaLabel
7339
+ * @param {string} iconHtml Raw SVG string for the dialog icon
7340
+ * @param {string} titleText
7341
+ * @returns {{ overlay: HTMLElement, box: HTMLElement }}
7342
+ */
7343
+ _buildDialogShell(ariaLabel, iconHtml, titleText) {
7320
7344
  const overlay = createElement("div", {
7321
7345
  class: "an-dialog-overlay",
7322
7346
  role: "dialog",
7323
7347
  "aria-modal": "true",
7324
- "aria-label": L.ariaLabel
7348
+ "aria-label": ariaLabel
7325
7349
  });
7326
7350
  const box = createElement("div", { class: "an-dialog-box" });
7327
7351
  const header = createElement("div", { class: "an-dialog-header" });
7328
7352
  const iconEl = createElement("span", { class: "an-dialog-icon" });
7329
- 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>`;
7330
- const title = createElement("h3", { class: "an-dialog-title" });
7331
- title.textContent = L.title;
7353
+ iconEl.innerHTML = iconHtml;
7354
+ const titleEl = createElement("h3", { class: "an-dialog-title" });
7355
+ titleEl.textContent = titleText;
7332
7356
  header.appendChild(iconEl);
7333
- header.appendChild(title);
7357
+ header.appendChild(titleEl);
7358
+ box.appendChild(header);
7359
+ overlay.appendChild(box);
7360
+ makeDraggable(header, box);
7361
+ const d = on(overlay, "click", (e) => {
7362
+ if (e.target === overlay) this._close();
7363
+ });
7364
+ this._disposers.push(d);
7365
+ return {
7366
+ overlay,
7367
+ box
7368
+ };
7369
+ }
7370
+ /**
7371
+ * Builds an action button row with a primary insert button and a cancel button.
7372
+ * Disposers are registered automatically.
7373
+ * @param {string} insertLabel
7374
+ * @param {string} cancelLabel
7375
+ * @param {() => void} onInsert
7376
+ * @returns {HTMLElement}
7377
+ */
7378
+ _buildButtonRow(insertLabel, cancelLabel, onInsert) {
7379
+ const btnRow = createElement("div", { class: "an-dialog-actions" });
7380
+ const insertBtn = createElement("button", {
7381
+ type: "button",
7382
+ class: "an-btn an-btn-primary"
7383
+ });
7384
+ insertBtn.textContent = insertLabel;
7385
+ const cancelBtn = createElement("button", {
7386
+ type: "button",
7387
+ class: "an-btn"
7388
+ });
7389
+ cancelBtn.textContent = cancelLabel;
7390
+ btnRow.appendChild(insertBtn);
7391
+ btnRow.appendChild(cancelBtn);
7392
+ const d1 = on(insertBtn, "click", onInsert);
7393
+ const d2 = on(cancelBtn, "click", () => this._close());
7394
+ this._disposers.push(d1, d2);
7395
+ return btnRow;
7396
+ }
7397
+ };
7398
+ //#endregion
7399
+ //#region src/js/module/LinkDialog.js
7400
+ /**
7401
+ * LinkDialog.js - Dialog for inserting / editing hyperlinks
7402
+ * Inspired by Summernote's LinkDialog — rewritten without jQuery
7403
+ */
7404
+ 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>`;
7405
+ var LinkDialog = class extends BaseDialog {
7406
+ /**
7407
+ * Opens the link dialog.
7408
+ * Pre-fills with the currently selected link if present.
7409
+ */
7410
+ show() {
7411
+ this._saveRange();
7412
+ this._prefill();
7413
+ this._open();
7414
+ }
7415
+ _buildDialog() {
7416
+ const L = this.context.locale.linkDialog;
7417
+ const { overlay, box } = this._buildDialogShell(L.ariaLabel, ICON_SVG$2, L.title);
7334
7418
  const urlLabel = createElement("label", { class: "an-label" });
7335
7419
  urlLabel.textContent = L.url;
7336
7420
  const urlInput = createElement("input", {
@@ -7342,6 +7426,7 @@ var LinkDialog = class {
7342
7426
  autocomplete: "off"
7343
7427
  });
7344
7428
  this._urlInput = urlInput;
7429
+ this._firstInput = urlInput;
7345
7430
  const textLabel = createElement("label", { class: "an-label" });
7346
7431
  textLabel.textContent = L.displayText;
7347
7432
  const textInput = createElement("input", {
@@ -7362,27 +7447,8 @@ var LinkDialog = class {
7362
7447
  this._tabCheckbox = tabCheckbox;
7363
7448
  tabLabel.appendChild(tabCheckbox);
7364
7449
  tabLabel.appendChild(document.createTextNode(" " + L.openInNewTab));
7365
- const btnRow = createElement("div", { class: "an-dialog-actions" });
7366
- const insertBtn = createElement("button", {
7367
- type: "button",
7368
- class: "an-btn an-btn-primary"
7369
- });
7370
- insertBtn.textContent = L.insertBtn;
7371
- const cancelBtn = createElement("button", {
7372
- type: "button",
7373
- class: "an-btn"
7374
- });
7375
- cancelBtn.textContent = L.cancelBtn;
7376
- btnRow.appendChild(insertBtn);
7377
- btnRow.appendChild(cancelBtn);
7378
- box.append(header, urlLabel, urlInput, textLabel, textInput, tabLabel, btnRow);
7379
- overlay.appendChild(box);
7380
- makeDraggable(header, box);
7381
- const d1 = on(insertBtn, "click", () => this._onInsert());
7382
- const d2 = on(cancelBtn, "click", () => this._close());
7383
- const d3 = on(overlay, "click", (e) => {
7384
- if (e.target === overlay) this._close();
7385
- });
7450
+ const btnRow = this._buildButtonRow(L.insertBtn, L.cancelBtn, () => this._onInsert());
7451
+ box.append(urlLabel, urlInput, textLabel, textInput, tabLabel, btnRow);
7386
7452
  const d4 = on(urlInput, "keydown", (e) => {
7387
7453
  if (e.key === "Enter") {
7388
7454
  e.preventDefault();
@@ -7395,11 +7461,11 @@ var LinkDialog = class {
7395
7461
  this._onInsert();
7396
7462
  }
7397
7463
  });
7398
- this._disposers.push(d1, d2, d3, d4, d5);
7464
+ this._disposers.push(d4, d5);
7399
7465
  return overlay;
7400
7466
  }
7401
7467
  _prefill() {
7402
- const sel = window.getSelection();
7468
+ const sel = globalThis.getSelection();
7403
7469
  let anchor = null;
7404
7470
  if (sel && sel.rangeCount > 0) {
7405
7471
  let node = sel.getRangeAt(0).startContainer;
@@ -7444,21 +7510,6 @@ var LinkDialog = class {
7444
7510
  this.context.invoke("editor.insertLink", url, text, newTab);
7445
7511
  this._close();
7446
7512
  }
7447
- _open() {
7448
- if (this._dialog) {
7449
- this._dialog.style.display = "flex";
7450
- this._removeTrap = trapFocus(this._dialog, () => this._close());
7451
- setTimeout(() => this._urlInput && this._urlInput.focus(), 50);
7452
- }
7453
- }
7454
- _close() {
7455
- if (this._dialog) this._dialog.style.display = "none";
7456
- if (this._removeTrap) {
7457
- this._removeTrap();
7458
- this._removeTrap = null;
7459
- }
7460
- this._savedRange = null;
7461
- }
7462
7513
  };
7463
7514
  //#endregion
7464
7515
  //#region src/js/module/ImageDialog.js
@@ -7466,33 +7517,10 @@ var LinkDialog = class {
7466
7517
  * ImageDialog.js - Dialog for inserting images (by URL or file upload)
7467
7518
  * Inspired by Summernote's ImageDialog — rewritten without jQuery
7468
7519
  */
7469
- var ImageDialog = class {
7470
- /**
7471
- * @param {import('../Context.js').Context} context
7472
- */
7473
- constructor(context) {
7474
- this.context = context;
7475
- this.options = context.options;
7476
- /** @type {HTMLElement|null} */
7477
- this._dialog = null;
7478
- this._disposers = [];
7479
- this._savedRange = null;
7480
- }
7481
- initialize() {
7482
- this._dialog = this._buildDialog();
7483
- document.body.appendChild(this._dialog);
7484
- return this;
7485
- }
7486
- destroy() {
7487
- this._disposers.forEach((d) => d());
7488
- this._disposers = [];
7489
- if (this._dialog && this._dialog.parentNode) this._dialog.parentNode.removeChild(this._dialog);
7490
- this._dialog = null;
7491
- }
7520
+ 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>`;
7521
+ var ImageDialog = class extends BaseDialog {
7492
7522
  show() {
7493
- withSavedRange((range) => {
7494
- this._savedRange = range;
7495
- });
7523
+ this._saveRange();
7496
7524
  this._urlInput.value = "";
7497
7525
  this._altInput.value = "";
7498
7526
  if (this._fileInput) this._fileInput.value = "";
@@ -7500,20 +7528,7 @@ var ImageDialog = class {
7500
7528
  }
7501
7529
  _buildDialog() {
7502
7530
  const L = this.context.locale.imageDialog;
7503
- const overlay = createElement("div", {
7504
- class: "an-dialog-overlay",
7505
- role: "dialog",
7506
- "aria-modal": "true",
7507
- "aria-label": L.ariaLabel
7508
- });
7509
- const box = createElement("div", { class: "an-dialog-box" });
7510
- const header = createElement("div", { class: "an-dialog-header" });
7511
- const iconEl = createElement("span", { class: "an-dialog-icon" });
7512
- 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>`;
7513
- const title = createElement("h3", { class: "an-dialog-title" });
7514
- title.textContent = L.title;
7515
- header.appendChild(iconEl);
7516
- header.appendChild(title);
7531
+ const { overlay, box } = this._buildDialogShell(L.ariaLabel, ICON_SVG$1, L.title);
7517
7532
  const urlLabel = createElement("label", { class: "an-label" });
7518
7533
  urlLabel.textContent = L.imageUrl;
7519
7534
  const urlInput = createElement("input", {
@@ -7523,6 +7538,7 @@ var ImageDialog = class {
7523
7538
  autocomplete: "off"
7524
7539
  });
7525
7540
  this._urlInput = urlInput;
7541
+ this._firstInput = urlInput;
7526
7542
  const altLabel = createElement("label", { class: "an-label" });
7527
7543
  altLabel.textContent = L.altText;
7528
7544
  const altInput = createElement("input", {
@@ -7532,7 +7548,7 @@ var ImageDialog = class {
7532
7548
  autocomplete: "off"
7533
7549
  });
7534
7550
  this._altInput = altInput;
7535
- box.append(header, urlLabel, urlInput, altLabel, altInput);
7551
+ box.append(urlLabel, urlInput, altLabel, altInput);
7536
7552
  const alignLabel = createElement("label", { class: "an-label" });
7537
7553
  alignLabel.textContent = L.alignment;
7538
7554
  const alignRow = createElement("div", { class: "an-align-row" });
@@ -7586,27 +7602,8 @@ var ImageDialog = class {
7586
7602
  this._disposers.push(d);
7587
7603
  box.append(fileLabel, fileInput, fileHint);
7588
7604
  }
7589
- const btnRow = createElement("div", { class: "an-dialog-actions" });
7590
- const insertBtn = createElement("button", {
7591
- type: "button",
7592
- class: "an-btn an-btn-primary"
7593
- });
7594
- insertBtn.textContent = L.insertBtn;
7595
- const cancelBtn = createElement("button", {
7596
- type: "button",
7597
- class: "an-btn"
7598
- });
7599
- cancelBtn.textContent = L.cancelBtn;
7600
- btnRow.appendChild(insertBtn);
7601
- btnRow.appendChild(cancelBtn);
7605
+ const btnRow = this._buildButtonRow(L.insertBtn, L.cancelBtn, () => this._onInsert());
7602
7606
  box.append(btnRow);
7603
- overlay.appendChild(box);
7604
- makeDraggable(header, box);
7605
- const d1 = on(insertBtn, "click", () => this._onInsert());
7606
- const d2 = on(cancelBtn, "click", () => this._close());
7607
- const d3 = on(overlay, "click", (e) => {
7608
- if (e.target === overlay) this._close();
7609
- });
7610
7607
  const d4 = on(urlInput, "keydown", (e) => {
7611
7608
  if (e.key === "Enter") {
7612
7609
  e.preventDefault();
@@ -7619,7 +7616,7 @@ var ImageDialog = class {
7619
7616
  this._onInsert();
7620
7617
  }
7621
7618
  });
7622
- this._disposers.push(d1, d2, d3, d4, d5);
7619
+ this._disposers.push(d4, d5);
7623
7620
  return overlay;
7624
7621
  }
7625
7622
  _onFileChange() {
@@ -7674,21 +7671,6 @@ var ImageDialog = class {
7674
7671
  this.context.invoke("editor.insertImage", src, alt, align);
7675
7672
  this._close();
7676
7673
  }
7677
- _open() {
7678
- if (this._dialog) {
7679
- this._dialog.style.display = "flex";
7680
- this._removeTrap = trapFocus(this._dialog, () => this._close());
7681
- setTimeout(() => this._urlInput && this._urlInput.focus(), 50);
7682
- }
7683
- }
7684
- _close() {
7685
- if (this._dialog) this._dialog.style.display = "none";
7686
- if (this._removeTrap) {
7687
- this._removeTrap();
7688
- this._removeTrap = null;
7689
- }
7690
- this._savedRange = null;
7691
- }
7692
7674
  };
7693
7675
  //#endregion
7694
7676
  //#region src/js/module/VideoDialog.js
@@ -7700,31 +7682,10 @@ var ImageDialog = class {
7700
7682
  * • Vimeo URLs → <iframe> embed
7701
7683
  * • Direct video URLs → <video> element (.mp4 / .webm / .ogg)
7702
7684
  */
7703
- var VideoDialog = class {
7704
- /** @param {import('../Context.js').Context} context */
7705
- constructor(context) {
7706
- this.context = context;
7707
- this.options = context.options;
7708
- /** @type {HTMLElement|null} */
7709
- this._dialog = null;
7710
- this._disposers = [];
7711
- this._savedRange = null;
7712
- }
7713
- initialize() {
7714
- this._dialog = this._buildDialog();
7715
- document.body.appendChild(this._dialog);
7716
- return this;
7717
- }
7718
- destroy() {
7719
- this._disposers.forEach((d) => d());
7720
- this._disposers = [];
7721
- if (this._dialog && this._dialog.parentNode) this._dialog.parentNode.removeChild(this._dialog);
7722
- this._dialog = null;
7723
- }
7685
+ 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>`;
7686
+ var VideoDialog = class extends BaseDialog {
7724
7687
  show() {
7725
- withSavedRange((range) => {
7726
- this._savedRange = range;
7727
- });
7688
+ this._saveRange();
7728
7689
  this._urlInput.value = "";
7729
7690
  this._widthInput.value = "560";
7730
7691
  this._hintEl.textContent = "";
@@ -7732,20 +7693,7 @@ var VideoDialog = class {
7732
7693
  }
7733
7694
  _buildDialog() {
7734
7695
  const L = this.context.locale.videoDialog;
7735
- const overlay = createElement("div", {
7736
- class: "an-dialog-overlay",
7737
- role: "dialog",
7738
- "aria-modal": "true",
7739
- "aria-label": L.ariaLabel
7740
- });
7741
- const box = createElement("div", { class: "an-dialog-box" });
7742
- const header = createElement("div", { class: "an-dialog-header" });
7743
- const iconEl = createElement("span", { class: "an-dialog-icon" });
7744
- 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>`;
7745
- const title = createElement("h3", { class: "an-dialog-title" });
7746
- title.textContent = L.title;
7747
- header.appendChild(iconEl);
7748
- header.appendChild(title);
7696
+ const { overlay, box } = this._buildDialogShell(L.ariaLabel, ICON_SVG, L.title);
7749
7697
  const urlLabel = createElement("label", { class: "an-label" });
7750
7698
  urlLabel.textContent = L.videoUrl;
7751
7699
  const urlInput = createElement("input", {
@@ -7755,6 +7703,7 @@ var VideoDialog = class {
7755
7703
  autocomplete: "off"
7756
7704
  });
7757
7705
  this._urlInput = urlInput;
7706
+ this._firstInput = urlInput;
7758
7707
  const hintEl = createElement("p", { class: "an-dialog-hint" });
7759
7708
  this._hintEl = hintEl;
7760
7709
  const widthLabel = createElement("label", { class: "an-label" });
@@ -7768,43 +7717,24 @@ var VideoDialog = class {
7768
7717
  value: "560"
7769
7718
  });
7770
7719
  this._widthInput = widthInput;
7771
- const btnRow = createElement("div", { class: "an-dialog-actions" });
7772
- const insertBtn = createElement("button", {
7773
- type: "button",
7774
- class: "an-btn an-btn-primary"
7775
- });
7776
- insertBtn.textContent = L.insertBtn;
7777
- const cancelBtn = createElement("button", {
7778
- type: "button",
7779
- class: "an-btn"
7780
- });
7781
- cancelBtn.textContent = L.cancelBtn;
7782
- btnRow.appendChild(insertBtn);
7783
- btnRow.appendChild(cancelBtn);
7784
- box.append(header, urlLabel, urlInput, hintEl, widthLabel, widthInput, btnRow);
7785
- overlay.appendChild(box);
7786
- makeDraggable(header, box);
7720
+ const btnRow = this._buildButtonRow(L.insertBtn, L.cancelBtn, () => this._onInsert());
7721
+ box.append(urlLabel, urlInput, hintEl, widthLabel, widthInput, btnRow);
7787
7722
  const d0 = on(urlInput, "input", () => {
7788
7723
  const info = this._parseVideoUrl(urlInput.value.trim());
7789
7724
  hintEl.textContent = info ? this.context.locale.videoDialog.detected(info.type) : urlInput.value ? this.context.locale.videoDialog.unknownFormat : "";
7790
7725
  });
7791
- const d1 = on(insertBtn, "click", () => this._onInsert());
7792
- const d2 = on(cancelBtn, "click", () => this._close());
7793
- const d3 = on(overlay, "click", (e) => {
7794
- if (e.target === overlay) this._close();
7795
- });
7796
7726
  const d4 = on(urlInput, "keydown", (e) => {
7797
7727
  if (e.key === "Enter") {
7798
7728
  e.preventDefault();
7799
7729
  this._onInsert();
7800
7730
  }
7801
7731
  });
7802
- this._disposers.push(d0, d1, d2, d3, d4);
7732
+ this._disposers.push(d0, d4);
7803
7733
  return overlay;
7804
7734
  }
7805
7735
  _onInsert() {
7806
7736
  const rawUrl = this._urlInput.value.trim();
7807
- const width = Math.max(80, parseInt(this._widthInput.value, 10) || 560);
7737
+ const width = Math.max(80, Number.parseInt(this._widthInput.value, 10) || 560);
7808
7738
  if (!rawUrl) {
7809
7739
  this._urlInput.focus();
7810
7740
  return;
@@ -7819,21 +7749,6 @@ var VideoDialog = class {
7819
7749
  this.context.invoke("editor.insertVideo", html);
7820
7750
  this._close();
7821
7751
  }
7822
- _open() {
7823
- if (this._dialog) {
7824
- this._dialog.style.display = "flex";
7825
- this._removeTrap = trapFocus(this._dialog, () => this._close());
7826
- setTimeout(() => this._urlInput && this._urlInput.focus(), 50);
7827
- }
7828
- }
7829
- _close() {
7830
- if (this._dialog) this._dialog.style.display = "none";
7831
- if (this._removeTrap) {
7832
- this._removeTrap();
7833
- this._removeTrap = null;
7834
- }
7835
- this._savedRange = null;
7836
- }
7837
7752
  /**
7838
7753
  * Parses a video URL and returns { type, embedUrl } or null.
7839
7754
  * @param {string} url
@@ -7847,22 +7762,22 @@ var VideoDialog = class {
7847
7762
  } catch {
7848
7763
  return null;
7849
7764
  }
7850
- const ytWatch = url.match(/(?:youtube\.com\/watch\?(?:.*&)?v=|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/);
7765
+ const ytWatch = /(?:youtube\.com\/watch\?(?:.*&)?v=|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/.exec(url);
7851
7766
  if (ytWatch) return {
7852
7767
  type: "YouTube",
7853
7768
  embedUrl: `https://www.youtube.com/embed/${ytWatch[1]}`
7854
7769
  };
7855
- const ytShort = url.match(/youtu\.be\/([a-zA-Z0-9_-]{11})/);
7770
+ const ytShort = /youtu\.be\/([a-zA-Z0-9_-]{11})/.exec(url);
7856
7771
  if (ytShort) return {
7857
7772
  type: "YouTube",
7858
7773
  embedUrl: `https://www.youtube.com/embed/${ytShort[1]}`
7859
7774
  };
7860
- const ytShorts = url.match(/youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/);
7775
+ const ytShorts = /youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/.exec(url);
7861
7776
  if (ytShorts) return {
7862
7777
  type: "YouTube Shorts",
7863
7778
  embedUrl: `https://www.youtube.com/embed/${ytShorts[1]}`
7864
7779
  };
7865
- const vimeo = url.match(/vimeo\.com\/(\d+)/);
7780
+ const vimeo = /vimeo\.com\/(\d+)/.exec(url);
7866
7781
  if (vimeo) return {
7867
7782
  type: "Vimeo",
7868
7783
  embedUrl: `https://player.vimeo.com/video/${vimeo[1]}`
@@ -7886,7 +7801,7 @@ var VideoDialog = class {
7886
7801
  const iframeTitle = `${info.type} video player`;
7887
7802
  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>`;
7888
7803
  }
7889
- 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>`;
7804
+ 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>`;
7890
7805
  const safeSrc = (() => {
7891
7806
  try {
7892
7807
  const p = new URL(url);
@@ -7897,7 +7812,7 @@ var VideoDialog = class {
7897
7812
  }
7898
7813
  })();
7899
7814
  if (!safeSrc) return null;
7900
- 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>`;
7815
+ 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>`;
7901
7816
  }
7902
7817
  };
7903
7818
  //#endregion
@@ -7968,7 +7883,7 @@ var ImageResizer = class {
7968
7883
  if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
7969
7884
  const img = e.target?.closest("img");
7970
7885
  if (img) this._select(img);
7971
- }), 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 }));
7886
+ }), 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 }));
7972
7887
  return this;
7973
7888
  }
7974
7889
  destroy() {
@@ -7983,7 +7898,7 @@ var ImageResizer = class {
7983
7898
  this._positionRaf = null;
7984
7899
  }
7985
7900
  this._deselect();
7986
- if (this._overlay && this._overlay.parentNode) this._overlay.parentNode.removeChild(this._overlay);
7901
+ if (this._overlay && this._overlay.parentNode) this._overlay.remove();
7987
7902
  this._overlay = null;
7988
7903
  }
7989
7904
  /** @returns {HTMLImageElement|null} */
@@ -8185,7 +8100,7 @@ var VideoResizer = class {
8185
8100
  if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
8186
8101
  const wrapper = this._findWrapper(e.target);
8187
8102
  if (wrapper) this._select(wrapper);
8188
- }), 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) => {
8103
+ }), 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) => {
8189
8104
  if (e.target instanceof Element && e.target.closest(".an-video-wrapper")) e.preventDefault();
8190
8105
  }));
8191
8106
  return this;
@@ -8202,7 +8117,7 @@ var VideoResizer = class {
8202
8117
  this._positionRaf = null;
8203
8118
  }
8204
8119
  this._deselect();
8205
- if (this._overlay && this._overlay.parentNode) this._overlay.parentNode.removeChild(this._overlay);
8120
+ this._overlay?.remove();
8206
8121
  this._overlay = null;
8207
8122
  }
8208
8123
  /** @returns {HTMLElement|null} */
@@ -8223,7 +8138,7 @@ var VideoResizer = class {
8223
8138
  */
8224
8139
  _findWrapper(el) {
8225
8140
  if (!el || !(el instanceof Element)) return null;
8226
- if (el.classList && el.classList.contains("an-video-wrapper")) return el;
8141
+ if (el.classList?.contains("an-video-wrapper")) return el;
8227
8142
  const w = el.closest(".an-video-wrapper");
8228
8143
  if (w) return w;
8229
8144
  return null;
@@ -8256,7 +8171,7 @@ var VideoResizer = class {
8256
8171
  _onDocClick(e) {
8257
8172
  if (!this._activeWrapper) return;
8258
8173
  if (this._activeWrapper.contains(e.target)) return;
8259
- if (this._overlay && this._overlay.contains(e.target)) return;
8174
+ if (this._overlay?.contains(e.target)) return;
8260
8175
  if (e.target.closest(".an-contextmenu")) return;
8261
8176
  this._deselect();
8262
8177
  }
@@ -8381,14 +8296,14 @@ var LinkTooltip = class {
8381
8296
  }), on(editable, "mouseout", (e) => {
8382
8297
  const to = e.relatedTarget;
8383
8298
  if (!to || !editable.contains(to) && !this._el.contains(to)) this._scheduleHide();
8384
- }), on(window, "scroll", () => this._hide(), { passive: true }), on(window, "resize", () => this._hide(), { passive: true }));
8299
+ }), on(globalThis, "scroll", () => this._hide(), { passive: true }), on(globalThis, "resize", () => this._hide(), { passive: true }));
8385
8300
  return this;
8386
8301
  }
8387
8302
  destroy() {
8388
8303
  this._clearTimers();
8389
8304
  this._disposers.forEach((d) => d());
8390
8305
  this._disposers = [];
8391
- if (this._el && this._el.parentNode) this._el.parentNode.removeChild(this._el);
8306
+ if (this._el && this._el.parentNode) this._el.remove();
8392
8307
  this._el = null;
8393
8308
  }
8394
8309
  _buildTooltip() {
@@ -8473,8 +8388,8 @@ var LinkTooltip = class {
8473
8388
  const margin = 6;
8474
8389
  let top = rect.bottom + margin;
8475
8390
  let left = rect.left;
8476
- if (top + tipH > window.innerHeight - margin) top = rect.top - tipH - margin;
8477
- if (left + tipW > window.innerWidth - margin) left = window.innerWidth - tipW - margin;
8391
+ if (top + tipH > globalThis.innerHeight - margin) top = rect.top - tipH - margin;
8392
+ if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
8478
8393
  if (left < margin) left = margin;
8479
8394
  this._el.style.top = `${top}px`;
8480
8395
  this._el.style.left = `${left}px`;
@@ -8489,12 +8404,12 @@ var LinkTooltip = class {
8489
8404
  }
8490
8405
  }
8491
8406
  _openLink() {
8492
- const url = this._activeAnchor && this._activeAnchor.getAttribute("href");
8493
- if (url) window.open(url, "_blank", "noopener,noreferrer");
8407
+ const url = this._activeAnchor?.getAttribute("href");
8408
+ if (url) globalThis.open(url, "_blank", "noopener,noreferrer");
8494
8409
  this._hide();
8495
8410
  }
8496
8411
  _copyLink() {
8497
- const url = this._activeAnchor && this._activeAnchor.getAttribute("href");
8412
+ const url = this._activeAnchor?.getAttribute("href");
8498
8413
  if (url) navigator.clipboard.writeText(url).catch(() => {
8499
8414
  const ta = document.createElement("textarea");
8500
8415
  ta.value = url;
@@ -8503,7 +8418,7 @@ var LinkTooltip = class {
8503
8418
  document.body.appendChild(ta);
8504
8419
  ta.select();
8505
8420
  document.execCommand("copy");
8506
- document.body.removeChild(ta);
8421
+ ta.remove();
8507
8422
  });
8508
8423
  if (this._copyBtn) {
8509
8424
  this._copyBtn.classList.add("an-link-tooltip-btn--copied");
@@ -8514,7 +8429,7 @@ var LinkTooltip = class {
8514
8429
  const anchor = this._activeAnchor;
8515
8430
  if (!anchor) return;
8516
8431
  this._hide();
8517
- const sel = window.getSelection();
8432
+ const sel = globalThis.getSelection();
8518
8433
  const range = document.createRange();
8519
8434
  range.selectNodeContents(anchor);
8520
8435
  sel.removeAllRanges();
@@ -8525,7 +8440,7 @@ var LinkTooltip = class {
8525
8440
  const anchor = this._activeAnchor;
8526
8441
  if (!anchor) return;
8527
8442
  this._hide();
8528
- const sel = window.getSelection();
8443
+ const sel = globalThis.getSelection();
8529
8444
  const range = document.createRange();
8530
8445
  range.selectNode(anchor);
8531
8446
  sel.removeAllRanges();
@@ -8574,14 +8489,14 @@ var ImageTooltip = class {
8574
8489
  }, { passive: true }), on(document, "click", (e) => {
8575
8490
  const et = e.target;
8576
8491
  if (this._activeImg && !this._activeImg.contains(et) && !this._el.contains(et)) this._hide();
8577
- }), on(window, "scroll", () => this._hide(), { passive: true }), on(window, "resize", () => this._hide(), { passive: true }));
8492
+ }), on(globalThis, "scroll", () => this._hide(), { passive: true }), on(globalThis, "resize", () => this._hide(), { passive: true }));
8578
8493
  return this;
8579
8494
  }
8580
8495
  destroy() {
8581
8496
  this._clearTimers();
8582
8497
  this._disposers.forEach((d) => d());
8583
8498
  this._disposers = [];
8584
- if (this._el && this._el.parentNode) this._el.parentNode.removeChild(this._el);
8499
+ this._el?.remove();
8585
8500
  this._el = null;
8586
8501
  }
8587
8502
  _buildTooltip() {
@@ -8682,8 +8597,8 @@ var ImageTooltip = class {
8682
8597
  const margin = 6;
8683
8598
  let top = rect.bottom + margin;
8684
8599
  let left = rect.left + (rect.width - tipW) / 2;
8685
- if (top + tipH > window.innerHeight - margin) top = rect.top - tipH - margin;
8686
- if (left + tipW > window.innerWidth - margin) left = window.innerWidth - tipW - margin;
8600
+ if (top + tipH > globalThis.innerHeight - margin) top = rect.top - tipH - margin;
8601
+ if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
8687
8602
  if (left < margin) left = margin;
8688
8603
  this._el.style.top = `${top}px`;
8689
8604
  this._el.style.left = `${left}px`;
@@ -8739,8 +8654,8 @@ var ImageTooltip = class {
8739
8654
  const img = this._activeImg;
8740
8655
  if (!img) return;
8741
8656
  const current = img.style.transform || "";
8742
- const match = current.match(/rotate\((-?[\d.]+)deg\)/);
8743
- const next = ((match ? parseFloat(match[1]) : 0) + delta + 360) % 360;
8657
+ const match = /rotate\((-?[\d.]+)deg\)/.exec(current);
8658
+ const next = ((match ? Number.parseFloat(match[1]) : 0) + delta + 360) % 360;
8744
8659
  const cleaned = current.replace(/rotate\(-?[\d.]+deg\)/, "").trim();
8745
8660
  img.style.transform = cleaned ? `${cleaned} rotate(${next}deg)` : next === 0 ? "" : `rotate(${next}deg)`;
8746
8661
  this.context.invoke("editor.afterCommand");
@@ -8755,8 +8670,8 @@ var ImageTooltip = class {
8755
8670
  this._hide();
8756
8671
  this.context.invoke("imageResizer.deselect");
8757
8672
  const figure = img.closest("figure.an-figure");
8758
- if (figure && figure.parentNode) figure.parentNode.removeChild(figure);
8759
- else if (img.parentNode) img.parentNode.removeChild(img);
8673
+ if (figure) figure.remove();
8674
+ else img.remove();
8760
8675
  this.context.invoke("editor.afterCommand");
8761
8676
  }
8762
8677
  _crop() {
@@ -8775,7 +8690,7 @@ var ImageTooltip = class {
8775
8690
  this._hide();
8776
8691
  const range = document.createRange();
8777
8692
  range.selectNodeContents(cap);
8778
- const sel = window.getSelection();
8693
+ const sel = globalThis.getSelection();
8779
8694
  if (sel) {
8780
8695
  sel.removeAllRanges();
8781
8696
  sel.addRange(range);
@@ -8809,7 +8724,7 @@ var ImageTooltip = class {
8809
8724
  figure.appendChild(figcaption);
8810
8725
  const range = document.createRange();
8811
8726
  range.selectNodeContents(figcaption);
8812
- const sel = window.getSelection();
8727
+ const sel = globalThis.getSelection();
8813
8728
  if (sel) {
8814
8729
  sel.removeAllRanges();
8815
8730
  sel.addRange(range);
@@ -8850,8 +8765,7 @@ var VideoTooltip = class {
8850
8765
  const editable = this.context.layoutInfo.editable;
8851
8766
  this._disposers.push(on(editable, "mouseover", (e) => {
8852
8767
  if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
8853
- const target = e.target;
8854
- const wrapper = target && target.closest ? target.closest(".an-video-wrapper") : null;
8768
+ const wrapper = e.target?.closest(".an-video-wrapper");
8855
8769
  if (wrapper && editable.contains(wrapper)) this._scheduleShow(wrapper);
8856
8770
  }, { passive: true }), on(editable, "mouseout", (e) => {
8857
8771
  const to = e.relatedTarget;
@@ -8859,7 +8773,7 @@ var VideoTooltip = class {
8859
8773
  }, { passive: true }), on(document, "click", (e) => {
8860
8774
  const target = e.target;
8861
8775
  if (this._activeWrapper && !this._activeWrapper.contains(target) && !this._el.contains(target)) this._hide();
8862
- }), on(window, "scroll", () => this._hide(), { passive: true }), on(window, "resize", () => this._hide(), { passive: true }));
8776
+ }), on(globalThis, "scroll", () => this._hide(), { passive: true }), on(globalThis, "resize", () => this._hide(), { passive: true }));
8863
8777
  return this;
8864
8778
  }
8865
8779
  destroy() {
@@ -8867,7 +8781,7 @@ var VideoTooltip = class {
8867
8781
  this._clearTimers();
8868
8782
  this._disposers.forEach((d) => d());
8869
8783
  this._disposers = [];
8870
- if (this._el && this._el.parentNode) this._el.parentNode.removeChild(this._el);
8784
+ this._el?.remove();
8871
8785
  this._el = null;
8872
8786
  }
8873
8787
  _buildTooltip() {
@@ -8964,8 +8878,8 @@ var VideoTooltip = class {
8964
8878
  const margin = 6;
8965
8879
  let top = rect.bottom + margin;
8966
8880
  let left = rect.left + (rect.width - tipW) / 2;
8967
- if (top + tipH > window.innerHeight - margin) top = rect.top - tipH - margin;
8968
- if (left + tipW > window.innerWidth - margin) left = window.innerWidth - tipW - margin;
8881
+ if (top + tipH > globalThis.innerHeight - margin) top = rect.top - tipH - margin;
8882
+ if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
8969
8883
  if (left < margin) left = margin;
8970
8884
  this._el.style.top = `${top}px`;
8971
8885
  this._el.style.left = `${left}px`;
@@ -9019,7 +8933,7 @@ var VideoTooltip = class {
9019
8933
  if (!wrapper) return;
9020
8934
  this._hide();
9021
8935
  this.context.invoke("videoResizer.deselect");
9022
- if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper);
8936
+ wrapper.remove();
9023
8937
  this.context.invoke("editor.afterCommand");
9024
8938
  }
9025
8939
  _togglePreview() {
@@ -9261,12 +9175,12 @@ var TableTooltip = class {
9261
9175
  }, { passive: true }), on(editable, "mouseout", (e) => {
9262
9176
  if (this._selectMode) return;
9263
9177
  const to = e.relatedTarget;
9264
- if (!to || !editable.contains(to) && !this._el.contains(to) && !(this._sizePopover && this._sizePopover.contains(to))) this._scheduleHide();
9178
+ if (!to || !editable.contains(to) && !this._el.contains(to) && !this._sizePopover?.contains(to)) this._scheduleHide();
9265
9179
  }, { passive: true }), on(document, "click", (e) => {
9266
9180
  const et = e.target;
9267
- if (this._selectMode && this._activeTable && this._activeTable.contains(et)) return;
9268
- if (this._activeTable && !this._activeTable.contains(et) && !this._el.contains(et) && !(this._sizePopover && this._sizePopover.contains(et))) this._hide();
9269
- }), on(document, "selectionchange", () => this._syncShadeStrip()), on(window, "scroll", () => this._hide(), { passive: true }), on(window, "resize", () => this._hide(), { passive: true }));
9181
+ if (this._selectMode && this._activeTable?.contains(et)) return;
9182
+ if (this._activeTable && !this._activeTable.contains(et) && !this._el.contains(et) && !this._sizePopover?.contains(et)) this._hide();
9183
+ }), on(document, "selectionchange", () => this._syncShadeStrip()), on(globalThis, "scroll", () => this._hide(), { passive: true }), on(globalThis, "resize", () => this._hide(), { passive: true }));
9270
9184
  this._initResize();
9271
9185
  return this;
9272
9186
  }
@@ -9392,11 +9306,11 @@ var TableTooltip = class {
9392
9306
  this._clearTimers();
9393
9307
  this._disposers.forEach((d) => d());
9394
9308
  this._disposers = [];
9395
- if (this._el && this._el.parentNode) this._el.parentNode.removeChild(this._el);
9309
+ if (this._el && this._el.parentNode) this._el.remove();
9396
9310
  this._el = null;
9397
- if (this._sizePopover && this._sizePopover.parentNode) this._sizePopover.parentNode.removeChild(this._sizePopover);
9311
+ if (this._sizePopover && this._sizePopover.parentNode) this._sizePopover.remove();
9398
9312
  this._sizePopover = null;
9399
- if (this._shadePopover && this._shadePopover.parentNode) this._shadePopover.parentNode.removeChild(this._shadePopover);
9313
+ if (this._shadePopover && this._shadePopover.parentNode) this._shadePopover.remove();
9400
9314
  this._shadePopover = null;
9401
9315
  }
9402
9316
  _buildTooltip() {
@@ -9506,7 +9420,7 @@ var TableTooltip = class {
9506
9420
  _syncShadeStrip() {
9507
9421
  if (!this._shadeColorStrip || !this._el || this._el.style.display === "none") return;
9508
9422
  const cell = this._getCell();
9509
- this._shadeColorStrip.style.background = cell && cell.style.backgroundColor || "transparent";
9423
+ this._shadeColorStrip.style.background = cell?.style.backgroundColor || "transparent";
9510
9424
  }
9511
9425
  _hide() {
9512
9426
  this._el.style.display = "none";
@@ -9536,20 +9450,20 @@ var TableTooltip = class {
9536
9450
  let left = rect.left + (rect.width - tipW) / 2;
9537
9451
  let top = rect.top - tipH - margin;
9538
9452
  if (top < margin) top = rect.bottom + margin;
9539
- if (left + tipW > window.innerWidth - margin) left = window.innerWidth - tipW - margin;
9453
+ if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
9540
9454
  if (left < margin) left = margin;
9541
9455
  this._el.style.left = `${left}px`;
9542
9456
  this._el.style.top = `${top}px`;
9543
9457
  }
9544
9458
  _getCell() {
9545
- const sel = window.getSelection();
9459
+ const sel = globalThis.getSelection();
9546
9460
  if (sel && sel.rangeCount) {
9547
9461
  let container = sel.getRangeAt(0).commonAncestorContainer;
9548
9462
  if (container.nodeType === 3) container = container.parentElement;
9549
- const cellFromSel = container && container.closest("td, th");
9550
- if (cellFromSel && this._activeTable && this._activeTable.contains(cellFromSel)) return cellFromSel;
9463
+ const cellFromSel = container?.closest("td, th");
9464
+ if (cellFromSel && this._activeTable?.contains(cellFromSel)) return cellFromSel;
9551
9465
  }
9552
- return this._activeCell || this._activeTable && this._activeTable.querySelector("td, th");
9466
+ return this._activeCell || this._activeTable?.querySelector("td, th");
9553
9467
  }
9554
9468
  _toggleSelectMode() {
9555
9469
  this._selectMode = !this._selectMode;
@@ -9648,11 +9562,12 @@ var TableTooltip = class {
9648
9562
  const table = cells[0].closest("table");
9649
9563
  if (!table) return;
9650
9564
  const allRows = Array.from(table.querySelectorAll("tr"));
9651
- const refRow = [...new Set(cells.map((c) => c.closest("tr")).filter(Boolean))].reduce((best, r) => {
9565
+ const selectedRows = [...new Set(cells.map((c) => c.closest("tr")).filter(Boolean))];
9566
+ const refRow = selectedRows.reduce((best, r) => {
9652
9567
  const bi = allRows.indexOf(best);
9653
9568
  const ri = allRows.indexOf(r);
9654
9569
  return position === "above" ? ri < bi ? r : best : ri > bi ? r : best;
9655
- });
9570
+ }, selectedRows[0]);
9656
9571
  const colCount = Array.from(refRow.cells).reduce((sum, c) => sum + (c.colSpan || 1), 0);
9657
9572
  const newRow = document.createElement("tr");
9658
9573
  const refCells = Array.from(refRow.cells);
@@ -9695,7 +9610,7 @@ var TableTooltip = class {
9695
9610
  if (selectedRows.filter((r) => r.closest("tbody")).length >= totalBodyRows) return;
9696
9611
  this._activeCell = null;
9697
9612
  this._clearSelection();
9698
- selectedRows.forEach((r) => r.parentElement?.removeChild(r));
9613
+ selectedRows.forEach((r) => r.remove());
9699
9614
  requestAnimationFrame(() => this._positionNear(this._activeTable));
9700
9615
  this.context.invoke("editor.afterCommand");
9701
9616
  }
@@ -9717,7 +9632,7 @@ var TableTooltip = class {
9717
9632
  });
9718
9633
  this._activeCell = null;
9719
9634
  this._clearSelection();
9720
- cellsToDelete.forEach((c) => c.parentElement?.removeChild(c));
9635
+ cellsToDelete.forEach((c) => c.remove());
9721
9636
  requestAnimationFrame(() => this._positionNear(this._activeTable));
9722
9637
  this.context.invoke("editor.afterCommand");
9723
9638
  }
@@ -9728,7 +9643,7 @@ var TableTooltip = class {
9728
9643
  if (!table) return;
9729
9644
  let selected = this._getSelectedCells().filter((c) => table.contains(c));
9730
9645
  if (selected.length < 2) {
9731
- const sel = window.getSelection();
9646
+ const sel = globalThis.getSelection();
9732
9647
  if (!sel || sel.rangeCount === 0) return;
9733
9648
  const range = sel.getRangeAt(0);
9734
9649
  selected = Array.from(table.querySelectorAll("td, th")).filter((c) => {
@@ -9770,7 +9685,7 @@ var TableTooltip = class {
9770
9685
  first.rowSpan = maxR - minR + 1;
9771
9686
  first.style.verticalAlign = "middle";
9772
9687
  first.innerHTML = rectCells.map((c) => c.innerHTML).join("");
9773
- rectCells.slice(1).forEach((c) => c.parentElement?.removeChild(c));
9688
+ rectCells.slice(1).forEach((c) => c.remove());
9774
9689
  this._clearSelection();
9775
9690
  this.context.invoke("editor.afterCommand");
9776
9691
  }
@@ -9778,7 +9693,7 @@ var TableTooltip = class {
9778
9693
  const table = this._activeTable;
9779
9694
  if (!table) return;
9780
9695
  this._hide();
9781
- if (table.parentNode) table.parentNode.removeChild(table);
9696
+ if (table.parentNode) table.remove();
9782
9697
  this.context.invoke("editor.afterCommand");
9783
9698
  }
9784
9699
  _unmergeCells() {
@@ -9867,7 +9782,7 @@ var TableTooltip = class {
9867
9782
  this._sizeInputEl = inputEl;
9868
9783
  this._sizeApply = null;
9869
9784
  const d1 = on(applyBtn, "click", () => {
9870
- const val = parseInt(this._sizeInputEl.value, 10);
9785
+ const val = Number.parseInt(this._sizeInputEl.value, 10);
9871
9786
  if (val > 0 && typeof this._sizeApply === "function") this._sizeApply(val);
9872
9787
  this._hideSizePopover();
9873
9788
  });
@@ -9896,7 +9811,7 @@ var TableTooltip = class {
9896
9811
  const table = cell.closest("table");
9897
9812
  if (!table) return;
9898
9813
  const firstCell = table.querySelector("td, th");
9899
- const currentPx = firstCell ? parseInt(firstCell.style.borderWidth, 10) || parseInt(window.getComputedStyle(firstCell).borderWidth, 10) || 1 : 1;
9814
+ const currentPx = firstCell ? Number.parseInt(firstCell.style.borderWidth, 10) || Number.parseInt(globalThis.getComputedStyle(firstCell).borderWidth, 10) || 1 : 1;
9900
9815
  this._sizeTitleEl.textContent = this.context.locale.tooltips.table.tableBorderWidthPx;
9901
9816
  this._sizeInputEl.min = "0";
9902
9817
  this._sizeInputEl.max = "10";
@@ -9955,8 +9870,8 @@ var TableTooltip = class {
9955
9870
  const ph = this._sizePopover.offsetHeight || 110;
9956
9871
  let left = tipRect.left;
9957
9872
  let top = tipRect.bottom + 6;
9958
- if (left + pw > window.innerWidth - 8) left = window.innerWidth - pw - 8;
9959
- if (top + ph > window.innerHeight - 8) top = tipRect.top - ph - 6;
9873
+ if (left + pw > globalThis.innerWidth - 8) left = globalThis.innerWidth - pw - 8;
9874
+ if (top + ph > globalThis.innerHeight - 8) top = tipRect.top - ph - 6;
9960
9875
  this._sizePopover.style.left = `${left}px`;
9961
9876
  this._sizePopover.style.top = `${top}px`;
9962
9877
  if (this._sizeInputEl) {
@@ -10010,11 +9925,10 @@ var TableTooltip = class {
10010
9925
  customRow.appendChild(colorInput);
10011
9926
  customRow.appendChild(customLabel);
10012
9927
  pop.appendChild(customRow);
10013
- this._disposers.push(on(pop, "mousedown", (e) => e.preventDefault()));
10014
- this._disposers.push(on(pop, "mouseenter", () => this._clearTimers()), on(pop, "mouseleave", () => this._scheduleHide()));
9928
+ this._disposers.push(on(pop, "mousedown", (e) => e.preventDefault()), on(pop, "mouseenter", () => this._clearTimers()), on(pop, "mouseleave", () => this._scheduleHide()));
10015
9929
  this._disposers.push(on(document, "click", (e) => {
10016
9930
  const et = e.target;
10017
- if (this._shadePopover && this._shadePopover.style.display !== "none" && !this._shadePopover.contains(et) && !(this._el && this._el.contains(et))) this._hideCellShadePopover();
9931
+ if (this._shadePopover && this._shadePopover.style.display !== "none" && !this._shadePopover.contains(et) && !this._el?.contains(et)) this._hideCellShadePopover();
10018
9932
  }));
10019
9933
  return pop;
10020
9934
  }
@@ -10031,8 +9945,8 @@ var TableTooltip = class {
10031
9945
  const tipRect = this._el.getBoundingClientRect();
10032
9946
  let left = tipRect.left;
10033
9947
  let top = tipRect.bottom + 6;
10034
- if (left + pw > window.innerWidth - 8) left = window.innerWidth - pw - 8;
10035
- if (top + ph > window.innerHeight - 8) top = tipRect.top - ph - 6;
9948
+ if (left + pw > globalThis.innerWidth - 8) left = globalThis.innerWidth - pw - 8;
9949
+ if (top + ph > globalThis.innerHeight - 8) top = tipRect.top - ph - 6;
10036
9950
  this._shadePopover.style.left = `${Math.max(8, left)}px`;
10037
9951
  this._shadePopover.style.top = `${Math.max(8, top)}px`;
10038
9952
  });
@@ -10095,7 +10009,7 @@ var CodeTooltip = class {
10095
10009
  this._clearTimers();
10096
10010
  this._disposers.forEach((d) => d());
10097
10011
  this._disposers = [];
10098
- if (this._el && this._el.parentNode) this._el.parentNode.removeChild(this._el);
10012
+ this._el?.remove();
10099
10013
  this._el = null;
10100
10014
  }
10101
10015
  _buildTooltip() {
@@ -10221,21 +10135,21 @@ var CodeTooltip = class {
10221
10135
  let top = rect.top - tipH - margin;
10222
10136
  let left = rect.left + (rect.width - tipW) / 2;
10223
10137
  if (top < margin) top = rect.bottom + margin;
10224
- if (left + tipW > window.innerWidth - margin) left = window.innerWidth - tipW - margin;
10138
+ if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
10225
10139
  if (left < margin) left = margin;
10226
10140
  this._el.style.top = `${top}px`;
10227
10141
  this._el.style.left = `${left}px`;
10228
10142
  }
10229
10143
  _syncWrapBtn() {
10230
10144
  if (!this._activePre || !this._wrapBtn) return;
10231
- const wrapped = (this._activePre.style.whiteSpace || "").includes("pre-wrap") || window.getComputedStyle(this._activePre).whiteSpace === "pre-wrap";
10145
+ const wrapped = (this._activePre.style.whiteSpace || "").includes("pre-wrap") || globalThis.getComputedStyle(this._activePre).whiteSpace === "pre-wrap";
10232
10146
  this._wrapBtn.classList.toggle("active", wrapped);
10233
10147
  this._wrapBtn.title = wrapped ? this.context.locale.tooltips.code.disableWordWrap : this.context.locale.tooltips.code.enableWordWrap;
10234
10148
  }
10235
10149
  _syncLangSelect() {
10236
10150
  if (!this._activePre || !this._langSelect) return;
10237
10151
  const codeEl = this._activePre.querySelector("code");
10238
- const fromAttr = this._activePre.getAttribute("data-language") || "";
10152
+ const fromAttr = this._activePre.dataset.language || "";
10239
10153
  const fromClass = codeEl ? (_LANG_CLASS_RE.exec(codeEl.className) || [])[1] || "" : "";
10240
10154
  this._langSelect.value = fromAttr || fromClass || "";
10241
10155
  }
@@ -10254,7 +10168,7 @@ var CodeTooltip = class {
10254
10168
  document.execCommand("copy");
10255
10169
  this._flashCopied();
10256
10170
  } catch (_) {}
10257
- document.body.removeChild(ta);
10171
+ ta.remove();
10258
10172
  }
10259
10173
  }
10260
10174
  _flashCopied() {
@@ -10287,7 +10201,6 @@ var CodeTooltip = class {
10287
10201
  applyLanguage(pre, lang) {
10288
10202
  if (!pre || !lang) return;
10289
10203
  const savedPre = this._activePre;
10290
- this._langSelect && this._langSelect.value;
10291
10204
  this._activePre = pre;
10292
10205
  if (this._langSelect) this._langSelect.value = lang;
10293
10206
  this._onLangChange();
@@ -10298,7 +10211,7 @@ var CodeTooltip = class {
10298
10211
  const pre = this._activePre;
10299
10212
  if (!pre) return;
10300
10213
  const lang = this._langSelect.value;
10301
- const _w = window;
10214
+ const _w = globalThis;
10302
10215
  let codeEl = pre.querySelector("code");
10303
10216
  if (!codeEl) {
10304
10217
  codeEl = document.createElement("code");
@@ -10308,15 +10221,15 @@ var CodeTooltip = class {
10308
10221
  }
10309
10222
  codeEl.className = lang ? `language-${lang}` : "";
10310
10223
  pre.className = lang ? `language-${lang}` : "";
10311
- if (lang) pre.setAttribute("data-language", lang);
10312
- else pre.removeAttribute("data-language");
10224
+ if (lang) pre.dataset.language = lang;
10225
+ else delete pre.dataset.language;
10313
10226
  const applyPrism = () => {
10314
10227
  codeEl.querySelectorAll("br").forEach((br) => br.replaceWith("\n"));
10315
10228
  _w.Prism.highlightElement(codeEl);
10316
10229
  this.context.invoke("editor.afterCommand");
10317
10230
  };
10318
10231
  if (lang) {
10319
- if (typeof _w.Prism !== "undefined") {
10232
+ if (_w.Prism !== void 0) {
10320
10233
  if (_w.Prism.languages[lang]) {
10321
10234
  applyPrism();
10322
10235
  return;
@@ -10338,7 +10251,7 @@ var CodeTooltip = class {
10338
10251
  * Called once at initialize time. Fire-and-forget; errors are silent.
10339
10252
  */
10340
10253
  _ensurePrism() {
10341
- const _w = window;
10254
+ const _w = globalThis;
10342
10255
  if (!this.context.options.codeHighlight || _w.Prism) return;
10343
10256
  const cdn = this.context.options.codeHighlightCDN;
10344
10257
  const themeHref = `${cdn}/themes/prism-tomorrow.min.css`;
@@ -10371,11 +10284,11 @@ var CodeTooltip = class {
10371
10284
  * @param {Function} cb – called once the grammar is ready
10372
10285
  */
10373
10286
  _loadPrismComponent(lang, cb) {
10374
- const _w = window;
10287
+ const _w = globalThis;
10375
10288
  const src = `${this.context.options.codeHighlightCDN}/components/prism-${lang}.min.js`;
10376
10289
  if (document.querySelector(`script[src="${src}"]`)) {
10377
10290
  const poll = setInterval(() => {
10378
- if (_w.Prism && _w.Prism.languages[lang]) {
10291
+ if (_w.Prism?.languages[lang]) {
10379
10292
  clearInterval(poll);
10380
10293
  cb();
10381
10294
  }
@@ -10406,7 +10319,7 @@ var CodeTooltip = class {
10406
10319
  const pre = this._activePre;
10407
10320
  if (!pre) return;
10408
10321
  this._hide();
10409
- if (pre.parentNode) pre.parentNode.removeChild(pre);
10322
+ pre.remove();
10410
10323
  this.context.invoke("editor.afterCommand");
10411
10324
  }
10412
10325
  };
@@ -12761,7 +12674,7 @@ var EmojiDialog = class {
12761
12674
  destroy() {
12762
12675
  this._disposers.forEach((d) => d());
12763
12676
  this._disposers = [];
12764
- if (this._dialog && this._dialog.parentNode) this._dialog.parentNode.removeChild(this._dialog);
12677
+ if (this._dialog && this._dialog.parentNode) this._dialog.remove();
12765
12678
  this._dialog = null;
12766
12679
  }
12767
12680
  show() {
@@ -12822,7 +12735,7 @@ var EmojiDialog = class {
12822
12735
  class: "an-icon-cat",
12823
12736
  "data-cat": id
12824
12737
  });
12825
- tab.textContent = L.categories && L.categories[id] || label;
12738
+ tab.textContent = L.categories?.[id] || label;
12826
12739
  catBar.appendChild(tab);
12827
12740
  });
12828
12741
  this._catBar = catBar;
@@ -12903,7 +12816,7 @@ var EmojiDialog = class {
12903
12816
  const savedRange = this._savedRange;
12904
12817
  const editable = this.context.layoutInfo.editable;
12905
12818
  if (savedRange) savedRange.select();
12906
- const sel = window.getSelection();
12819
+ const sel = globalThis.getSelection();
12907
12820
  let range = sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
12908
12821
  if (!range) {
12909
12822
  range = document.createRange();
@@ -12913,7 +12826,7 @@ var EmojiDialog = class {
12913
12826
  const _sc = range.startContainer;
12914
12827
  const _tdAnchor = (_sc.nodeType === 1 ? _sc : _sc.parentElement)?.closest("td, th");
12915
12828
  range.deleteContents();
12916
- if (_tdAnchor && _tdAnchor.isConnected && !_tdAnchor.contains(range.startContainer)) {
12829
+ if (_tdAnchor?.isConnected && !_tdAnchor.contains(range.startContainer)) {
12917
12830
  range.setStart(_tdAnchor, 0);
12918
12831
  range.collapse(true);
12919
12832
  }
@@ -12933,7 +12846,7 @@ var EmojiDialog = class {
12933
12846
  if (this._dialog) {
12934
12847
  this._dialog.style.display = "flex";
12935
12848
  this._removeTrap = trapFocus(this._dialog, () => this._close());
12936
- setTimeout(() => this._searchInput && this._searchInput.focus(), 50);
12849
+ setTimeout(() => this._searchInput?.focus(), 50);
12937
12850
  }
12938
12851
  }
12939
12852
  _close() {
@@ -13240,7 +13153,7 @@ var IconDialog = class {
13240
13153
  destroy() {
13241
13154
  this._disposers.forEach((d) => d());
13242
13155
  this._disposers = [];
13243
- if (this._dialog && this._dialog.parentNode) this._dialog.parentNode.removeChild(this._dialog);
13156
+ this._dialog?.remove();
13244
13157
  this._dialog = null;
13245
13158
  }
13246
13159
  show() {
@@ -13305,7 +13218,7 @@ var IconDialog = class {
13305
13218
  class: "an-icon-cat",
13306
13219
  "data-cat": id
13307
13220
  });
13308
- tab.textContent = L.categories && L.categories[id] || label;
13221
+ tab.textContent = L.categories?.[id] || label;
13309
13222
  catBar.appendChild(tab);
13310
13223
  });
13311
13224
  this._catBar = catBar;
@@ -13473,17 +13386,17 @@ var IconDialog = class {
13473
13386
  this._preview.innerHTML = "<span class=\"an-icon-preview-hint\">Select an icon</span>";
13474
13387
  return;
13475
13388
  }
13476
- const cls = this._styleSelect && this._styleSelect.value || "fa-solid";
13477
- const size = this._sizeSelect && this._sizeSelect.value || "1em";
13478
- const color = (this._useColorCb ? this._useColorCb.checked : false) && this._colorInput ? this._colorInput.value : "";
13389
+ const cls = this._styleSelect?.value || "fa-solid";
13390
+ const size = this._sizeSelect?.value || "1em";
13391
+ const color = this._useColorCb?.checked ?? false ? this._colorInput?.value ?? "" : "";
13479
13392
  const styleAttr = [size ? `font-size:${size}` : "", color ? `color:${color}` : ""].filter(Boolean).join(";");
13480
13393
  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>`;
13481
13394
  }
13482
13395
  _onInsert() {
13483
13396
  if (!this._selectedIcon) return;
13484
- const cls = this._styleSelect && this._styleSelect.value || "fa-solid";
13485
- const size = this._sizeSelect && this._sizeSelect.value || "";
13486
- const color = (this._useColorCb ? this._useColorCb.checked : false) && this._colorInput ? this._colorInput.value : "";
13397
+ const cls = this._styleSelect?.value || "fa-solid";
13398
+ const size = this._sizeSelect?.value || "";
13399
+ const color = this._useColorCb?.checked ?? false ? this._colorInput?.value ?? "" : "";
13487
13400
  const styleParts = [size ? `font-size:${size}` : "", color ? `color:${color}` : ""].filter(Boolean);
13488
13401
  const iconEl = document.createElement("i");
13489
13402
  iconEl.className = `${cls} fa-${this._selectedIcon}`;
@@ -13493,8 +13406,8 @@ var IconDialog = class {
13493
13406
  const savedRange = this._savedRange;
13494
13407
  const editable = this.context.layoutInfo.editable;
13495
13408
  if (savedRange) savedRange.select();
13496
- const sel = window.getSelection();
13497
- let range = sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
13409
+ const sel = globalThis.getSelection();
13410
+ let range = (sel?.rangeCount ?? 0) > 0 ? sel.getRangeAt(0) : null;
13498
13411
  if (!range) {
13499
13412
  range = document.createRange();
13500
13413
  range.selectNodeContents(editable);
@@ -13533,7 +13446,7 @@ var IconDialog = class {
13533
13446
  if (this._dialog) {
13534
13447
  this._dialog.style.display = "flex";
13535
13448
  this._removeTrap = trapFocus(this._dialog, () => this._close());
13536
- setTimeout(() => this._searchInput && this._searchInput.focus(), 50);
13449
+ setTimeout(() => this._searchInput?.focus(), 50);
13537
13450
  }
13538
13451
  }
13539
13452
  _close() {
@@ -13634,7 +13547,7 @@ var defaultItems = [
13634
13547
  icon: ICONS.paste,
13635
13548
  action: (ctx) => {
13636
13549
  if (!navigator.clipboard) return;
13637
- const editable = ctx.layoutInfo && ctx.layoutInfo.editable;
13550
+ const editable = ctx.layoutInfo?.editable;
13638
13551
  if (!editable) return;
13639
13552
  const doInsert = (html, text) => {
13640
13553
  editable.focus();
@@ -13759,13 +13672,13 @@ var ContextMenu = class {
13759
13672
  this.el.style.display = "none";
13760
13673
  document.body.appendChild(this.el);
13761
13674
  this._renderItems(this._items);
13762
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
13675
+ const editable = this.context.layoutInfo?.editable;
13763
13676
  if (editable) this._disposers.push(on(editable, "contextmenu", (e) => this._onContextMenu(e)));
13764
13677
  this._disposers.push(on(document, "click", (e) => this._maybeHide(e)));
13765
13678
  this._disposers.push(on(document, "keydown", (e) => {
13766
13679
  if (e.key === "Escape") this.hide();
13767
13680
  }));
13768
- this._disposers.push(on(window, "scroll", () => this.hide(), { passive: true }));
13681
+ this._disposers.push(on(globalThis, "scroll", () => this.hide(), { passive: true }));
13769
13682
  return this;
13770
13683
  }
13771
13684
  destroy() {
@@ -13781,7 +13694,7 @@ var ContextMenu = class {
13781
13694
  } catch (_e) {}
13782
13695
  });
13783
13696
  this._disposers = [];
13784
- if (this.el && this.el.parentNode) this.el.parentNode.removeChild(this.el);
13697
+ if (this.el) this.el.remove();
13785
13698
  this.el = null;
13786
13699
  }
13787
13700
  _renderItems(items) {
@@ -13809,8 +13722,8 @@ var ContextMenu = class {
13809
13722
  backBtn.appendChild(createElement("span", { class: "an-context-label" }, [backLabel]));
13810
13723
  const off = on(backBtn, "click", (e) => {
13811
13724
  e.stopPropagation();
13812
- const curLeft = parseFloat(this.el.style.left);
13813
- const curTop = parseFloat(this.el.style.top);
13725
+ const curLeft = Number.parseFloat(this.el.style.left);
13726
+ const curTop = Number.parseFloat(this.el.style.top);
13814
13727
  this._renderItems(it.navigate());
13815
13728
  this._reposition(curLeft, curTop);
13816
13729
  });
@@ -13853,8 +13766,8 @@ var ContextMenu = class {
13853
13766
  btn.appendChild(chevron);
13854
13767
  const off = on(btn, "click", (e) => {
13855
13768
  e.stopPropagation();
13856
- const curLeft = parseFloat(this.el.style.left);
13857
- const curTop = parseFloat(this.el.style.top);
13769
+ const curLeft = Number.parseFloat(this.el.style.left);
13770
+ const curTop = Number.parseFloat(this.el.style.top);
13858
13771
  this._renderItems(it.navigate());
13859
13772
  this._reposition(curLeft, curTop);
13860
13773
  });
@@ -13979,10 +13892,10 @@ var ContextMenu = class {
13979
13892
  if (!cell) return;
13980
13893
  const rows = +cell.dataset.row;
13981
13894
  const cols = +cell.dataset.col;
13982
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
13895
+ const editable = this.context.layoutInfo?.editable;
13983
13896
  if (editable && this._savedRange) {
13984
13897
  editable.focus();
13985
- const sel = window.getSelection();
13898
+ const sel = globalThis.getSelection();
13986
13899
  sel.removeAllRanges();
13987
13900
  sel.addRange(this._savedRange.cloneRange());
13988
13901
  }
@@ -14024,12 +13937,12 @@ var ContextMenu = class {
14024
13937
  });
14025
13938
  }
14026
13939
  _onContextMenu(event) {
14027
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
13940
+ const editable = this.context.layoutInfo?.editable;
14028
13941
  if (!editable) return;
14029
13942
  if (!editable.contains(event.target)) return;
14030
13943
  if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
14031
13944
  event.preventDefault();
14032
- const winSel = window.getSelection();
13945
+ const winSel = globalThis.getSelection();
14033
13946
  this._savedRange = winSel && winSel.rangeCount > 0 ? winSel.getRangeAt(0).cloneRange() : null;
14034
13947
  this._renderItems(this._items);
14035
13948
  const openX = event.clientX;
@@ -14061,9 +13974,9 @@ var ContextMenu = class {
14061
13974
  const h = this.el.offsetHeight;
14062
13975
  let left = rx;
14063
13976
  let top = ry;
14064
- if (left + w > window.innerWidth - 8) left = window.innerWidth - w - 8;
13977
+ if (left + w > globalThis.innerWidth - 8) left = globalThis.innerWidth - w - 8;
14065
13978
  if (left < 8) left = 8;
14066
- if (top + h > window.innerHeight - 8) top = window.innerHeight - h - 8;
13979
+ if (top + h > globalThis.innerHeight - 8) top = globalThis.innerHeight - h - 8;
14067
13980
  if (top < 8) top = 8;
14068
13981
  this.el.style.left = `${left}px`;
14069
13982
  this.el.style.top = `${top}px`;
@@ -14084,17 +13997,17 @@ var ContextMenu = class {
14084
13997
  let node = range.startContainer;
14085
13998
  if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
14086
13999
  if (!node) return type === "foreColor" ? "#000000" : "transparent";
14087
- const cs = window.getComputedStyle(node);
14000
+ const cs = globalThis.getComputedStyle(node);
14088
14001
  if (type === "foreColor") return cs.color || "#000000";
14089
14002
  const bg = cs.backgroundColor;
14090
14003
  return !bg || bg === "rgba(0, 0, 0, 0)" || bg === "transparent" ? "transparent" : bg;
14091
14004
  }
14092
14005
  /** Restore selection, apply a color command, then hide the menu. */
14093
14006
  _applyColor(type, color) {
14094
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
14007
+ const editable = this.context.layoutInfo?.editable;
14095
14008
  if (!editable || !this._savedRange) return;
14096
14009
  editable.focus();
14097
- const sel = window.getSelection();
14010
+ const sel = globalThis.getSelection();
14098
14011
  sel.removeAllRanges();
14099
14012
  sel.addRange(this._savedRange.cloneRange());
14100
14013
  document.execCommand(type, false, color);
@@ -14109,15 +14022,15 @@ var ContextMenu = class {
14109
14022
  copyFormat() {
14110
14023
  const range = this._savedRange;
14111
14024
  if (!range) return;
14112
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
14025
+ const editable = this.context.layoutInfo?.editable;
14113
14026
  let node = range.startContainer;
14114
14027
  if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
14115
14028
  if (!node || !editable || !editable.contains(node)) return;
14116
- const cs = window.getComputedStyle(node);
14029
+ const cs = globalThis.getComputedStyle(node);
14117
14030
  const explicitFontFamily = this._findExplicitStyle(node, editable, "fontFamily");
14118
14031
  const explicitFontSize = this._findExplicitStyle(node, editable, "fontSize");
14119
14032
  this._copiedFormat = {
14120
- bold: parseInt(cs.fontWeight, 10) >= 700,
14033
+ bold: Number.parseInt(cs.fontWeight, 10) >= 700,
14121
14034
  italic: cs.fontStyle === "italic" || cs.fontStyle === "oblique",
14122
14035
  underline: (cs.textDecorationLine || "").includes("underline"),
14123
14036
  strikethrough: (cs.textDecorationLine || "").includes("line-through"),
@@ -14148,10 +14061,10 @@ var ContextMenu = class {
14148
14061
  pasteFormat() {
14149
14062
  if (!this._copiedFormat || !this._savedRange) return;
14150
14063
  const fmt = this._copiedFormat;
14151
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
14064
+ const editable = this.context.layoutInfo?.editable;
14152
14065
  if (!editable) return;
14153
14066
  editable.focus();
14154
- const sel = window.getSelection();
14067
+ const sel = globalThis.getSelection();
14155
14068
  sel.removeAllRanges();
14156
14069
  sel.addRange(this._savedRange.cloneRange());
14157
14070
  document.execCommand("removeFormat");
@@ -14168,14 +14081,14 @@ var ContextMenu = class {
14168
14081
  const preExisting = new Set(editable.querySelectorAll("font[size=\"7\"]"));
14169
14082
  document.execCommand("fontSize", false, "7");
14170
14083
  editable.querySelectorAll("font[size=\"7\"]").forEach((el) => {
14171
- if (!preExisting.has(el)) el.setAttribute("data-an-tmp", marker);
14084
+ if (!preExisting.has(el)) /** @type {HTMLElement} */ el.dataset.anTmp = marker;
14172
14085
  });
14173
14086
  editable.querySelectorAll(`[data-an-tmp="${marker}"]`).forEach((el) => {
14174
14087
  const span = document.createElement("span");
14175
14088
  span.style.fontSize = fmt.fontSize;
14176
14089
  el.parentNode.insertBefore(span, el);
14177
14090
  while (el.firstChild) span.appendChild(el.firstChild);
14178
- el.parentNode.removeChild(el);
14091
+ el.remove();
14179
14092
  });
14180
14093
  }
14181
14094
  this.context.invoke("editor.afterCommand");
@@ -14183,10 +14096,10 @@ var ContextMenu = class {
14183
14096
  /** Strip all inline formatting from the saved selection. */
14184
14097
  removeFormat() {
14185
14098
  if (!this._savedRange) return;
14186
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
14099
+ const editable = this.context.layoutInfo?.editable;
14187
14100
  if (!editable) return;
14188
14101
  editable.focus();
14189
- const sel = window.getSelection();
14102
+ const sel = globalThis.getSelection();
14190
14103
  sel.removeAllRanges();
14191
14104
  sel.addRange(this._savedRange.cloneRange());
14192
14105
  document.execCommand("removeFormat");
@@ -14300,14 +14213,14 @@ var ShortcutsDialog = class {
14300
14213
  destroy() {
14301
14214
  this._disposers.forEach((d) => d());
14302
14215
  this._disposers = [];
14303
- if (this._dialog && this._dialog.parentNode) this._dialog.parentNode.removeChild(this._dialog);
14216
+ this._dialog?.remove();
14304
14217
  this._dialog = null;
14305
14218
  }
14306
14219
  show() {
14307
14220
  if (this._dialog) {
14308
14221
  this._dialog.style.display = "flex";
14309
14222
  this._removeTrap = trapFocus(this._dialog, () => this._close());
14310
- setTimeout(() => this._closeBtn && this._closeBtn.focus(), 50);
14223
+ setTimeout(() => this._closeBtn?.focus(), 50);
14311
14224
  }
14312
14225
  }
14313
14226
  _close() {
@@ -14413,7 +14326,7 @@ var FindReplace = class {
14413
14326
  this._clearHighlights();
14414
14327
  this._disposers.forEach((d) => d());
14415
14328
  this._disposers = [];
14416
- if (this._dialog && this._dialog.parentNode) this._dialog.parentNode.removeChild(this._dialog);
14329
+ if (this._dialog && this._dialog.parentNode) this._dialog.remove();
14417
14330
  this._dialog = null;
14418
14331
  }
14419
14332
  /**
@@ -14656,15 +14569,19 @@ var FindReplace = class {
14656
14569
  const re = this._queryRegex;
14657
14570
  const MAX_RESULTS = 500;
14658
14571
  const walker = document.createTreeWalker(root, 4);
14659
- let node;
14660
- while ((node = walker.nextNode()) && results.length < MAX_RESULTS) {
14572
+ let node = walker.nextNode();
14573
+ while (node && results.length < MAX_RESULTS) {
14661
14574
  re.lastIndex = 0;
14662
14575
  let m;
14663
- while ((m = re.exec(node.textContent)) !== null && results.length < MAX_RESULTS) results.push({
14576
+ while ((m = re.exec(
14577
+ /** @type {Text} */
14578
+ node.textContent
14579
+ )) !== null && results.length < MAX_RESULTS) results.push({
14664
14580
  node,
14665
14581
  start: m.index,
14666
14582
  end: m.index + m[0].length
14667
14583
  });
14584
+ node = walker.nextNode();
14668
14585
  }
14669
14586
  return results;
14670
14587
  }
@@ -14699,7 +14616,7 @@ var FindReplace = class {
14699
14616
  const parent = match.mark.parentNode;
14700
14617
  const textNode = document.createTextNode(replacement);
14701
14618
  parent.insertBefore(textNode, match.mark);
14702
- parent.removeChild(match.mark);
14619
+ match.mark.remove();
14703
14620
  parent.normalize();
14704
14621
  this.context.invoke("editor.afterCommand");
14705
14622
  const savedIndex = this._currentIndex;
@@ -14717,7 +14634,7 @@ var FindReplace = class {
14717
14634
  if (!mark || !mark.parentNode) return;
14718
14635
  const textNode = document.createTextNode(replacement);
14719
14636
  mark.parentNode.insertBefore(textNode, mark);
14720
- mark.parentNode.removeChild(mark);
14637
+ mark.remove();
14721
14638
  });
14722
14639
  if (this.context.layoutInfo.editable) this.context.layoutInfo.editable.normalize();
14723
14640
  this._matches = [];
@@ -14736,7 +14653,7 @@ var FindReplace = class {
14736
14653
  const parent = mark.parentNode;
14737
14654
  if (!parent) return;
14738
14655
  while (mark.firstChild) parent.insertBefore(mark.firstChild, mark);
14739
- parent.removeChild(mark);
14656
+ mark.remove();
14740
14657
  });
14741
14658
  editable.normalize();
14742
14659
  this._matches = [];
@@ -14787,7 +14704,7 @@ function drawCropToCanvas(img, naturalRect, renderW, renderH) {
14787
14704
  resolve(null);
14788
14705
  }
14789
14706
  };
14790
- if (img.src.startsWith("data:") || img.src.startsWith("blob:") || img.src.startsWith(window.location.origin)) {
14707
+ if (img.src.startsWith("data:") || img.src.startsWith("blob:") || img.src.startsWith(globalThis.location.origin)) {
14791
14708
  tryDraw(img);
14792
14709
  return;
14793
14710
  }
@@ -15045,8 +14962,8 @@ var ImageCropOverlay = class {
15045
14962
  this._cropBox.style.top = `${y}px`;
15046
14963
  this._cropBox.style.width = `${w}px`;
15047
14964
  this._cropBox.style.height = `${h}px`;
15048
- const vw = window.innerWidth;
15049
- const vh = window.innerHeight;
14965
+ const vw = globalThis.innerWidth;
14966
+ const vh = globalThis.innerHeight;
15050
14967
  this._scrim.style.clipPath = [
15051
14968
  `polygon(`,
15052
14969
  `0 0, ${vw}px 0, ${vw}px ${vh}px, 0 ${vh}px, 0 0,`,
@@ -15070,7 +14987,7 @@ var ImageCropOverlay = class {
15070
14987
  }
15071
14988
  const margin = 8;
15072
14989
  let tbTop = y + h + margin;
15073
- if (tbTop + 40 > window.innerHeight - margin) tbTop = y - 40 - margin;
14990
+ if (tbTop + 40 > globalThis.innerHeight - margin) tbTop = y - 40 - margin;
15074
14991
  this._toolbar.style.left = `${x}px`;
15075
14992
  this._toolbar.style.top = `${tbTop}px`;
15076
14993
  }
@@ -15197,7 +15114,7 @@ var ImageCropOverlay = class {
15197
15114
  this._close(false);
15198
15115
  return;
15199
15116
  }
15200
- const fmt = img.src.match(/^data:image\/(jpe?g)/i) ? "image/jpeg" : "image/png";
15117
+ const fmt = /^data:image\/(jpe?g)/i.exec(img.src) ? "image/jpeg" : "image/png";
15201
15118
  const quality = fmt === "image/jpeg" ? .92 : void 0;
15202
15119
  const newSrc = canvas.toDataURL(fmt, quality);
15203
15120
  this._close(false);
@@ -15237,7 +15154,7 @@ var ImageCropOverlay = class {
15237
15154
  banner.textContent = msg;
15238
15155
  document.body.appendChild(banner);
15239
15156
  setTimeout(() => {
15240
- if (banner.parentNode) banner.parentNode.removeChild(banner);
15157
+ banner.remove();
15241
15158
  }, 4e3);
15242
15159
  }
15243
15160
  /**
@@ -15252,7 +15169,7 @@ var ImageCropOverlay = class {
15252
15169
  this._cropBox,
15253
15170
  this._toolbar
15254
15171
  ].forEach((el) => {
15255
- if (el && el.parentNode) el.parentNode.removeChild(el);
15172
+ el?.remove();
15256
15173
  });
15257
15174
  this._scrim = null;
15258
15175
  this._cropBox = null;
@@ -15273,7 +15190,7 @@ var ImageCropOverlay = class {
15273
15190
  *
15274
15191
  * Activated when both `autoSave` and `autoSaveRestore` options are true.
15275
15192
  * On initialize it checks localStorage for a draft that is within the
15276
- * `autoSaveRestoreTimeout` day window. If one is found a dismissible banner
15193
+ * `autoSaveRestoreTimeout` day globalThis. If one is found a dismissible banner
15277
15194
  * is prepended to the editor container.
15278
15195
  */
15279
15196
  var AutoSaveRestore = class {
@@ -15359,7 +15276,7 @@ var AutoSaveRestore = class {
15359
15276
  this._removeBanner();
15360
15277
  }
15361
15278
  _removeBanner() {
15362
- if (this._banner && this._banner.parentNode) this._banner.parentNode.removeChild(this._banner);
15279
+ this._banner?.remove();
15363
15280
  this._banner = null;
15364
15281
  }
15365
15282
  };
@@ -15422,8 +15339,8 @@ var MarkdownShortcuts = class {
15422
15339
  * @returns {{ text: string, range: Range, lineNode: Node } | null}
15423
15340
  */
15424
15341
  _getLineContext() {
15425
- const sel = window.getSelection();
15426
- if (!sel || !sel.rangeCount) return null;
15342
+ const sel = globalThis.getSelection();
15343
+ if (!sel?.rangeCount) return null;
15427
15344
  const range = sel.getRangeAt(0);
15428
15345
  if (!range.collapsed) return null;
15429
15346
  const editable = this.context.layoutInfo.editable;
@@ -15442,7 +15359,7 @@ var MarkdownShortcuts = class {
15442
15359
  }
15443
15360
  _isBlock(node) {
15444
15361
  if (node.nodeType !== Node.ELEMENT_NODE) return false;
15445
- const display = window.getComputedStyle(node).display;
15362
+ const display = globalThis.getComputedStyle(node).display;
15446
15363
  return display === "block" || display === "list-item" || display === "table-cell";
15447
15364
  }
15448
15365
  /** Applies block rule on Space key. Returns true if a rule fired. */
@@ -15473,7 +15390,7 @@ var MarkdownShortcuts = class {
15473
15390
  }
15474
15391
  ];
15475
15392
  for (const { re, handler } of blockPatterns) {
15476
- const m = text.match(re);
15393
+ const m = re.exec(text);
15477
15394
  if (m) {
15478
15395
  handler(m);
15479
15396
  return true;
@@ -15497,8 +15414,8 @@ var MarkdownShortcuts = class {
15497
15414
  return false;
15498
15415
  }
15499
15416
  _selectLineAndDelete() {
15500
- const sel = window.getSelection();
15501
- if (!sel || !sel.rangeCount) return;
15417
+ const sel = globalThis.getSelection();
15418
+ if (!sel?.rangeCount) return;
15502
15419
  const range = sel.getRangeAt(0);
15503
15420
  const startRange = document.createRange();
15504
15421
  startRange.setStart(range.startContainer.parentNode || range.startContainer, 0);
@@ -15536,8 +15453,8 @@ var MarkdownShortcuts = class {
15536
15453
  this.context.triggerEvent("change", this.context.getHTML());
15537
15454
  }
15538
15455
  _onInput() {
15539
- const sel = window.getSelection();
15540
- if (!sel || !sel.rangeCount) return;
15456
+ const sel = globalThis.getSelection();
15457
+ if (!sel?.rangeCount) return;
15541
15458
  const range = sel.getRangeAt(0);
15542
15459
  if (!range.collapsed) return;
15543
15460
  if (!this.context.layoutInfo.editable.contains(range.startContainer)) return;
@@ -15565,7 +15482,7 @@ var MarkdownShortcuts = class {
15565
15482
  ];
15566
15483
  const upToCursor = text.slice(0, offset);
15567
15484
  for (const { re, tag } of inlineRules) {
15568
- const m = upToCursor.match(re);
15485
+ const m = re.exec(upToCursor);
15569
15486
  if (!m) continue;
15570
15487
  const matchStart = upToCursor.length - m[0].length;
15571
15488
  const matchEnd = offset;
@@ -15576,11 +15493,8 @@ var MarkdownShortcuts = class {
15576
15493
  el.textContent = innerText;
15577
15494
  const beforeNode = document.createTextNode(before);
15578
15495
  const afterNode = document.createTextNode("​" + after);
15579
- const parent = node.parentNode;
15580
- parent.insertBefore(beforeNode, node);
15581
- parent.insertBefore(el, node);
15582
- parent.insertBefore(afterNode, node);
15583
- parent.removeChild(node);
15496
+ /** @type {ChildNode} */ node.before(beforeNode, el, afterNode);
15497
+ /** @type {ChildNode} */ node.remove();
15584
15498
  const newRange = document.createRange();
15585
15499
  newRange.setStart(afterNode, 1);
15586
15500
  newRange.collapse(true);
@@ -15651,12 +15565,12 @@ var _ACTIONS = {
15651
15565
  strikethrough: (ctx) => ctx.invoke("editor.strikethrough"),
15652
15566
  link: (ctx) => ctx.invoke("linkDialog.show"),
15653
15567
  removeFormat: (ctx) => {
15654
- const editable = ctx.layoutInfo && ctx.layoutInfo.editable;
15568
+ const editable = ctx.layoutInfo?.editable;
15655
15569
  if (!editable) return;
15656
15570
  editable.focus();
15657
15571
  document.execCommand("removeFormat");
15658
- const sel = window.getSelection();
15659
- if (sel && sel.rangeCount > 0 && !sel.getRangeAt(0).collapsed) {
15572
+ const sel = globalThis.getSelection();
15573
+ if (sel?.rangeCount > 0 && !sel.getRangeAt(0).collapsed) {
15660
15574
  const range = sel.getRangeAt(0);
15661
15575
  const ancestor = range.commonAncestorContainer;
15662
15576
  const root = ancestor.nodeType === 1 ? ancestor : ancestor.parentElement;
@@ -15714,15 +15628,15 @@ var BubbleToolbar = class {
15714
15628
  const d6 = this.context.on("contextMenu:hide", () => {
15715
15629
  this._contextMenuOpen = false;
15716
15630
  });
15717
- const d7 = on(window, "scroll", () => this._hide(), { passive: true });
15718
- const d8 = on(window, "resize", () => this._hide(), { passive: true });
15631
+ const d7 = on(globalThis, "scroll", () => this._hide(), { passive: true });
15632
+ const d8 = on(globalThis, "resize", () => this._hide(), { passive: true });
15719
15633
  this._disposers.push(d1, d2, d3, d4, d5, d6, d7, d8);
15720
15634
  return this;
15721
15635
  }
15722
15636
  destroy() {
15723
- if (this._el && this._el.parentNode) this._el.parentNode.removeChild(this._el);
15637
+ this._el?.remove();
15724
15638
  this._el = null;
15725
- if (this._picker && this._picker.parentNode) this._picker.parentNode.removeChild(this._picker);
15639
+ this._picker?.remove();
15726
15640
  this._picker = null;
15727
15641
  this._disposers.forEach((d) => d());
15728
15642
  this._disposers = [];
@@ -15836,15 +15750,15 @@ var BubbleToolbar = class {
15836
15750
  pickerAny._colorInput = colorInput;
15837
15751
  }
15838
15752
  _openColorPicker(type, anchorBtn) {
15839
- const sel = window.getSelection();
15840
- if (sel && sel.rangeCount > 0) this._savedRange = sel.getRangeAt(0).cloneRange();
15753
+ const sel = globalThis.getSelection();
15754
+ if (sel?.rangeCount > 0) this._savedRange = sel.getRangeAt(0).cloneRange();
15841
15755
  this._pickerType = type;
15842
15756
  const pickerAny = this._picker;
15843
15757
  const palette = pickerAny._paletteEl;
15844
15758
  const noColorBtn = pickerAny._noColorBtn;
15845
15759
  if (type === "hiliteColor") {
15846
15760
  if (!palette.contains(noColorBtn)) palette.appendChild(noColorBtn);
15847
- } else if (palette.contains(noColorBtn)) palette.removeChild(noColorBtn);
15761
+ } else if (palette.contains(noColorBtn)) noColorBtn.remove();
15848
15762
  /** @type {any} */ this._picker._colorInput.value = type === "foreColor" ? "#000000" : "#ffff00";
15849
15763
  this._picker.style.display = "block";
15850
15764
  const pw = this._picker.offsetWidth;
@@ -15853,7 +15767,7 @@ var BubbleToolbar = class {
15853
15767
  let top = toolbarRect.top - ph - 6;
15854
15768
  if (top < 8) top = toolbarRect.bottom + 6;
15855
15769
  let left = anchorBtn.getBoundingClientRect().left;
15856
- left = Math.max(8, Math.min(left, window.innerWidth - pw - 8));
15770
+ left = Math.max(8, Math.min(left, globalThis.innerWidth - pw - 8));
15857
15771
  this._picker.style.left = `${left}px`;
15858
15772
  this._picker.style.top = `${top}px`;
15859
15773
  }
@@ -15863,10 +15777,10 @@ var BubbleToolbar = class {
15863
15777
  }
15864
15778
  /** Restore the saved selection, apply execCommand, update the color strip, then close the picker. */
15865
15779
  _applyColor(type, color) {
15866
- const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
15780
+ const editable = this.context.layoutInfo?.editable;
15867
15781
  if (!editable || !this._savedRange) return;
15868
15782
  editable.focus();
15869
- const sel = window.getSelection();
15783
+ const sel = globalThis.getSelection();
15870
15784
  sel.removeAllRanges();
15871
15785
  try {
15872
15786
  sel.addRange(this._savedRange.cloneRange());
@@ -15877,8 +15791,7 @@ var BubbleToolbar = class {
15877
15791
  if (!document.execCommand(cmd, false, color) && cmd === "hiliteColor") document.execCommand("backColor", false, color);
15878
15792
  this.context.invoke("editor.afterCommand");
15879
15793
  const name = type === "hiliteColor" ? "hiliteColor" : "foreColor";
15880
- const btn = this._el && this._el.querySelector(`[data-name="${name}"]`);
15881
- const strip = btn && btn.querySelector(".an-bubble-color-strip");
15794
+ const strip = (this._el?.querySelector(`[data-name="${name}"]`))?.querySelector(".an-bubble-color-strip");
15882
15795
  if (strip) /** @type {HTMLElement} */ strip.style.background = color === "transparent" ? "transparent" : color;
15883
15796
  this._closeColorPicker();
15884
15797
  this._syncActive();
@@ -15893,14 +15806,14 @@ var BubbleToolbar = class {
15893
15806
  const gap = 8;
15894
15807
  let left = rect.left + rect.width / 2 - bw / 2;
15895
15808
  let top = rect.top - bh - gap;
15896
- left = Math.max(8, Math.min(left, window.innerWidth - bw - 8));
15809
+ left = Math.max(8, Math.min(left, globalThis.innerWidth - bw - 8));
15897
15810
  if (top < 8) top = rect.bottom + gap;
15898
15811
  const tableTooltipEl = document.querySelector(".an-table-tooltip");
15899
15812
  if (tableTooltipEl && tableTooltipEl.style.display !== "none") {
15900
15813
  const ttRect = tableTooltipEl.getBoundingClientRect();
15901
15814
  if (top < ttRect.bottom + gap && top + bh > ttRect.top - gap) {
15902
15815
  top = rect.bottom + gap;
15903
- if (top + bh > window.innerHeight - 8) top = ttRect.bottom + gap;
15816
+ if (top + bh > globalThis.innerHeight - 8) top = ttRect.bottom + gap;
15904
15817
  }
15905
15818
  }
15906
15819
  el.style.top = `${top}px`;
@@ -15926,17 +15839,15 @@ var BubbleToolbar = class {
15926
15839
  /** Read the current selection's color and update the color-strip indicators. */
15927
15840
  _syncColorStrips() {
15928
15841
  if (!this._el) return;
15929
- const sel = window.getSelection();
15842
+ const sel = globalThis.getSelection();
15930
15843
  if (!sel || !sel.rangeCount) return;
15931
15844
  let node = sel.getRangeAt(0).startContainer;
15932
15845
  if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
15933
15846
  if (!node) return;
15934
- const cs = window.getComputedStyle(node);
15935
- const foreBtn = this._el.querySelector("[data-name=\"foreColor\"]");
15936
- const foreStrip = foreBtn && foreBtn.querySelector(".an-bubble-color-strip");
15847
+ const cs = globalThis.getComputedStyle(node);
15848
+ const foreStrip = this._el.querySelector("[data-name=\"foreColor\"]")?.querySelector(".an-bubble-color-strip");
15937
15849
  if (foreStrip) /** @type {HTMLElement} */ foreStrip.style.background = cs.color || "#000000";
15938
- const hiliteBtn = this._el.querySelector("[data-name=\"hiliteColor\"]");
15939
- const hiliteStrip = hiliteBtn && hiliteBtn.querySelector(".an-bubble-color-strip");
15850
+ const hiliteStrip = this._el.querySelector("[data-name=\"hiliteColor\"]")?.querySelector(".an-bubble-color-strip");
15940
15851
  if (hiliteStrip) {
15941
15852
  const bg = cs.backgroundColor;
15942
15853
  /** @type {HTMLElement} */ hiliteStrip.style.background = !bg || bg === "rgba(0, 0, 0, 0)" || bg === "transparent" ? "transparent" : bg;
@@ -15947,7 +15858,7 @@ var BubbleToolbar = class {
15947
15858
  this._rafId = requestAnimationFrame(() => {
15948
15859
  if (this._contextMenuOpen) return;
15949
15860
  if (this._picker && this._picker.style.display !== "none") return;
15950
- const sel = window.getSelection();
15861
+ const sel = globalThis.getSelection();
15951
15862
  if (!sel || sel.isCollapsed || !sel.rangeCount) {
15952
15863
  this._hide();
15953
15864
  return;
@@ -15970,8 +15881,8 @@ var BubbleToolbar = class {
15970
15881
  }
15971
15882
  _onMousedown(e) {
15972
15883
  if (!this._visible) return;
15973
- if (this._el && this._el.contains(e.target)) return;
15974
- if (this._picker && this._picker.contains(e.target)) return;
15884
+ if (this._el?.contains(e.target)) return;
15885
+ if (this._picker?.contains(e.target)) return;
15975
15886
  if (this.context.layoutInfo.editable.contains(e.target)) return;
15976
15887
  this._hide();
15977
15888
  }
@@ -16056,7 +15967,7 @@ var Mention = class {
16056
15967
  }
16057
15968
  destroy() {
16058
15969
  clearTimeout(this._debounceTimer);
16059
- if (this._dropdown && this._dropdown.parentNode) this._dropdown.parentNode.removeChild(this._dropdown);
15970
+ this._dropdown?.remove();
16060
15971
  this._dropdown = null;
16061
15972
  this._disposers.forEach((d) => d());
16062
15973
  this._disposers = [];
@@ -16120,8 +16031,8 @@ var Mention = class {
16120
16031
  const ddw = dd.offsetWidth;
16121
16032
  let top = rect.bottom + 4;
16122
16033
  let left = rect.left;
16123
- if (rect.bottom + ddh + 8 > window.innerHeight) top = rect.top - ddh - 4;
16124
- left = Math.max(8, Math.min(left, window.innerWidth - ddw - 8));
16034
+ if (rect.bottom + ddh + 8 > globalThis.innerHeight) top = rect.top - ddh - 4;
16035
+ left = Math.max(8, Math.min(left, globalThis.innerWidth - ddw - 8));
16125
16036
  dd.style.top = `${top}px`;
16126
16037
  dd.style.left = `${left}px`;
16127
16038
  dd.style.visibility = "";
@@ -16145,7 +16056,7 @@ var Mention = class {
16145
16056
  * collapsed range is reliable at this point but often empty inside async callbacks.
16146
16057
  */
16147
16058
  _captureCaretRect() {
16148
- if (this._triggerNode && this._triggerNode.isConnected) try {
16059
+ if (this._triggerNode?.isConnected) try {
16149
16060
  const r = document.createRange();
16150
16061
  const end = Math.min(this._triggerOffset + 1, this._triggerNode.textContent.length);
16151
16062
  r.setStart(this._triggerNode, this._triggerOffset);
@@ -16156,13 +16067,13 @@ var Mention = class {
16156
16067
  return;
16157
16068
  }
16158
16069
  } catch (_) {}
16159
- const sel = window.getSelection();
16070
+ const sel = globalThis.getSelection();
16160
16071
  if (!sel || !sel.rangeCount) return;
16161
16072
  const rects = sel.getRangeAt(0).getClientRects();
16162
16073
  if (rects.length > 0) this._caretRect = rects[rects.length - 1];
16163
16074
  }
16164
16075
  _getQueryAtCursor() {
16165
- const sel = window.getSelection();
16076
+ const sel = globalThis.getSelection();
16166
16077
  if (!sel || !sel.rangeCount) return null;
16167
16078
  const range = sel.getRangeAt(0);
16168
16079
  if (!range.collapsed) return null;
@@ -16219,7 +16130,7 @@ var Mention = class {
16219
16130
  }
16220
16131
  _onDocClick(e) {
16221
16132
  if (!this._open) return;
16222
- if (this._dropdown && this._dropdown.contains(e.target)) return;
16133
+ if (this._dropdown?.contains(e.target)) return;
16223
16134
  this._hideDropdown();
16224
16135
  }
16225
16136
  _select(index) {
@@ -16228,7 +16139,7 @@ var Mention = class {
16228
16139
  if (this._triggerNode) {
16229
16140
  const node = this._triggerNode;
16230
16141
  node.textContent = node.textContent.slice(0, this._triggerOffset) + node.textContent.slice(this._triggerOffset + this._cfg.trigger.length + this._query.length);
16231
- const sel = window.getSelection();
16142
+ const sel = globalThis.getSelection();
16232
16143
  const range = document.createRange();
16233
16144
  range.setStart(node, this._triggerOffset);
16234
16145
  range.collapse(true);
@@ -16331,7 +16242,7 @@ var Context = class {
16331
16242
  register("markdownShortcuts", MarkdownShortcuts);
16332
16243
  register("bubbleToolbar", BubbleToolbar);
16333
16244
  register("mention", Mention);
16334
- for (const [name, ModuleClass] of _customModules) register(name, ModuleClass);
16245
+ if (_customModules.size > 0) for (const [name, ModuleClass] of _customModules) register(name, ModuleClass);
16335
16246
  }
16336
16247
  /**
16337
16248
  * Registers and initialises a custom module on this instance.
@@ -16384,6 +16295,7 @@ var Context = class {
16384
16295
  });
16385
16296
  }
16386
16297
  _applyGlobalPlugins() {
16298
+ if (_globalPlugins.size === 0) return;
16387
16299
  for (const { plugin, options } of _globalPlugins.values()) this._installPlugin(plugin, options);
16388
16300
  }
16389
16301
  _bindEditorEvents(editable) {
@@ -16589,23 +16501,27 @@ var Context = class {
16589
16501
  a.style.display = "none";
16590
16502
  document.body.appendChild(a);
16591
16503
  a.click();
16592
- document.body.removeChild(a);
16504
+ a.remove();
16593
16505
  URL.revokeObjectURL(url);
16594
16506
  }
16595
16507
  /**
16596
- * Opens the editor content in a new window and triggers the browser print dialog.
16508
+ * Opens the editor content in a new globalThis and triggers the browser print dialog.
16597
16509
  * @param {string} [title='']
16598
16510
  */
16599
16511
  print(title = "") {
16600
16512
  const content = this.getHTML();
16601
- const safeTitle = (title || "").replace(/</g, "&lt;").replace(/>/g, "&gt;");
16602
- const w = window.open("", "_blank");
16603
- if (!w) return;
16604
- 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>`);
16605
- w.document.close();
16606
- w.onload = () => {
16513
+ 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>`;
16514
+ const blob = new Blob([markup], { type: "text/html" });
16515
+ const url = URL.createObjectURL(blob);
16516
+ const w = globalThis.open(url, "_blank");
16517
+ if (!w) {
16518
+ URL.revokeObjectURL(url);
16519
+ return;
16520
+ }
16521
+ w.addEventListener("load", () => {
16607
16522
  w.print();
16608
- };
16523
+ URL.revokeObjectURL(url);
16524
+ });
16609
16525
  }
16610
16526
  /**
16611
16527
  * Sets whether the editor is disabled (readonly).
@@ -16643,10 +16559,10 @@ var Context = class {
16643
16559
  this._disposers.forEach((d) => d());
16644
16560
  this._disposers = [];
16645
16561
  const container = this.layoutInfo.container;
16646
- const wasDark = container && container.classList.contains("an-theme-dark");
16647
- if (container && container.parentNode) {
16562
+ const wasDark = container?.classList.contains("an-theme-dark");
16563
+ if (container?.parentNode) {
16648
16564
  this.targetEl.style.display = "";
16649
- container.parentNode.removeChild(container);
16565
+ container.remove();
16650
16566
  }
16651
16567
  if (wasDark && !document.querySelector(".an-container.an-theme-dark")) document.body.classList.remove("an-theme-dark");
16652
16568
  if (typeof this.options.onDestroy === "function") this.options.onDestroy(this);
@@ -16712,7 +16628,7 @@ function tail(arr, n = 1) {
16712
16628
  * @returns {T[]}
16713
16629
  */
16714
16630
  function flatten(arr) {
16715
- return arr.reduce((acc, val) => acc.concat(val), []);
16631
+ return arr.flat();
16716
16632
  }
16717
16633
  /**
16718
16634
  * Returns unique elements of an array (using Set).
@@ -16791,7 +16707,7 @@ var env = {
16791
16707
  /** True if running on mobile */
16792
16708
  isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent),
16793
16709
  /** True if touch is supported */
16794
- isTouch: "ontouchstart" in window || navigator.maxTouchPoints > 0,
16710
+ isTouch: "ontouchstart" in globalThis || navigator.maxTouchPoints > 0,
16795
16711
  /** Modifier key name depending on platform */
16796
16712
  modifierKey: /Macintosh/.test(userAgent) ? "metaKey" : "ctrlKey"
16797
16713
  };
@@ -16902,7 +16818,7 @@ var AutumnNote = {
16902
16818
  return this;
16903
16819
  },
16904
16820
  /** Library version */
16905
- version: "1.5.0"
16821
+ version: "1.6.2"
16906
16822
  };
16907
16823
  /**
16908
16824
  * @param {string|Element|NodeList|Element[]} selector