autumnnote 1.5.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -8
- package/dist/autumnnote.css +324 -4
- package/dist/autumnnote.es.js +943 -526
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.umd.js +935 -519
- package/dist/autumnnote.umd.js.map +1 -1
- package/package.json +21 -3
- package/src/js/Context.js +23 -16
- package/src/js/core/detectLang.js +98 -0
- package/src/js/core/dom.js +67 -11
- package/src/js/core/env.js +1 -1
- package/src/js/core/func.js +1 -1
- package/src/js/core/lists.js +1 -1
- package/src/js/core/markdown.js +32 -31
- package/src/js/core/range.js +8 -8
- package/src/js/editing/History.js +10 -10
- package/src/js/editing/Style.js +44 -44
- package/src/js/editing/Table.js +5 -7
- package/src/js/editing/Typing.js +19 -19
- package/src/js/i18n/en.js +2 -0
- package/src/js/i18n/vi.js +2 -0
- package/src/js/index.js +3 -2
- package/src/js/module/AutoSaveRestore.js +2 -4
- package/src/js/module/BubbleToolbar.js +51 -34
- package/src/js/module/Buttons.js +20 -18
- package/src/js/module/Clipboard.js +16 -17
- package/src/js/module/CodeTooltip.js +48 -24
- package/src/js/module/Codeview.js +5 -7
- package/src/js/module/ContextMenu.js +37 -37
- package/src/js/module/Editor.js +77 -26
- package/src/js/module/EmojiDialog.js +24 -18
- package/src/js/module/FindReplace.js +93 -66
- package/src/js/module/Fullscreen.js +1 -1
- package/src/js/module/IconDialog.js +39 -35
- package/src/js/module/ImageCropOverlay.js +13 -13
- package/src/js/module/ImageDialog.js +19 -13
- package/src/js/module/ImageResizer.js +5 -5
- package/src/js/module/ImageTooltip.js +20 -16
- package/src/js/module/LinkDialog.js +20 -14
- package/src/js/module/LinkTooltip.js +15 -12
- package/src/js/module/MarkdownShortcuts.js +11 -14
- package/src/js/module/Mention.js +11 -13
- package/src/js/module/Placeholder.js +1 -1
- package/src/js/module/ShortcutsDialog.js +2 -4
- package/src/js/module/Statusbar.js +5 -7
- package/src/js/module/TableTooltip.js +196 -36
- package/src/js/module/Toolbar.js +35 -34
- package/src/js/module/VideoDialog.js +16 -10
- package/src/js/module/VideoResizer.js +7 -9
- package/src/js/module/VideoTooltip.js +15 -10
- package/src/js/renderer.js +5 -3
- package/src/js/settings.js +53 -36
- package/src/styles/autumnnote.scss +332 -7
package/dist/autumnnote.es.js
CHANGED
|
@@ -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
|
|
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)
|
|
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
|
-
|
|
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 =
|
|
325
|
+
const sel = globalThis.getSelection();
|
|
325
326
|
if (sel) {
|
|
326
327
|
sel.removeAllRanges();
|
|
327
328
|
sel.addRange(range);
|
|
@@ -364,27 +365,71 @@ function trapFocus(container, onEscape) {
|
|
|
364
365
|
const handler = (e) => {
|
|
365
366
|
if (e.key === "Escape") {
|
|
366
367
|
e.stopPropagation();
|
|
367
|
-
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
|
|
375
|
+
const last = els.at(-1);
|
|
375
376
|
if (e.shiftKey) {
|
|
376
377
|
if (document.activeElement === first) {
|
|
377
378
|
e.preventDefault();
|
|
378
|
-
last.focus();
|
|
379
|
+
/** @type {HTMLElement} */ last.focus();
|
|
379
380
|
}
|
|
380
381
|
} else if (document.activeElement === last) {
|
|
381
382
|
e.preventDefault();
|
|
382
|
-
first.focus();
|
|
383
|
+
/** @type {HTMLElement} */ first.focus();
|
|
383
384
|
}
|
|
384
385
|
};
|
|
385
386
|
document.addEventListener("keydown", handler);
|
|
386
387
|
return () => document.removeEventListener("keydown", handler);
|
|
387
388
|
}
|
|
389
|
+
/**
|
|
390
|
+
* Makes a dialog box draggable by its handle element.
|
|
391
|
+
* On first drag the box is pinned to its current viewport coordinates via
|
|
392
|
+
* `position:fixed`, freeing it from the parent flex container's centering.
|
|
393
|
+
* The position is clamped to the visible viewport.
|
|
394
|
+
*
|
|
395
|
+
* @param {HTMLElement} handle Element the user grabs (title bar / header)
|
|
396
|
+
* @param {HTMLElement} box Element that actually moves
|
|
397
|
+
* @returns {Function} Cleanup function (removes the mousedown listener)
|
|
398
|
+
*/
|
|
399
|
+
function makeDraggable(handle, box) {
|
|
400
|
+
handle.style.cursor = "grab";
|
|
401
|
+
const onMousedown = (e) => {
|
|
402
|
+
if (e.button !== 0) return;
|
|
403
|
+
if (e.target.closest("button, input, select, textarea, a")) return;
|
|
404
|
+
e.preventDefault();
|
|
405
|
+
if (!box.dataset.anDragPinned) {
|
|
406
|
+
const r = box.getBoundingClientRect();
|
|
407
|
+
box.style.position = "fixed";
|
|
408
|
+
box.style.margin = "0";
|
|
409
|
+
box.style.left = `${r.left}px`;
|
|
410
|
+
box.style.top = `${r.top}px`;
|
|
411
|
+
box.dataset.anDragPinned = "1";
|
|
412
|
+
}
|
|
413
|
+
const startX = e.clientX - Number.parseFloat(box.style.left);
|
|
414
|
+
const startY = e.clientY - Number.parseFloat(box.style.top);
|
|
415
|
+
handle.style.cursor = "grabbing";
|
|
416
|
+
const onMove = (ev) => {
|
|
417
|
+
const bw = box.offsetWidth;
|
|
418
|
+
const bh = box.offsetHeight;
|
|
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`;
|
|
421
|
+
};
|
|
422
|
+
const onUp = () => {
|
|
423
|
+
handle.style.cursor = "grab";
|
|
424
|
+
document.removeEventListener("mousemove", onMove);
|
|
425
|
+
document.removeEventListener("mouseup", onUp);
|
|
426
|
+
};
|
|
427
|
+
document.addEventListener("mousemove", onMove);
|
|
428
|
+
document.addEventListener("mouseup", onUp);
|
|
429
|
+
};
|
|
430
|
+
handle.addEventListener("mousedown", onMousedown);
|
|
431
|
+
return () => handle.removeEventListener("mousedown", onMousedown);
|
|
432
|
+
}
|
|
388
433
|
//#endregion
|
|
389
434
|
//#region src/js/core/range.js
|
|
390
435
|
/**
|
|
@@ -418,10 +463,10 @@ var WrappedRange = class {
|
|
|
418
463
|
return range;
|
|
419
464
|
}
|
|
420
465
|
/**
|
|
421
|
-
* Select this wrapped range in the
|
|
466
|
+
* Select this wrapped range in the globalThis.
|
|
422
467
|
*/
|
|
423
468
|
select() {
|
|
424
|
-
const sel =
|
|
469
|
+
const sel = globalThis.getSelection();
|
|
425
470
|
if (!sel) return;
|
|
426
471
|
sel.removeAllRanges();
|
|
427
472
|
sel.addRange(this.toNativeRange());
|
|
@@ -474,13 +519,13 @@ function fromNativeRange(range) {
|
|
|
474
519
|
return new WrappedRange(range.startContainer, range.startOffset, range.endContainer, range.endOffset);
|
|
475
520
|
}
|
|
476
521
|
/**
|
|
477
|
-
* Returns a WrappedRange for the current
|
|
522
|
+
* Returns a WrappedRange for the current globalThis selection,
|
|
478
523
|
* optionally restricted to a given editable element.
|
|
479
524
|
* @param {HTMLElement} [editable]
|
|
480
525
|
* @returns {WrappedRange|null}
|
|
481
526
|
*/
|
|
482
527
|
function currentRange(editable) {
|
|
483
|
-
const sel =
|
|
528
|
+
const sel = globalThis.getSelection();
|
|
484
529
|
if (!sel || sel.rangeCount === 0) return null;
|
|
485
530
|
const native = sel.getRangeAt(0);
|
|
486
531
|
if (editable && !editable.contains(native.commonAncestorContainer)) return null;
|
|
@@ -509,7 +554,7 @@ function collapsedRange(node, offset = 0) {
|
|
|
509
554
|
* @returns {boolean}
|
|
510
555
|
*/
|
|
511
556
|
function isSelectionInside(el) {
|
|
512
|
-
const sel =
|
|
557
|
+
const sel = globalThis.getSelection();
|
|
513
558
|
if (!sel || sel.rangeCount === 0) return false;
|
|
514
559
|
return el.contains(sel.getRangeAt(0).commonAncestorContainer);
|
|
515
560
|
}
|
|
@@ -518,7 +563,7 @@ function isSelectionInside(el) {
|
|
|
518
563
|
* @param {Function} fn
|
|
519
564
|
*/
|
|
520
565
|
function withSavedRange(fn) {
|
|
521
|
-
const sel =
|
|
566
|
+
const sel = globalThis.getSelection();
|
|
522
567
|
if (!sel || sel.rangeCount === 0) {
|
|
523
568
|
fn(null);
|
|
524
569
|
return;
|
|
@@ -562,16 +607,16 @@ var italic = () => execCommand("italic");
|
|
|
562
607
|
* execCommand's state detection is unreliable.
|
|
563
608
|
*/
|
|
564
609
|
function underline() {
|
|
565
|
-
const sel =
|
|
610
|
+
const sel = globalThis.getSelection();
|
|
566
611
|
if (!sel || !sel.rangeCount) return;
|
|
567
612
|
let container = sel.getRangeAt(0).commonAncestorContainer;
|
|
568
613
|
if (container.nodeType === 3) container = container.parentElement;
|
|
569
|
-
const uEl = container
|
|
614
|
+
const uEl = container?.closest("u");
|
|
570
615
|
const nativeState = document.queryCommandState("underline");
|
|
571
616
|
if (uEl && !nativeState) {
|
|
572
617
|
const parent = uEl.parentNode;
|
|
573
618
|
while (uEl.firstChild) parent.insertBefore(uEl.firstChild, uEl);
|
|
574
|
-
|
|
619
|
+
uEl.remove();
|
|
575
620
|
return;
|
|
576
621
|
}
|
|
577
622
|
execCommand("underline");
|
|
@@ -582,16 +627,16 @@ function underline() {
|
|
|
582
627
|
* execCommand's state detection is unreliable (mirrors underline() logic).
|
|
583
628
|
*/
|
|
584
629
|
function strikethrough() {
|
|
585
|
-
const sel =
|
|
630
|
+
const sel = globalThis.getSelection();
|
|
586
631
|
if (!sel || !sel.rangeCount) return;
|
|
587
632
|
let sc = sel.getRangeAt(0).startContainer;
|
|
588
633
|
if (sc.nodeType === 3) sc = sc.parentElement;
|
|
589
|
-
const sEl = sc
|
|
634
|
+
const sEl = sc?.closest("s") || sc?.closest("strike");
|
|
590
635
|
const nativeState = document.queryCommandState("strikeThrough");
|
|
591
636
|
if (sEl && !nativeState) {
|
|
592
637
|
const parent = sEl.parentNode;
|
|
593
638
|
while (sEl.firstChild) parent.insertBefore(sEl.firstChild, sEl);
|
|
594
|
-
|
|
639
|
+
sEl.remove();
|
|
595
640
|
return;
|
|
596
641
|
}
|
|
597
642
|
execCommand("strikeThrough");
|
|
@@ -623,10 +668,10 @@ var fontName = (name) => execCommand("fontName", name);
|
|
|
623
668
|
* Sets the font size (in pt or with unit) for the selection.
|
|
624
669
|
* Uses a span-based approach to set px sizes precisely.
|
|
625
670
|
* @param {string} size - e.g. '14px'
|
|
626
|
-
* @param {HTMLElement} [editable] - scoping element to avoid touching nodes outside this editor
|
|
671
|
+
* @param {HTMLElement|Document} [editable] - scoping element to avoid touching nodes outside this editor
|
|
627
672
|
*/
|
|
628
673
|
function fontSize(size, editable = document) {
|
|
629
|
-
const sel =
|
|
674
|
+
const sel = globalThis.getSelection();
|
|
630
675
|
const wasCollapsed = !sel || !sel.rangeCount || sel.getRangeAt(0).collapsed;
|
|
631
676
|
if (wasCollapsed && sel && sel.rangeCount > 0) {
|
|
632
677
|
try {
|
|
@@ -652,12 +697,12 @@ function fontSize(size, editable = document) {
|
|
|
652
697
|
span.style.fontSize = size;
|
|
653
698
|
el.parentNode.insertBefore(span, el);
|
|
654
699
|
while (el.firstChild) span.appendChild(el.firstChild);
|
|
655
|
-
el.
|
|
700
|
+
el.remove();
|
|
656
701
|
newSpans.push(span);
|
|
657
702
|
});
|
|
658
703
|
if (!wasCollapsed && sel && newSpans.length > 0) {
|
|
659
704
|
const first = newSpans[0];
|
|
660
|
-
const last = newSpans
|
|
705
|
+
const last = newSpans.at(-1);
|
|
661
706
|
try {
|
|
662
707
|
const nr = document.createRange();
|
|
663
708
|
const startNode = first.firstChild || first;
|
|
@@ -701,11 +746,11 @@ var indent = () => execCommand("indent");
|
|
|
701
746
|
* (which would destroy the ul > li checklist structure).
|
|
702
747
|
*/
|
|
703
748
|
function outdent() {
|
|
704
|
-
const sel =
|
|
749
|
+
const sel = globalThis.getSelection();
|
|
705
750
|
if (sel && sel.rangeCount) {
|
|
706
751
|
let container = sel.getRangeAt(0).commonAncestorContainer;
|
|
707
752
|
if (container.nodeType === 3) container = container.parentElement;
|
|
708
|
-
const checkLi = container
|
|
753
|
+
const checkLi = container?.closest(".an-checklist li");
|
|
709
754
|
if (checkLi) {
|
|
710
755
|
_checklistItemToP(checkLi);
|
|
711
756
|
return;
|
|
@@ -735,7 +780,7 @@ function _checklistItemToP(checkLi) {
|
|
|
735
780
|
if (child.nodeType === 1 && child.tagName === "INPUT") continue;
|
|
736
781
|
p.appendChild(child.cloneNode(true));
|
|
737
782
|
}
|
|
738
|
-
p.innerHTML = p.innerHTML.
|
|
783
|
+
p.innerHTML = p.innerHTML.replaceAll("", "");
|
|
739
784
|
if (!p.hasChildNodes() || !p.textContent.trim()) {
|
|
740
785
|
p.innerHTML = "";
|
|
741
786
|
p.appendChild(document.createTextNode("\xA0"));
|
|
@@ -747,14 +792,14 @@ function _checklistItemToP(checkLi) {
|
|
|
747
792
|
checkUl.parentNode.insertBefore(newUl, checkUl.nextSibling);
|
|
748
793
|
}
|
|
749
794
|
checkUl.parentNode.insertBefore(p, checkUl.nextSibling);
|
|
750
|
-
|
|
751
|
-
if (checkUl.children.length === 0) checkUl.
|
|
795
|
+
checkLi.remove();
|
|
796
|
+
if (checkUl.children.length === 0) checkUl.remove();
|
|
752
797
|
try {
|
|
753
798
|
const nr = document.createRange();
|
|
754
799
|
const firstChild = p.firstChild;
|
|
755
800
|
nr.setStart(firstChild && firstChild.nodeType === 3 ? firstChild : p, 0);
|
|
756
801
|
nr.collapse(true);
|
|
757
|
-
const s =
|
|
802
|
+
const s = globalThis.getSelection();
|
|
758
803
|
if (s) {
|
|
759
804
|
s.removeAllRanges();
|
|
760
805
|
s.addRange(nr);
|
|
@@ -778,7 +823,7 @@ var insertOrderedList = () => execCommand("insertOrderedList");
|
|
|
778
823
|
* @param {string} value - Line-height value to apply; typically a unitless multiplier (for example, "1.5").
|
|
779
824
|
*/
|
|
780
825
|
function lineHeight(value) {
|
|
781
|
-
const sel =
|
|
826
|
+
const sel = globalThis.getSelection();
|
|
782
827
|
if (!sel || sel.rangeCount === 0) return;
|
|
783
828
|
const range = sel.getRangeAt(0);
|
|
784
829
|
const BLOCK_TAGS = new Set([
|
|
@@ -827,25 +872,25 @@ function lineHeight(value) {
|
|
|
827
872
|
/**
|
|
828
873
|
* Wraps the selection in an inline <code> element, or unwraps it if the
|
|
829
874
|
* cursor is already inside a <code> that is not inside a <pre>.
|
|
830
|
-
* @param {HTMLElement} [
|
|
875
|
+
* @param {HTMLElement} [_editable]
|
|
831
876
|
*/
|
|
832
|
-
function toggleInlineCode(
|
|
833
|
-
const sel =
|
|
877
|
+
function toggleInlineCode(_editable) {
|
|
878
|
+
const sel = globalThis.getSelection();
|
|
834
879
|
if (!sel || !sel.rangeCount) return;
|
|
835
880
|
const range = sel.getRangeAt(0);
|
|
836
881
|
let container = range.commonAncestorContainer;
|
|
837
882
|
if (container.nodeType === 3) container = container.parentElement;
|
|
838
|
-
const codeEl = container
|
|
883
|
+
const codeEl = container?.closest("code");
|
|
839
884
|
if (codeEl && !codeEl.closest("pre")) {
|
|
840
885
|
const parent = codeEl.parentNode;
|
|
841
886
|
const prevSibling = codeEl.previousSibling;
|
|
842
887
|
const movedChildren = Array.from(codeEl.childNodes);
|
|
843
888
|
while (codeEl.firstChild) parent.insertBefore(codeEl.firstChild, codeEl);
|
|
844
|
-
|
|
845
|
-
|
|
889
|
+
codeEl.remove();
|
|
890
|
+
parent?.normalize();
|
|
846
891
|
if (movedChildren.length > 0) try {
|
|
847
892
|
const firstMoved = movedChildren[0];
|
|
848
|
-
const lastMoved = movedChildren
|
|
893
|
+
const lastMoved = movedChildren.at(-1);
|
|
849
894
|
const nr = document.createRange();
|
|
850
895
|
const anchorNode = firstMoved.parentNode === parent ? firstMoved : prevSibling ? prevSibling.nextSibling : parent.firstChild;
|
|
851
896
|
if (anchorNode) {
|
|
@@ -886,11 +931,11 @@ function toggleInlineCode(editable) {
|
|
|
886
931
|
* @returns {boolean}
|
|
887
932
|
*/
|
|
888
933
|
function isInlineCode() {
|
|
889
|
-
const sel =
|
|
934
|
+
const sel = globalThis.getSelection();
|
|
890
935
|
if (!sel || !sel.rangeCount) return false;
|
|
891
936
|
let sc = sel.getRangeAt(0).startContainer;
|
|
892
937
|
if (sc.nodeType === 3) sc = sc.parentElement;
|
|
893
|
-
const code = sc
|
|
938
|
+
const code = sc?.closest("code");
|
|
894
939
|
return !!(code && !code.closest("pre"));
|
|
895
940
|
}
|
|
896
941
|
/**
|
|
@@ -908,30 +953,30 @@ function isInlineCode() {
|
|
|
908
953
|
* Empty or whitespace-only selections do not create a checklist.
|
|
909
954
|
*/
|
|
910
955
|
function toggleChecklist() {
|
|
911
|
-
const sel =
|
|
956
|
+
const sel = globalThis.getSelection();
|
|
912
957
|
if (!sel || !sel.rangeCount) return;
|
|
913
958
|
const range = sel.getRangeAt(0);
|
|
914
959
|
let container = range.commonAncestorContainer;
|
|
915
960
|
if (container.nodeType === 3) container = container.parentElement;
|
|
916
|
-
const ul = container
|
|
961
|
+
const ul = container?.closest(".an-checklist");
|
|
917
962
|
if (ul) {
|
|
918
963
|
const selectedLis = Array.from(ul.querySelectorAll("li")).filter((li) => sel.containsNode(li, true));
|
|
919
964
|
if (selectedLis.length > 0) {
|
|
920
|
-
let firstP = null;
|
|
965
|
+
/** @type {HTMLElement|null} */ let firstP = null;
|
|
921
966
|
selectedLis.forEach((li) => {
|
|
922
967
|
const p = document.createElement("p");
|
|
923
968
|
for (const child of li.childNodes) {
|
|
924
969
|
if (child.nodeType === 1 && child.tagName === "INPUT") continue;
|
|
925
970
|
p.appendChild(child.cloneNode(true));
|
|
926
971
|
}
|
|
927
|
-
p.innerHTML = p.innerHTML.
|
|
972
|
+
p.innerHTML = p.innerHTML.replaceAll("", "");
|
|
928
973
|
if (!p.hasChildNodes() || !p.textContent.trim()) {
|
|
929
974
|
p.innerHTML = "";
|
|
930
975
|
p.appendChild(document.createTextNode("\xA0"));
|
|
931
976
|
}
|
|
932
977
|
ul.parentNode.insertBefore(p, ul);
|
|
933
978
|
if (!firstP) firstP = p;
|
|
934
|
-
|
|
979
|
+
li.remove();
|
|
935
980
|
});
|
|
936
981
|
if (ul.children.length === 0) ul.remove();
|
|
937
982
|
if (firstP) {
|
|
@@ -959,7 +1004,7 @@ function toggleChecklist() {
|
|
|
959
1004
|
]);
|
|
960
1005
|
let block = container;
|
|
961
1006
|
while (block && block.parentNode && !BLOCK_TAGS.has(block.tagName)) block = block.parentNode;
|
|
962
|
-
const itemText = block && BLOCK_TAGS.has(block.tagName) ? Array.from(block.childNodes).map((n) => n.textContent).join("").
|
|
1007
|
+
const itemText = block && BLOCK_TAGS.has(block.tagName) ? Array.from(block.childNodes).map((n) => n.textContent).join("").replaceAll("\xA0", " ") : "";
|
|
963
1008
|
const ul = document.createElement("ul");
|
|
964
1009
|
ul.className = "an-checklist";
|
|
965
1010
|
const li = document.createElement("li");
|
|
@@ -1015,7 +1060,7 @@ function toggleChecklist() {
|
|
|
1015
1060
|
if (blocks.length === 0) return;
|
|
1016
1061
|
const newUl = document.createElement("ul");
|
|
1017
1062
|
newUl.className = "an-checklist";
|
|
1018
|
-
let lastTextNode = null;
|
|
1063
|
+
/** @type {Text|null} */ let lastTextNode = null;
|
|
1019
1064
|
blocks.forEach((block) => {
|
|
1020
1065
|
const li = document.createElement("li");
|
|
1021
1066
|
const cb = document.createElement("input");
|
|
@@ -1030,7 +1075,7 @@ function toggleChecklist() {
|
|
|
1030
1075
|
});
|
|
1031
1076
|
const firstBlock = blocks[0];
|
|
1032
1077
|
firstBlock.parentNode.insertBefore(newUl, firstBlock);
|
|
1033
|
-
blocks.forEach((block) => block.
|
|
1078
|
+
blocks.forEach((block) => block.remove());
|
|
1034
1079
|
if (lastTextNode) {
|
|
1035
1080
|
const nr = document.createRange();
|
|
1036
1081
|
nr.setStart(lastTextNode, lastTextNode.textContent.length);
|
|
@@ -1044,11 +1089,11 @@ function toggleChecklist() {
|
|
|
1044
1089
|
* @returns {boolean}
|
|
1045
1090
|
*/
|
|
1046
1091
|
function isInChecklist() {
|
|
1047
|
-
const sel =
|
|
1092
|
+
const sel = globalThis.getSelection();
|
|
1048
1093
|
if (!sel || !sel.rangeCount) return false;
|
|
1049
1094
|
let container = sel.getRangeAt(0).commonAncestorContainer;
|
|
1050
1095
|
if (container.nodeType === 3) container = container.parentElement;
|
|
1051
|
-
return !!
|
|
1096
|
+
return !!container?.closest(".an-checklist li");
|
|
1052
1097
|
}
|
|
1053
1098
|
//#endregion
|
|
1054
1099
|
//#region src/js/module/Buttons.js
|
|
@@ -1059,12 +1104,14 @@ function isInChecklist() {
|
|
|
1059
1104
|
*/
|
|
1060
1105
|
/**
|
|
1061
1106
|
* @typedef {object} DropdownDef
|
|
1062
|
-
* @property {string} name
|
|
1063
|
-
* @property {'select'} type
|
|
1107
|
+
* @property {string} name - unique identifier
|
|
1108
|
+
* @property {'select'} type - discriminator for Toolbar renderer
|
|
1064
1109
|
* @property {string} tooltip
|
|
1065
|
-
* @property {string
|
|
1066
|
-
* @property {Function} action
|
|
1067
|
-
* @property {Function} [getValue]
|
|
1110
|
+
* @property {Array<string|{value:string,label:string,disabled?:boolean}>} [items] - overridden at render time from options
|
|
1111
|
+
* @property {Function} action - called with (context, value)
|
|
1112
|
+
* @property {Function} [getValue] - called with (context) to get current value
|
|
1113
|
+
* @property {string} [selectClass] - extra CSS class(es) for the <select>
|
|
1114
|
+
* @property {string} [placeholder] - placeholder text for the empty option
|
|
1068
1115
|
*/
|
|
1069
1116
|
/**
|
|
1070
1117
|
* @typedef {object} ButtonDef
|
|
@@ -1128,11 +1175,11 @@ var boldBtn = btn("bold", "bold", "Bold (Ctrl+B)", () => bold(), () => document.
|
|
|
1128
1175
|
var italicBtn = btn("italic", "italic", "Italic (Ctrl+I)", () => italic(), () => document.queryCommandState("italic"));
|
|
1129
1176
|
var underlineBtn = btn("underline", "underline", "Underline (Ctrl+U)", () => underline(), () => {
|
|
1130
1177
|
if (document.queryCommandState("underline")) return true;
|
|
1131
|
-
const sel =
|
|
1178
|
+
const sel = globalThis.getSelection();
|
|
1132
1179
|
if (!sel || !sel.rangeCount) return false;
|
|
1133
1180
|
let sc = sel.getRangeAt(0).startContainer;
|
|
1134
1181
|
if (sc.nodeType === 3) sc = sc.parentElement;
|
|
1135
|
-
return !!(sc && sc.closest
|
|
1182
|
+
return !!(sc && sc.closest("u"));
|
|
1136
1183
|
});
|
|
1137
1184
|
var strikeBtn = btn("strikethrough", "strikethrough", "Strikethrough", () => strikethrough(), () => document.queryCommandState("strikeThrough"));
|
|
1138
1185
|
var superscriptBtn = btn("superscript", "superscript", "Superscript", () => superscript(), () => document.queryCommandState("superscript"));
|
|
@@ -1191,15 +1238,15 @@ var fontSizeBtn = {
|
|
|
1191
1238
|
action: (ctx, value) => fontSize(value, ctx.layoutInfo.editable),
|
|
1192
1239
|
getValue: (ctx) => {
|
|
1193
1240
|
try {
|
|
1194
|
-
const sel =
|
|
1241
|
+
const sel = globalThis.getSelection();
|
|
1195
1242
|
if (sel && sel.rangeCount) {
|
|
1196
1243
|
let el = sel.getRangeAt(0).startContainer;
|
|
1197
|
-
if (el.nodeType === 3) el = el.parentElement;
|
|
1244
|
+
if (el && el.nodeType === 3) el = el.parentElement;
|
|
1198
1245
|
while (el && el.nodeType === 1 && !el.style.fontSize) el = el.parentElement;
|
|
1199
|
-
const size = el && el.style
|
|
1246
|
+
const size = el && el.style.fontSize ? el.style.fontSize : "";
|
|
1200
1247
|
if (size) return size;
|
|
1201
1248
|
}
|
|
1202
|
-
const editable = ctx
|
|
1249
|
+
const editable = ctx?.layoutInfo?.editable;
|
|
1203
1250
|
if (editable) return editable.style.fontSize || "";
|
|
1204
1251
|
return "";
|
|
1205
1252
|
} catch {
|
|
@@ -1303,7 +1350,7 @@ var lineHeightBtn = {
|
|
|
1303
1350
|
action: (_ctx, value) => lineHeight(value),
|
|
1304
1351
|
getValue: () => {
|
|
1305
1352
|
try {
|
|
1306
|
-
const sel =
|
|
1353
|
+
const sel = globalThis.getSelection();
|
|
1307
1354
|
if (!sel || !sel.rangeCount) return "";
|
|
1308
1355
|
const BLOCKS = new Set([
|
|
1309
1356
|
"P",
|
|
@@ -1321,8 +1368,11 @@ var lineHeightBtn = {
|
|
|
1321
1368
|
"TH"
|
|
1322
1369
|
]);
|
|
1323
1370
|
let el = sel.getRangeAt(0).startContainer;
|
|
1324
|
-
if (el.nodeType === 3) el = el.parentElement;
|
|
1325
|
-
while (el && !BLOCKS.has(
|
|
1371
|
+
if (el && el.nodeType === 3) el = el.parentElement;
|
|
1372
|
+
while (el && !BLOCKS.has(
|
|
1373
|
+
/** @type {Element} */
|
|
1374
|
+
el.tagName
|
|
1375
|
+
)) el = el.parentElement;
|
|
1326
1376
|
if (!el) return "";
|
|
1327
1377
|
return el.style.lineHeight || getComputedStyle(el).lineHeight || "";
|
|
1328
1378
|
} catch {
|
|
@@ -1416,47 +1466,64 @@ var defaultToolbar = [
|
|
|
1416
1466
|
*/
|
|
1417
1467
|
/**
|
|
1418
1468
|
* @typedef {object} AsnOptions
|
|
1419
|
-
* @property {string} [placeholder]
|
|
1420
|
-
* @property {number} [height]
|
|
1421
|
-
* @property {number} [minHeight]
|
|
1422
|
-
* @property {number} [maxHeight]
|
|
1423
|
-
* @property {boolean} [focus]
|
|
1424
|
-
* @property {boolean} [resizable]
|
|
1425
|
-
* @property {Array} [toolbar]
|
|
1426
|
-
* @property {boolean} [
|
|
1427
|
-
* @property {
|
|
1469
|
+
* @property {string} [placeholder] - Placeholder text when editor is empty
|
|
1470
|
+
* @property {number} [height] - Editor height in px (min)
|
|
1471
|
+
* @property {number} [minHeight] - Minimum height in px
|
|
1472
|
+
* @property {number} [maxHeight] - Maximum height in px (0 = unlimited)
|
|
1473
|
+
* @property {boolean} [focus] - Auto-focus on init
|
|
1474
|
+
* @property {boolean} [resizable] - Show resize handle
|
|
1475
|
+
* @property {Array} [toolbar] - Toolbar button group config
|
|
1476
|
+
* @property {boolean} [useBootstrap] - Use Bootstrap button classes on toolbar buttons
|
|
1477
|
+
* @property {string} [toolbarButtonClass] - CSS classes for Bootstrap toolbar buttons
|
|
1478
|
+
* @property {boolean} [useFontAwesome] - Use Font Awesome icons (default: true)
|
|
1479
|
+
* @property {string} [fontAwesomeClass] - Font Awesome prefix class, e.g. 'fas' or 'fa-solid'
|
|
1480
|
+
* @property {boolean} [pasteAsPlainText] - Force plain-text paste
|
|
1481
|
+
* @property {boolean} [pasteCleanHTML] - Sanitise HTML on paste
|
|
1428
1482
|
* @property {boolean} [pasteStripAttributes] - Strip class/style/data-* from pasted HTML (default: false)
|
|
1429
|
-
* @property {boolean} [allowImageUpload]
|
|
1430
|
-
* @property {number} [maxImageSize]
|
|
1431
|
-
* @property {number} [tabSize]
|
|
1432
|
-
* @property {
|
|
1433
|
-
* @property {
|
|
1434
|
-
* @property {
|
|
1435
|
-
* @property {
|
|
1436
|
-
* @property {
|
|
1437
|
-
* @property {
|
|
1438
|
-
* @property {
|
|
1439
|
-
* @property {
|
|
1440
|
-
* @property {
|
|
1441
|
-
* @property {
|
|
1442
|
-
* @property {boolean} [
|
|
1443
|
-
* @property {
|
|
1444
|
-
* @property {string} [
|
|
1445
|
-
* @property {
|
|
1446
|
-
* @property {
|
|
1447
|
-
* @property {
|
|
1448
|
-
* @property {
|
|
1449
|
-
* @property {
|
|
1450
|
-
* @property {
|
|
1451
|
-
* @property {
|
|
1452
|
-
* @property {
|
|
1453
|
-
* @property {string
|
|
1483
|
+
* @property {boolean} [allowImageUpload] - Allow file upload in image dialog
|
|
1484
|
+
* @property {number} [maxImageSize] - Max upload size in MB
|
|
1485
|
+
* @property {number} [tabSize] - Spaces per tab in non-list context
|
|
1486
|
+
* @property {number} [historyLimit] - Maximum undo/redo history steps
|
|
1487
|
+
* @property {string} [defaultFontFamily] - Default font family applied to the editable area on init
|
|
1488
|
+
* @property {string} [defaultFontSize] - Default font size applied to the editable area on init (e.g. '14px')
|
|
1489
|
+
* @property {string[]} [fontFamilies] - Font families shown in the font-family toolbar dropdown
|
|
1490
|
+
* @property {Function} [onChange] - Callback on content change
|
|
1491
|
+
* @property {Function} [onFocus] - Callback on focus
|
|
1492
|
+
* @property {Function} [onBlur] - Callback on blur
|
|
1493
|
+
* @property {Function} [onInit] - Callback after the editor has initialised
|
|
1494
|
+
* @property {Function} [onImageUpload] - Custom upload handler: (files) => void
|
|
1495
|
+
* @property {Function} [onImageError] - Callback when an image upload error occurs
|
|
1496
|
+
* @property {boolean} [stickyToolbar] - Stick the toolbar to the viewport top when scrolling
|
|
1497
|
+
* @property {number} [stickyToolbarOffset] - Top offset in px for sticky toolbar (e.g. fixed nav height)
|
|
1498
|
+
* @property {string} [theme] - 'light' (default) | 'dark'
|
|
1499
|
+
* @property {boolean} [codeHighlight] - Auto-load Prism.js for syntax highlighting of code blocks
|
|
1500
|
+
* @property {string} [codeHighlightCDN] - CDN base URL for Prism assets (defaults to cdnjs)
|
|
1501
|
+
* @property {boolean} [markdownPaste] - Convert pasted Markdown text to HTML (default: true)
|
|
1502
|
+
* @property {boolean} [readOnly] - Start editor in read-only / non-editable mode
|
|
1503
|
+
* @property {boolean} [spellcheck] - Enable browser spellcheck in the editable area (default: true)
|
|
1504
|
+
* @property {string} [direction] - Text direction: 'ltr' (default) | 'rtl'
|
|
1505
|
+
* @property {string} [toolbarOverflow] - Toolbar overflow strategy: 'wrap' (default) | 'scroll'
|
|
1506
|
+
* @property {boolean} [autoSave] - Auto-save content to localStorage on change
|
|
1507
|
+
* @property {string} [autoSaveKey] - localStorage key used for auto-save (default: 'autumnnote-autosave')
|
|
1508
|
+
* @property {number} [maxChars] - Maximum character count (0 = unlimited). Shows warning in statusbar.
|
|
1509
|
+
* @property {number} [maxWords] - Maximum word count (0 = unlimited). Shows warning in statusbar.
|
|
1510
|
+
* @property {boolean} [tableHeaderRow] - Insert a header row (<thead><th>) when creating tables
|
|
1511
|
+
* @property {Function} [onPaste] - Callback fired on every paste: ({ text, html }) => void
|
|
1512
|
+
* @property {Function} [onSelectionChange] - Callback fired on cursor/selection change: (context) => void
|
|
1513
|
+
* @property {string[]} [colorSwatches] - Custom brand colour swatches prepended to the colour-picker palette
|
|
1454
1514
|
* @property {Function} [onDestroy] - Callback fired when the editor is destroyed: (context) => void
|
|
1455
1515
|
* @property {Function} [onCharLimitReached] - Callback fired when the character limit is hit: (context) => void
|
|
1456
1516
|
* @property {Function} [onWordLimitReached] - Callback fired when the word limit is hit: (context) => void
|
|
1457
|
-
* @property {string} [focusColor]
|
|
1517
|
+
* @property {string} [focusColor] - Custom focus ring colour, e.g. '#f97316'. Overrides the default blue.
|
|
1518
|
+
* @property {boolean} [autoSaveRestore] - Show a restore banner when a previously auto-saved draft exists
|
|
1519
|
+
* @property {number} [autoSaveRestoreTimeout] - Maximum age in days for a draft to be offered for restore (0 = no expiry)
|
|
1520
|
+
* @property {Function} [onAutoSaveRestore] - Callback fired after the user chooses to restore a draft
|
|
1521
|
+
* @property {boolean} [markdownShortcuts] - Convert markdown syntax typed inline to HTML
|
|
1522
|
+
* @property {boolean} [bubbleToolbar] - Show a mini floating toolbar above text selections
|
|
1523
|
+
* @property {string[]} [bubbleToolbarItems] - Button names for the bubble toolbar
|
|
1524
|
+
* @property {object|null} [mention] - @mention configuration (onSearch, minChars, ...)
|
|
1525
|
+
* @property {string} [lang] - Display language or partial locale object override
|
|
1458
1526
|
*/
|
|
1459
|
-
/** @type {AsnOptions} */
|
|
1460
1527
|
var defaultOptions = {
|
|
1461
1528
|
placeholder: "",
|
|
1462
1529
|
height: 200,
|
|
@@ -1855,6 +1922,8 @@ var en = {
|
|
|
1855
1922
|
rowHeight: "Row Height",
|
|
1856
1923
|
tableBorderWidth: "Table Border Width",
|
|
1857
1924
|
deleteTable: "Delete Table",
|
|
1925
|
+
cellBackground: "Cell Background",
|
|
1926
|
+
noShading: "No Shading",
|
|
1858
1927
|
columnWidthPx: "Column Width (px)",
|
|
1859
1928
|
rowHeightPx: "Row Height (px)",
|
|
1860
1929
|
tableBorderWidthPx: "Table Border Width (px)",
|
|
@@ -2210,6 +2279,8 @@ var locales = {
|
|
|
2210
2279
|
rowHeight: "Chiều cao hàng",
|
|
2211
2280
|
tableBorderWidth: "Độ rộng viền bảng",
|
|
2212
2281
|
deleteTable: "Xóa bảng",
|
|
2282
|
+
cellBackground: "Màu Nền Ô",
|
|
2283
|
+
noShading: "Xóa Màu Nền",
|
|
2213
2284
|
columnWidthPx: "Chiều rộng cột (px)",
|
|
2214
2285
|
rowHeightPx: "Chiều cao hàng (px)",
|
|
2215
2286
|
tableBorderWidthPx: "Độ rộng viền bảng (px)",
|
|
@@ -4404,14 +4475,17 @@ function renderLayout(targetEl, options) {
|
|
|
4404
4475
|
} catch (_) {}
|
|
4405
4476
|
if (!initialContent) initialContent = targetEl.tagName === "TEXTAREA" ? (targetEl.value || "").trim() : (targetEl.innerHTML || "").trim();
|
|
4406
4477
|
editable.innerHTML = sanitiseHTML(initialContent, { allowIframes: true });
|
|
4407
|
-
const defaultFont = options.defaultFontFamily || options.fontFamilies
|
|
4478
|
+
const defaultFont = options.defaultFontFamily || options.fontFamilies?.[0];
|
|
4408
4479
|
if (defaultFont) editable.style.fontFamily = defaultFont;
|
|
4409
4480
|
if (options.defaultFontSize) editable.style.fontSize = options.defaultFontSize;
|
|
4410
4481
|
if (options.height) editable.style.minHeight = `${options.height}px`;
|
|
4411
4482
|
else if (options.minHeight) editable.style.minHeight = `${options.minHeight}px`;
|
|
4412
4483
|
if (options.maxHeight) editable.style.maxHeight = `${options.maxHeight}px`;
|
|
4413
4484
|
container.appendChild(editable);
|
|
4414
|
-
if (options.theme === "dark")
|
|
4485
|
+
if (options.theme === "dark") {
|
|
4486
|
+
container.classList.add("an-theme-dark");
|
|
4487
|
+
document.body.classList.add("an-theme-dark");
|
|
4488
|
+
}
|
|
4415
4489
|
if (options.readOnly) {
|
|
4416
4490
|
container.classList.add("an-disabled");
|
|
4417
4491
|
editable.querySelectorAll("ul.an-checklist input[type=\"checkbox\"]").forEach((cb) => {
|
|
@@ -4449,7 +4523,7 @@ var History = class {
|
|
|
4449
4523
|
constructor(editable, limit = 100) {
|
|
4450
4524
|
this.editable = editable;
|
|
4451
4525
|
this._limit = limit;
|
|
4452
|
-
/** @type {Array<{html: string,
|
|
4526
|
+
/** @type {Array<{html: string, images?: Record<string,string>, sel: {start: number, end: number}|null}>} */
|
|
4453
4527
|
this.stack = [];
|
|
4454
4528
|
this.stackOffset = -1;
|
|
4455
4529
|
this._savePoint();
|
|
@@ -4463,7 +4537,7 @@ var History = class {
|
|
|
4463
4537
|
* @returns {{ start: number, end: number }|null}
|
|
4464
4538
|
*/
|
|
4465
4539
|
_serializeSelection() {
|
|
4466
|
-
const sel =
|
|
4540
|
+
const sel = globalThis.getSelection();
|
|
4467
4541
|
if (!sel || sel.rangeCount === 0) return null;
|
|
4468
4542
|
const range = sel.getRangeAt(0);
|
|
4469
4543
|
if (!this.editable.contains(range.startContainer)) return null;
|
|
@@ -4529,7 +4603,7 @@ var History = class {
|
|
|
4529
4603
|
const range = document.createRange();
|
|
4530
4604
|
range.setStart(startNode, startOff);
|
|
4531
4605
|
range.setEnd(endNode, endOff);
|
|
4532
|
-
const sel =
|
|
4606
|
+
const sel = globalThis.getSelection();
|
|
4533
4607
|
sel.removeAllRanges();
|
|
4534
4608
|
sel.addRange(range);
|
|
4535
4609
|
} catch (_) {
|
|
@@ -4537,7 +4611,7 @@ var History = class {
|
|
|
4537
4611
|
const fb = document.createRange();
|
|
4538
4612
|
fb.setStart(this.editable, 0);
|
|
4539
4613
|
fb.collapse(true);
|
|
4540
|
-
const s =
|
|
4614
|
+
const s = globalThis.getSelection();
|
|
4541
4615
|
if (s) {
|
|
4542
4616
|
s.removeAllRanges();
|
|
4543
4617
|
s.addRange(fb);
|
|
@@ -4601,8 +4675,7 @@ var History = class {
|
|
|
4601
4675
|
recordUndo() {
|
|
4602
4676
|
const current = this._serialize();
|
|
4603
4677
|
const { html: tokenized } = this._tokenizeImages(current);
|
|
4604
|
-
|
|
4605
|
-
if (prev && prev.html === tokenized) return;
|
|
4678
|
+
if (this.stack[this.stackOffset]?.html === tokenized) return;
|
|
4606
4679
|
this._savePoint();
|
|
4607
4680
|
}
|
|
4608
4681
|
/**
|
|
@@ -4648,8 +4721,7 @@ var History = class {
|
|
|
4648
4721
|
* Build an HTML table with the given number of columns and rows, optionally including a header row.
|
|
4649
4722
|
* @param {number} cols - Number of columns in each row.
|
|
4650
4723
|
* @param {number} rows - Total number of rows to create (including header when `headerRow` is true).
|
|
4651
|
-
* @param {{ headerRow?: boolean }} [opts] - Options
|
|
4652
|
-
* @param {boolean} [opts.headerRow=false] - When true and `rows > 0`, creates a header row (`<thead>`) plus body rows for the remainder.
|
|
4724
|
+
* @param {{ headerRow?: boolean }} [opts] - Options: `headerRow` creates a `<thead>` when true.
|
|
4653
4725
|
* @returns {HTMLTableElement} The constructed `<table>` element with a `<tbody>` and optional `<thead>`; each cell contains a `<br>` placeholder.
|
|
4654
4726
|
*/
|
|
4655
4727
|
function createTable(cols, rows, opts = {}) {
|
|
@@ -4683,12 +4755,11 @@ function createTable(cols, rows, opts = {}) {
|
|
|
4683
4755
|
* @param {number} cols - Number of columns for the new table.
|
|
4684
4756
|
* @param {number} rows - Number of rows for the new table.
|
|
4685
4757
|
* @param {{ headerRow?: boolean }} [opts] - Options for table creation.
|
|
4686
|
-
* @param {boolean} [opts.headerRow=false] - If true, include a header row as the first row.
|
|
4687
4758
|
*/
|
|
4688
4759
|
function insertTable(cols, rows, opts = {}) {
|
|
4689
4760
|
if (cols <= 0 || rows <= 0) return;
|
|
4690
4761
|
const table = createTable(cols, rows, opts);
|
|
4691
|
-
const sel =
|
|
4762
|
+
const sel = globalThis.getSelection();
|
|
4692
4763
|
if (!sel || sel.rangeCount === 0) return;
|
|
4693
4764
|
const range = sel.getRangeAt(0);
|
|
4694
4765
|
range.deleteContents();
|
|
@@ -4706,7 +4777,7 @@ function insertTable(cols, rows, opts = {}) {
|
|
|
4706
4777
|
"PRE"
|
|
4707
4778
|
]);
|
|
4708
4779
|
let anchor = range.startContainer;
|
|
4709
|
-
if (anchor
|
|
4780
|
+
if (anchor?.nodeType === 3) anchor = anchor.parentElement;
|
|
4710
4781
|
while (anchor && !BLOCK.has(anchor.tagName?.toUpperCase()) && anchor.parentElement) anchor = anchor.parentElement;
|
|
4711
4782
|
if (anchor && BLOCK.has(anchor.tagName?.toUpperCase()) && anchor.parentNode) {
|
|
4712
4783
|
anchor.after(table);
|
|
@@ -4796,8 +4867,8 @@ function isModifier(event, keyName) {
|
|
|
4796
4867
|
* Inspired by Summernote's Typing module
|
|
4797
4868
|
*/
|
|
4798
4869
|
var _FA_PATTERN = /\bfa-/;
|
|
4799
|
-
var isFAIcon = (n) => !!(n
|
|
4800
|
-
var isZwsAnchor = (n) => !!(n
|
|
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 === ""));
|
|
4801
4872
|
/**
|
|
4802
4873
|
* Handles special keydown behaviour inside the editor.
|
|
4803
4874
|
* @param {KeyboardEvent} event
|
|
@@ -4807,7 +4878,7 @@ var isZwsAnchor = (n) => !!(n && n.nodeType === Node.TEXT_NODE && (n.textContent
|
|
|
4807
4878
|
*/
|
|
4808
4879
|
function handleKeydown(event, editable, options = {}) {
|
|
4809
4880
|
const moveCaret = (setFn) => {
|
|
4810
|
-
const sel =
|
|
4881
|
+
const sel = globalThis.getSelection();
|
|
4811
4882
|
if (!sel) return false;
|
|
4812
4883
|
const nr = document.createRange();
|
|
4813
4884
|
setFn(nr);
|
|
@@ -4817,14 +4888,14 @@ function handleKeydown(event, editable, options = {}) {
|
|
|
4817
4888
|
return true;
|
|
4818
4889
|
};
|
|
4819
4890
|
if (isKey(event, key.BACKSPACE)) {
|
|
4820
|
-
const sel =
|
|
4821
|
-
if (sel
|
|
4891
|
+
const sel = globalThis.getSelection();
|
|
4892
|
+
if (sel?.rangeCount > 0) {
|
|
4822
4893
|
const r = sel.getRangeAt(0);
|
|
4823
4894
|
if (r.collapsed && r.startContainer.nodeType === Node.TEXT_NODE) {
|
|
4824
4895
|
const textNode = r.startContainer;
|
|
4825
4896
|
if (r.startOffset === 0 && isFAIcon(textNode.previousSibling)) {
|
|
4826
4897
|
event.preventDefault();
|
|
4827
|
-
textNode.previousSibling.remove();
|
|
4898
|
+
/** @type {ChildNode} */ textNode.previousSibling.remove();
|
|
4828
4899
|
return true;
|
|
4829
4900
|
}
|
|
4830
4901
|
if (r.startOffset === 1 && textNode.textContent === "" && isFAIcon(textNode.previousSibling)) {
|
|
@@ -4848,7 +4919,7 @@ function handleKeydown(event, editable, options = {}) {
|
|
|
4848
4919
|
return false;
|
|
4849
4920
|
}
|
|
4850
4921
|
if (isKey(event, key.LEFT) || isKey(event, key.RIGHT)) {
|
|
4851
|
-
const sel =
|
|
4922
|
+
const sel = globalThis.getSelection();
|
|
4852
4923
|
if (!sel || sel.rangeCount === 0) return false;
|
|
4853
4924
|
const r = sel.getRangeAt(0);
|
|
4854
4925
|
if (!r.collapsed) return false;
|
|
@@ -4936,7 +5007,7 @@ function handleKeydown(event, editable, options = {}) {
|
|
|
4936
5007
|
else execCommand("indent");
|
|
4937
5008
|
return true;
|
|
4938
5009
|
}
|
|
4939
|
-
if (para
|
|
5010
|
+
if (para?.nodeName.toUpperCase() === "PRE") {
|
|
4940
5011
|
if (event.shiftKey) return false;
|
|
4941
5012
|
event.preventDefault();
|
|
4942
5013
|
execCommand("insertText", " ".repeat(options.tabSize || 4));
|
|
@@ -4959,18 +5030,18 @@ function handleKeydown(event, editable, options = {}) {
|
|
|
4959
5030
|
if (!range) return false;
|
|
4960
5031
|
const sc = range.sc;
|
|
4961
5032
|
const el = sc.nodeType === 3 ? sc.parentElement : sc;
|
|
4962
|
-
if (el
|
|
5033
|
+
if (el?.nodeName === "I" && /\bfa-/.test(el.className || "")) {
|
|
4963
5034
|
const nr = document.createRange();
|
|
4964
5035
|
nr.setStartAfter(el);
|
|
4965
5036
|
nr.collapse(true);
|
|
4966
|
-
const selI =
|
|
5037
|
+
const selI = globalThis.getSelection();
|
|
4967
5038
|
if (selI) {
|
|
4968
5039
|
selI.removeAllRanges();
|
|
4969
5040
|
selI.addRange(nr);
|
|
4970
5041
|
}
|
|
4971
5042
|
return false;
|
|
4972
5043
|
}
|
|
4973
|
-
const videoWrapper = el
|
|
5044
|
+
const videoWrapper = el?.closest(".an-video-wrapper");
|
|
4974
5045
|
if (videoWrapper) {
|
|
4975
5046
|
event.preventDefault();
|
|
4976
5047
|
const p = document.createElement("p");
|
|
@@ -4979,16 +5050,16 @@ function handleKeydown(event, editable, options = {}) {
|
|
|
4979
5050
|
const nr = document.createRange();
|
|
4980
5051
|
nr.setStart(p, 0);
|
|
4981
5052
|
nr.collapse(true);
|
|
4982
|
-
const sel =
|
|
5053
|
+
const sel = globalThis.getSelection();
|
|
4983
5054
|
sel.removeAllRanges();
|
|
4984
5055
|
sel.addRange(nr);
|
|
4985
5056
|
return true;
|
|
4986
5057
|
}
|
|
4987
|
-
const checkLi = el
|
|
5058
|
+
const checkLi = el?.closest(".an-checklist li");
|
|
4988
5059
|
if (checkLi) {
|
|
4989
5060
|
event.preventDefault();
|
|
4990
5061
|
const ul = checkLi.closest(".an-checklist");
|
|
4991
|
-
const sel =
|
|
5062
|
+
const sel = globalThis.getSelection();
|
|
4992
5063
|
let nativeRange = sel.getRangeAt(0);
|
|
4993
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();
|
|
4994
5065
|
if (!liText(checkLi)) {
|
|
@@ -5032,12 +5103,12 @@ function handleKeydown(event, editable, options = {}) {
|
|
|
5032
5103
|
return true;
|
|
5033
5104
|
}
|
|
5034
5105
|
const para = closestPara(range.sc, editable);
|
|
5035
|
-
if (para
|
|
5106
|
+
if (para?.nodeName.toUpperCase() === "PRE") {
|
|
5036
5107
|
event.preventDefault();
|
|
5037
5108
|
execCommand("insertText", "\n");
|
|
5038
5109
|
return true;
|
|
5039
5110
|
}
|
|
5040
|
-
if (para
|
|
5111
|
+
if (para?.nodeName.toUpperCase() === "BLOCKQUOTE") {
|
|
5041
5112
|
const native = range.toNativeRange();
|
|
5042
5113
|
native.setEnd(para, para.childNodes.length);
|
|
5043
5114
|
if (native.toString() === "" && range.isCollapsed()) {
|
|
@@ -5084,8 +5155,9 @@ function htmlToMarkdown(html) {
|
|
|
5084
5155
|
function _domToMd(node, depth = 0) {
|
|
5085
5156
|
if (node.nodeType === 3) return node.textContent.replace(/\s+/g, " ");
|
|
5086
5157
|
if (node.nodeType !== 1) return "";
|
|
5087
|
-
const
|
|
5088
|
-
const
|
|
5158
|
+
const el = node;
|
|
5159
|
+
const tag = el.nodeName.toLowerCase();
|
|
5160
|
+
const inner = () => Array.from(el.childNodes).map((n) => _domToMd(n, depth)).join("");
|
|
5089
5161
|
switch (tag) {
|
|
5090
5162
|
case "p":
|
|
5091
5163
|
case "div": return `\n\n${inner()}\n\n`;
|
|
@@ -5103,34 +5175,34 @@ function _domToMd(node, depth = 0) {
|
|
|
5103
5175
|
case "del":
|
|
5104
5176
|
case "s":
|
|
5105
5177
|
case "strike": return `~~${inner()}~~`;
|
|
5106
|
-
case "sup": return `^${inner()}
|
|
5107
|
-
case "sub": return `~${inner()}
|
|
5178
|
+
case "sup": return `^${inner()}^`;
|
|
5179
|
+
case "sub": return `~${inner()}~`;
|
|
5108
5180
|
case "code":
|
|
5109
|
-
if (
|
|
5181
|
+
if (el.closest("pre")) return inner();
|
|
5110
5182
|
return `\`${inner()}\``;
|
|
5111
5183
|
case "pre": {
|
|
5112
|
-
const codeEl =
|
|
5113
|
-
const langMatch = (codeEl && codeEl.className || "")
|
|
5114
|
-
return `\n\n\`\`\`${langMatch ? langMatch[1] : ""}\n${(codeEl ||
|
|
5184
|
+
const codeEl = el.querySelector("code");
|
|
5185
|
+
const langMatch = /language-(\S+)/.exec(codeEl && codeEl.className || "");
|
|
5186
|
+
return `\n\n\`\`\`${langMatch ? langMatch[1] : ""}\n${(codeEl || el).textContent || ""}\n\`\`\`\n\n`;
|
|
5115
5187
|
}
|
|
5116
5188
|
case "blockquote": return `\n\n${inner().trim().split("\n").map((l) => `> ${l}`).join("\n")}\n\n`;
|
|
5117
5189
|
case "a": {
|
|
5118
|
-
const href =
|
|
5190
|
+
const href = el.getAttribute("href") || "";
|
|
5119
5191
|
return `[${inner()}](${href})`;
|
|
5120
5192
|
}
|
|
5121
5193
|
case "img": {
|
|
5122
|
-
const src =
|
|
5123
|
-
return ``;
|
|
5124
5196
|
}
|
|
5125
5197
|
case "ul": {
|
|
5126
|
-
const items = Array.from(
|
|
5198
|
+
const items = Array.from(el.querySelectorAll(":scope > li"));
|
|
5127
5199
|
if (!items.length) return inner();
|
|
5128
5200
|
const indent = " ".repeat(depth);
|
|
5129
5201
|
const lines = items.map((li) => `${indent}- ${_domToMd(li, depth + 1).trim()}`).join("\n");
|
|
5130
5202
|
return depth === 0 ? `\n\n${lines}\n\n` : `\n${lines}`;
|
|
5131
5203
|
}
|
|
5132
5204
|
case "ol": {
|
|
5133
|
-
const items = Array.from(
|
|
5205
|
+
const items = Array.from(el.querySelectorAll(":scope > li"));
|
|
5134
5206
|
if (!items.length) return inner();
|
|
5135
5207
|
const indent = " ".repeat(depth);
|
|
5136
5208
|
const lines = items.map((li, i) => `${indent}${i + 1}. ${_domToMd(li, depth + 1).trim()}`).join("\n");
|
|
@@ -5139,9 +5211,9 @@ function _domToMd(node, depth = 0) {
|
|
|
5139
5211
|
case "li": return inner();
|
|
5140
5212
|
case "hr": return "\n\n---\n\n";
|
|
5141
5213
|
case "table": {
|
|
5142
|
-
const rows = Array.from(
|
|
5214
|
+
const rows = Array.from(el.querySelectorAll("tr"));
|
|
5143
5215
|
if (!rows.length) return inner();
|
|
5144
|
-
const cellTexts = rows.map((tr) => Array.from(tr.querySelectorAll("th, td")).map((c) => c.textContent.trim().
|
|
5216
|
+
const cellTexts = rows.map((tr) => Array.from(tr.querySelectorAll("th, td")).map((c) => c.textContent.trim().replaceAll("|", "\\|")));
|
|
5145
5217
|
const cols = Math.max(...cellTexts.map((r) => r.length));
|
|
5146
5218
|
const padRow = (row) => {
|
|
5147
5219
|
const r = [...row];
|
|
@@ -5150,7 +5222,7 @@ function _domToMd(node, depth = 0) {
|
|
|
5150
5222
|
};
|
|
5151
5223
|
let md = "\n\n";
|
|
5152
5224
|
md += `| ${padRow(cellTexts[0]).join(" | ")} |\n`;
|
|
5153
|
-
md += `| ${Array(cols).fill("---").join(" | ")} |\n`;
|
|
5225
|
+
md += `| ${new Array(cols).fill("---").join(" | ")} |\n`;
|
|
5154
5226
|
for (let r = 1; r < cellTexts.length; r++) md += `| ${padRow(cellTexts[r]).join(" | ")} |\n`;
|
|
5155
5227
|
return md + "\n";
|
|
5156
5228
|
}
|
|
@@ -5174,12 +5246,12 @@ function isMarkdown(text) {
|
|
|
5174
5246
|
* @returns {string}
|
|
5175
5247
|
*/
|
|
5176
5248
|
function markdownToHTML(text) {
|
|
5177
|
-
const lines = text.
|
|
5249
|
+
const lines = text.replaceAll("\r\n", "\n").replaceAll("\r", "\n").split("\n");
|
|
5178
5250
|
const out = [];
|
|
5179
5251
|
let i = 0;
|
|
5180
5252
|
while (i < lines.length) {
|
|
5181
5253
|
const line = lines[i];
|
|
5182
|
-
const fenceMatch =
|
|
5254
|
+
const fenceMatch = /^```(\S*)$/.exec(line);
|
|
5183
5255
|
if (fenceMatch) {
|
|
5184
5256
|
const lang = fenceMatch[1];
|
|
5185
5257
|
const codeLines = [];
|
|
@@ -5198,7 +5270,7 @@ function markdownToHTML(text) {
|
|
|
5198
5270
|
i++;
|
|
5199
5271
|
continue;
|
|
5200
5272
|
}
|
|
5201
|
-
const hMatch =
|
|
5273
|
+
const hMatch = /^(#{1,6})\s+(.+)$/.exec(line);
|
|
5202
5274
|
if (hMatch) {
|
|
5203
5275
|
const level = hMatch[1].length;
|
|
5204
5276
|
out.push(`<h${level}>${_inline(hMatch[2])}</h${level}>`);
|
|
@@ -5245,7 +5317,8 @@ function markdownToHTML(text) {
|
|
|
5245
5317
|
i++;
|
|
5246
5318
|
}
|
|
5247
5319
|
const thead = `<thead><tr>${headerCells.map((c) => `<th>${_inline(c)}</th>`).join("")}</tr></thead>`;
|
|
5248
|
-
const
|
|
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>` : "";
|
|
5249
5322
|
out.push(`<table>${thead}${tbody}</table>`);
|
|
5250
5323
|
continue;
|
|
5251
5324
|
}
|
|
@@ -5281,10 +5354,51 @@ function _inline(text) {
|
|
|
5281
5354
|
return text;
|
|
5282
5355
|
}
|
|
5283
5356
|
function _esc(v) {
|
|
5284
|
-
return String(v).
|
|
5357
|
+
return String(v).replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
5285
5358
|
}
|
|
5286
5359
|
function _escAttr(v) {
|
|
5287
|
-
return String(v).
|
|
5360
|
+
return String(v).replaceAll("&", "&").replaceAll("\"", """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
5361
|
+
}
|
|
5362
|
+
//#endregion
|
|
5363
|
+
//#region src/js/core/detectLang.js
|
|
5364
|
+
/**
|
|
5365
|
+
* detectLang.js — Heuristic programming-language detection for code snippets.
|
|
5366
|
+
*
|
|
5367
|
+
* Returns a Prism.js language identifier or null when no language can be
|
|
5368
|
+
* determined with reasonable confidence.
|
|
5369
|
+
*
|
|
5370
|
+
* Detection order (conflicts in parentheses):
|
|
5371
|
+
* TypeScript → Rust → PHP → Java → Kotlin → Swift → Go
|
|
5372
|
+
* → JavaScript → HTML → CSS → JSON → SQL → Python → Ruby
|
|
5373
|
+
* → Bash → C++ → C# → C → XML
|
|
5374
|
+
*
|
|
5375
|
+
* @param {string} code
|
|
5376
|
+
* @returns {string|null}
|
|
5377
|
+
*/
|
|
5378
|
+
function detectLang(code) {
|
|
5379
|
+
if (!code || !code.trim()) return null;
|
|
5380
|
+
const s = code.trim();
|
|
5381
|
+
if (/(:\s*(string|number|boolean|void|never|any|unknown)\b|interface\s+\w+\s*\{|type\s+\w+\s*[=<(]|<\w+>\s*[;,)]|readonly\s+\w|enum\s+\w+\s*\{|\?\s*:\s*\w|as\s+\w+\s*[;,)\]])/.test(s)) return "typescript";
|
|
5382
|
+
if (/\bprintln!\s*\(|\bprint!\s*\(|\bfn\s+\w+\s*(<[^>]*>)?\s*\(|\blet\s+mut\s|\bpub\s+fn\s|\buse\s+std::|\bimpl\s+\w+|\bOption<|\bResult<\w+/.test(s)) return "rust";
|
|
5383
|
+
if (/(<\?php\b|<\?=|\becho\s+.*\$\w|\$this->|\$\w+\s*=\s*\w|\bforeach\s*\(\s*\$|Illuminate\\)/.test(s)) return "php";
|
|
5384
|
+
if (/\bpublic\s+(class|static|void|int|String)\s+\w|System\.out\.(print|println)\s*\(|@(Override|Autowired|Component|Service|Controller)\b|import\s+java\.(util|io|lang|net)\.|throws\s+\w+Exception/.test(s)) return "java";
|
|
5385
|
+
if (/\bfun\s+\w+\s*\(|\bdata\s+class\s+\w+|\bcompanion\s+object\b|\bval\s+\w+\s*:\s*\w|\bprintln\s*\(/.test(s)) return "kotlin";
|
|
5386
|
+
if (/\bguard\s+(let|var)\b|\bprotocol\s+\w+\s*\{|\bextension\s+\w+|\bfunc\s+\w+[^(]*\([^)]*\)\s*->\s*\w|\blet\s+\w+\s*:\s*[A-Z]\w*|\bSwiftUI\b/.test(s)) return "swift";
|
|
5387
|
+
if (/\bpackage\s+\w+\b|\bfmt\.(Print|Println|Sprintf|Errorf|Fprintf)\s*\(|:=\s*\w|\bgoroutine\b|\bchan\s+\w|\bgo\s+func\b/.test(s)) return "go";
|
|
5388
|
+
if (/\b(const\s+\w|let\s+\w+\s*=|var\s+\w+\s*=|function\s+\w|\=>\s*[{(]|import\s+.*\bfrom\b\s*['"]|require\s*\(|console\.(log|error|warn|info)|document\.\w|window\.\w|async\s+function|\bPromise\b|React\.|useState\s*\(|\.then\s*\()/.test(s)) return "javascript";
|
|
5389
|
+
if (/^<!DOCTYPE html/i.test(s) || /<(html|head|body|div|section|article|nav|p|a|img|ul|ol|li|table|form|input|button|script|style)\b[^>]*>/i.test(s)) return "html";
|
|
5390
|
+
if (/(^|\n)\s*(\/\/\s+\S|&[:.[\w]|\$\w+\s*:|@(mixin|include|extend|each|if|for|use|forward)\b|#\{)/.test(s) && /[\w#.*&[\]:(),>+~ -]+\s*\{/.test(s)) return "scss";
|
|
5391
|
+
if (/(^|\n)\s*[\w#.*:[\]&, +-]+\s*\{[^}]*[\w-]+\s*:[^{}:;]+[;}\n]/m.test(s) && !/<\w|function\s|def\s|:\s*(string|number)/.test(s)) return "css";
|
|
5392
|
+
if (/^\s*[{[]/.test(s) && /"\w[\w\s-]*"\s*:/.test(s) && !/\bfunction\b|\bdef\b/.test(s)) return "json";
|
|
5393
|
+
if (/(^|\n)\s*(SELECT\s|INSERT\s+INTO|UPDATE\s+\w|DELETE\s+FROM|CREATE\s+(TABLE|DATABASE|INDEX|VIEW)|DROP\s+(TABLE|DATABASE)|ALTER\s+TABLE|WITH\s+\w+\s+AS\s*\()/im.test(s)) return "sql";
|
|
5394
|
+
if (/\bdef\s+\w+\s*\([^)]*\)\s*:|(^|\n)\s*class\s+\w+.*:\s*$|(^|\n)\s*import\s+\w|(^|\n)\s*from\s+\w+\s+import\s+|\bprint\s*\(|if\s+__name__\s*==\s*['"]__main__['"]/m.test(s)) return "python";
|
|
5395
|
+
if (/\bputs\s+\S|\battr_(accessor|reader|writer)\s|\.each\s+do\s*\|\w+\s*\||\bdo\s*\|\w+\s*\|.*\bend\b|\bdef\s+\w+[^:]*\n[\s\S]*?\bend\b/.test(s)) return "ruby";
|
|
5396
|
+
if (/^#!.*\/(ba|z|da|fi|k)?sh\b/m.test(s) || /\b(echo\s+["']|grep\s+|awk\s+|sed\s+['"\\/-]|chmod\s+|sudo\s+|apt(-get)?\s+install|brew\s+install|npm\s+(install|run|start|build)|pip\s+(install|3\s)|docker\s+(run|build|compose)|kubectl\s+|git\s+(clone|add|commit|push|pull|checkout))\b/.test(s)) return "bash";
|
|
5397
|
+
if (/\bcout\s*<<|\bcin\s*>>|using\s+namespace\s+std\b|std::\w|\btemplate\s*<\w|\b#include\s*<(iostream|vector|map|set|algorithm|string|memory)>/.test(s)) return "cpp";
|
|
5398
|
+
if (/\busing\s+System\b|Console\.(Write|WriteLine)\s*\(|\bget;\s*set;|\basync\s+Task[<\s]|IEnumerable<|\bLINQ\b|\.Select\s*\(|\.Where\s*\(/.test(s)) return "csharp";
|
|
5399
|
+
if (/\b#include\s*<(stdio|stdlib|string|math|time|ctype)\.h>|\bprintf\s*\(|\bscanf\s*\(|int\s+main\s*\(\s*(void|int\s+argc)|\bmalloc\s*\(|\bfree\s*\(/.test(s) && !/namespace|cout|cin|std::/.test(s)) return "c";
|
|
5400
|
+
if (/^<\?xml\s/i.test(s) || /xmlns:|<\/[\w:]+>/.test(s)) return "xml";
|
|
5401
|
+
return null;
|
|
5288
5402
|
}
|
|
5289
5403
|
//#endregion
|
|
5290
5404
|
//#region src/js/module/Editor.js
|
|
@@ -5325,7 +5439,7 @@ var Editor = class {
|
|
|
5325
5439
|
const onBeforeInput = (event) => this._enforceLimit(event);
|
|
5326
5440
|
const onSelChange = () => {
|
|
5327
5441
|
if (!this.context._alive) return;
|
|
5328
|
-
const sel =
|
|
5442
|
+
const sel = globalThis.getSelection();
|
|
5329
5443
|
if (sel && sel.rangeCount > 0 && editable.contains(sel.anchorNode)) {
|
|
5330
5444
|
this.context.invoke("toolbar.refresh");
|
|
5331
5445
|
if (typeof this.options.onSelectionChange === "function") this.options.onSelectionChange(this.context);
|
|
@@ -5335,13 +5449,14 @@ var Editor = class {
|
|
|
5335
5449
|
if (e.target.type === "checkbox" && e.target.closest(".an-checklist")) this.afterCommand();
|
|
5336
5450
|
};
|
|
5337
5451
|
const fixChecklistCursor = (event) => {
|
|
5338
|
-
const sel =
|
|
5452
|
+
const sel = globalThis.getSelection();
|
|
5339
5453
|
if (!sel || !sel.rangeCount) return;
|
|
5340
5454
|
const r = sel.getRangeAt(0);
|
|
5341
5455
|
if (!r.collapsed) return;
|
|
5342
5456
|
const sc = r.startContainer;
|
|
5343
5457
|
if (sc.nodeType !== Node.ELEMENT_NODE) return;
|
|
5344
|
-
const
|
|
5458
|
+
const scEl = sc;
|
|
5459
|
+
const li = scEl.matches(".an-checklist li") ? scEl : null;
|
|
5345
5460
|
if (!li) return;
|
|
5346
5461
|
const cb = li.querySelector("input[type=\"checkbox\"]");
|
|
5347
5462
|
if (!cb) return;
|
|
@@ -5381,33 +5496,37 @@ var Editor = class {
|
|
|
5381
5496
|
return;
|
|
5382
5497
|
}
|
|
5383
5498
|
const target = e.target;
|
|
5384
|
-
if (target && (target.nodeName === "IFRAME" || target.closest
|
|
5499
|
+
if (target && (target.nodeName === "IFRAME" || target.closest(".an-video-wrapper"))) e.preventDefault();
|
|
5385
5500
|
}), on(editable, "drop", (e) => {
|
|
5386
5501
|
if (isReadOnly()) e.preventDefault();
|
|
5387
5502
|
}));
|
|
5388
5503
|
/** @type {string|null} 'superscript' | 'subscript' | null */
|
|
5389
5504
|
let _compositionSupSub = null;
|
|
5390
5505
|
const onCompositionStart = () => {
|
|
5391
|
-
const sel =
|
|
5506
|
+
const sel = globalThis.getSelection();
|
|
5392
5507
|
if (!sel || !sel.rangeCount) {
|
|
5393
5508
|
_compositionSupSub = null;
|
|
5394
5509
|
return;
|
|
5395
5510
|
}
|
|
5396
5511
|
let node = sel.getRangeAt(0).startContainer;
|
|
5397
5512
|
if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
|
|
5398
|
-
if (node
|
|
5399
|
-
|
|
5400
|
-
|
|
5513
|
+
if (node) {
|
|
5514
|
+
const el = node;
|
|
5515
|
+
if (el.closest("sup")) _compositionSupSub = "superscript";
|
|
5516
|
+
else if (el.closest("sub")) _compositionSupSub = "subscript";
|
|
5517
|
+
else _compositionSupSub = null;
|
|
5518
|
+
}
|
|
5401
5519
|
};
|
|
5402
5520
|
const onCompositionEnd = () => {
|
|
5403
5521
|
const tag = _compositionSupSub;
|
|
5404
5522
|
_compositionSupSub = null;
|
|
5405
5523
|
if (!tag) return;
|
|
5406
|
-
const sel =
|
|
5524
|
+
const sel = globalThis.getSelection();
|
|
5407
5525
|
if (!sel || !sel.rangeCount) return;
|
|
5408
5526
|
let node = sel.getRangeAt(0).startContainer;
|
|
5409
5527
|
if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
|
|
5410
|
-
|
|
5528
|
+
const el = node;
|
|
5529
|
+
if (!(tag === "superscript" ? el?.closest("sup") : el?.closest("sub"))) document.execCommand(tag);
|
|
5411
5530
|
};
|
|
5412
5531
|
this._disposers.push(on(editable, "compositionstart", onCompositionStart), on(editable, "compositionend", onCompositionEnd));
|
|
5413
5532
|
}
|
|
@@ -5481,7 +5600,7 @@ var Editor = class {
|
|
|
5481
5600
|
if (type === "insertFromPaste" || type === "insertFromDrop") return;
|
|
5482
5601
|
if (!type.startsWith("insert")) return;
|
|
5483
5602
|
const text = this.context.layoutInfo.editable.innerText || "";
|
|
5484
|
-
const chars = text.
|
|
5603
|
+
const chars = text.replaceAll("\n", "").length;
|
|
5485
5604
|
if (maxChars && chars >= maxChars) {
|
|
5486
5605
|
event.preventDefault();
|
|
5487
5606
|
if (typeof this.options.onCharLimitReached === "function") this.options.onCharLimitReached(this.context);
|
|
@@ -5496,6 +5615,7 @@ var Editor = class {
|
|
|
5496
5615
|
}
|
|
5497
5616
|
afterCommand() {
|
|
5498
5617
|
this._cleanOrphanedFigures();
|
|
5618
|
+
this._ensureTrailingParagraph();
|
|
5499
5619
|
this.context.invoke("toolbar.refresh");
|
|
5500
5620
|
this.context.invoke("statusbar.update");
|
|
5501
5621
|
this._scheduleSnapshot();
|
|
@@ -5519,9 +5639,34 @@ var Editor = class {
|
|
|
5519
5639
|
*/
|
|
5520
5640
|
_cleanOrphanedFigures() {
|
|
5521
5641
|
this.context.layoutInfo.editable.querySelectorAll("figure.an-figure").forEach((fig) => {
|
|
5522
|
-
if (!fig.querySelector("img")) fig.
|
|
5642
|
+
if (!fig.querySelector("img")) fig.remove();
|
|
5523
5643
|
});
|
|
5524
5644
|
}
|
|
5645
|
+
/**
|
|
5646
|
+
* Ensures the editable always ends with a plain paragraph so the cursor can
|
|
5647
|
+
* be placed after block elements that do not naturally allow it
|
|
5648
|
+
* (pre, blockquote, table, figure, ul, ol, hr).
|
|
5649
|
+
* Without this, clicking below the last such element does nothing.
|
|
5650
|
+
*/
|
|
5651
|
+
_ensureTrailingParagraph() {
|
|
5652
|
+
const editable = this.context.layoutInfo.editable;
|
|
5653
|
+
if (!editable) return;
|
|
5654
|
+
const last = editable.lastElementChild;
|
|
5655
|
+
if (!last) return;
|
|
5656
|
+
if (new Set([
|
|
5657
|
+
"PRE",
|
|
5658
|
+
"BLOCKQUOTE",
|
|
5659
|
+
"TABLE",
|
|
5660
|
+
"FIGURE",
|
|
5661
|
+
"UL",
|
|
5662
|
+
"OL",
|
|
5663
|
+
"HR"
|
|
5664
|
+
]).has(last.nodeName)) {
|
|
5665
|
+
const p = document.createElement("p");
|
|
5666
|
+
p.innerHTML = "<br>";
|
|
5667
|
+
editable.appendChild(p);
|
|
5668
|
+
}
|
|
5669
|
+
}
|
|
5525
5670
|
focus() {
|
|
5526
5671
|
this.context.layoutInfo.editable.focus();
|
|
5527
5672
|
}
|
|
@@ -5530,7 +5675,7 @@ var Editor = class {
|
|
|
5530
5675
|
* @returns {string}
|
|
5531
5676
|
*/
|
|
5532
5677
|
getHTML() {
|
|
5533
|
-
const raw = this.context.layoutInfo.editable.innerHTML.
|
|
5678
|
+
const raw = this.context.layoutInfo.editable.innerHTML.replaceAll("", "");
|
|
5534
5679
|
return this.context.invoke("clipboard.resolveImages", raw) ?? raw;
|
|
5535
5680
|
}
|
|
5536
5681
|
/**
|
|
@@ -5575,7 +5720,7 @@ var Editor = class {
|
|
|
5575
5720
|
* @returns {boolean}
|
|
5576
5721
|
*/
|
|
5577
5722
|
isEmpty() {
|
|
5578
|
-
const text = (this.context.layoutInfo.editable.innerText || "").trim().
|
|
5723
|
+
const text = (this.context.layoutInfo.editable.innerText || "").trim().replaceAll("\xA0", "");
|
|
5579
5724
|
const hasMedia = !!this.context.layoutInfo.editable.querySelector("img, video, iframe, table");
|
|
5580
5725
|
return !text && !hasMedia;
|
|
5581
5726
|
}
|
|
@@ -5705,10 +5850,24 @@ var Editor = class {
|
|
|
5705
5850
|
this.context.print();
|
|
5706
5851
|
}
|
|
5707
5852
|
/**
|
|
5708
|
-
* @param {string} tagName - e.g. 'h1', 'p', 'blockquote'
|
|
5853
|
+
* @param {string} tagName - e.g. 'h1', 'p', 'blockquote', 'pre'
|
|
5709
5854
|
*/
|
|
5710
5855
|
formatBlock(tagName) {
|
|
5711
5856
|
formatBlock(tagName);
|
|
5857
|
+
if (tagName === "pre") {
|
|
5858
|
+
const sel = globalThis.getSelection();
|
|
5859
|
+
if (sel && sel.rangeCount > 0) {
|
|
5860
|
+
const container = sel.getRangeAt(0).commonAncestorContainer;
|
|
5861
|
+
const pre = container.nodeType === 1 ? container.closest("pre") : container.parentElement?.closest("pre");
|
|
5862
|
+
if (pre && !pre.dataset.language) {
|
|
5863
|
+
const lang = detectLang(pre.textContent || "");
|
|
5864
|
+
if (lang) {
|
|
5865
|
+
this.context.invoke("codeTooltip.applyLanguage", pre, lang);
|
|
5866
|
+
return;
|
|
5867
|
+
}
|
|
5868
|
+
}
|
|
5869
|
+
}
|
|
5870
|
+
}
|
|
5712
5871
|
this.afterCommand();
|
|
5713
5872
|
}
|
|
5714
5873
|
/**
|
|
@@ -5753,7 +5912,7 @@ var Editor = class {
|
|
|
5753
5912
|
* @param {boolean} [openInNewTab=false]
|
|
5754
5913
|
*/
|
|
5755
5914
|
insertLink(url, text, openInNewTab = false) {
|
|
5756
|
-
const sel =
|
|
5915
|
+
const sel = globalThis.getSelection();
|
|
5757
5916
|
if (!sel || sel.rangeCount === 0) return;
|
|
5758
5917
|
const safeUrl = sanitiseUrl(url);
|
|
5759
5918
|
if (!safeUrl) return;
|
|
@@ -5765,8 +5924,8 @@ var Editor = class {
|
|
|
5765
5924
|
if (openInNewTab) {
|
|
5766
5925
|
const link = this._getClosestAnchor();
|
|
5767
5926
|
if (link) {
|
|
5768
|
-
link.setAttribute("target", "_blank");
|
|
5769
|
-
link.setAttribute("rel", "noopener noreferrer");
|
|
5927
|
+
/** @type {Element} */ link.setAttribute("target", "_blank");
|
|
5928
|
+
/** @type {Element} */ link.setAttribute("rel", "noopener noreferrer");
|
|
5770
5929
|
}
|
|
5771
5930
|
}
|
|
5772
5931
|
}
|
|
@@ -5816,7 +5975,7 @@ var Editor = class {
|
|
|
5816
5975
|
this.afterCommand();
|
|
5817
5976
|
}
|
|
5818
5977
|
_getClosestAnchor() {
|
|
5819
|
-
const sel =
|
|
5978
|
+
const sel = globalThis.getSelection();
|
|
5820
5979
|
if (!sel || sel.rangeCount === 0) return null;
|
|
5821
5980
|
let node = sel.getRangeAt(0).startContainer;
|
|
5822
5981
|
while (node) {
|
|
@@ -5831,7 +5990,7 @@ var Editor = class {
|
|
|
5831
5990
|
* @returns {string}
|
|
5832
5991
|
*/
|
|
5833
5992
|
_escapeAttr(str) {
|
|
5834
|
-
return String(str ?? "").
|
|
5993
|
+
return String(str ?? "").replaceAll("&", "&").replaceAll("\"", """).replaceAll("<", "<").replaceAll(">", ">");
|
|
5835
5994
|
}
|
|
5836
5995
|
};
|
|
5837
5996
|
//#endregion
|
|
@@ -5946,7 +6105,7 @@ var Toolbar = class {
|
|
|
5946
6105
|
this._refreshRaf = null;
|
|
5947
6106
|
this._disposers.forEach((d) => d());
|
|
5948
6107
|
this._disposers = [];
|
|
5949
|
-
if (this.el && this.el.parentNode) this.el.
|
|
6108
|
+
if (this.el && this.el.parentNode) this.el.remove();
|
|
5950
6109
|
this.el = null;
|
|
5951
6110
|
}
|
|
5952
6111
|
_buildButtons() {
|
|
@@ -6014,8 +6173,8 @@ var Toolbar = class {
|
|
|
6014
6173
|
let isOpen = false;
|
|
6015
6174
|
const setHighlight = (rows, cols) => {
|
|
6016
6175
|
cells.forEach((cell) => {
|
|
6017
|
-
const r = +cell.
|
|
6018
|
-
const c = +cell.
|
|
6176
|
+
const r = +cell.dataset.row;
|
|
6177
|
+
const c = +cell.dataset.col;
|
|
6019
6178
|
cell.classList.toggle("active", r <= rows && c <= cols);
|
|
6020
6179
|
});
|
|
6021
6180
|
label.textContent = rows && cols ? `${rows} × ${cols}` : this.context.locale.toolbar.insertTableLabel || "Insert Table";
|
|
@@ -6029,8 +6188,8 @@ var Toolbar = class {
|
|
|
6029
6188
|
const ph = popup.offsetHeight;
|
|
6030
6189
|
let left = rect.left;
|
|
6031
6190
|
let top = rect.bottom + 4;
|
|
6032
|
-
if (left + pw >
|
|
6033
|
-
if (top + ph >
|
|
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;
|
|
6034
6193
|
popup.style.left = `${left}px`;
|
|
6035
6194
|
popup.style.top = `${top}px`;
|
|
6036
6195
|
popup.style.visibility = "";
|
|
@@ -6048,16 +6207,16 @@ var Toolbar = class {
|
|
|
6048
6207
|
else openPopup();
|
|
6049
6208
|
});
|
|
6050
6209
|
const d2 = on(grid, "mouseover", (e) => {
|
|
6051
|
-
const cell = e.target
|
|
6210
|
+
const cell = e.target?.closest(".an-table-cell");
|
|
6052
6211
|
if (!cell) return;
|
|
6053
|
-
setHighlight(+cell.
|
|
6212
|
+
setHighlight(+cell.dataset.row, +cell.dataset.col);
|
|
6054
6213
|
});
|
|
6055
6214
|
const d3 = on(grid, "mouseleave", () => setHighlight(0, 0));
|
|
6056
6215
|
const d4 = on(grid, "click", (e) => {
|
|
6057
|
-
const cell = e.target
|
|
6216
|
+
const cell = e.target?.closest(".an-table-cell");
|
|
6058
6217
|
if (!cell) return;
|
|
6059
|
-
const rows = +cell.
|
|
6060
|
-
const cols = +cell.
|
|
6218
|
+
const rows = +cell.dataset.row;
|
|
6219
|
+
const cols = +cell.dataset.col;
|
|
6061
6220
|
closePopup();
|
|
6062
6221
|
this.context.invoke("editor.focus");
|
|
6063
6222
|
def.action(this.context, rows, cols);
|
|
@@ -6066,7 +6225,7 @@ var Toolbar = class {
|
|
|
6066
6225
|
if (isOpen) closePopup();
|
|
6067
6226
|
});
|
|
6068
6227
|
this._disposers.push(d1, d2, d3, d4, d5, () => {
|
|
6069
|
-
if (popup.parentNode) popup.
|
|
6228
|
+
if (popup.parentNode) popup.remove();
|
|
6070
6229
|
});
|
|
6071
6230
|
wrap.appendChild(btn);
|
|
6072
6231
|
document.body.appendChild(popup);
|
|
@@ -6156,13 +6315,13 @@ var Toolbar = class {
|
|
|
6156
6315
|
/** @type {Range|null} saved selection range before popup opens */
|
|
6157
6316
|
let savedRange = null;
|
|
6158
6317
|
const saveSelection = () => {
|
|
6159
|
-
const sel =
|
|
6318
|
+
const sel = globalThis.getSelection();
|
|
6160
6319
|
savedRange = sel && sel.rangeCount ? sel.getRangeAt(0).cloneRange() : null;
|
|
6161
6320
|
};
|
|
6162
6321
|
const restoreSelection = () => {
|
|
6163
6322
|
if (!savedRange) return;
|
|
6164
6323
|
try {
|
|
6165
|
-
const sel =
|
|
6324
|
+
const sel = globalThis.getSelection();
|
|
6166
6325
|
if (!sel) return;
|
|
6167
6326
|
sel.removeAllRanges();
|
|
6168
6327
|
sel.addRange(savedRange);
|
|
@@ -6177,7 +6336,7 @@ var Toolbar = class {
|
|
|
6177
6336
|
const rect = arrowBtn.getBoundingClientRect();
|
|
6178
6337
|
const popupMinW = 184;
|
|
6179
6338
|
let left = rect.left;
|
|
6180
|
-
if (left + popupMinW >
|
|
6339
|
+
if (left + popupMinW > globalThis.innerWidth) left = rect.right - popupMinW;
|
|
6181
6340
|
popup.style.top = `${rect.bottom + 4}px`;
|
|
6182
6341
|
popup.style.left = `${Math.max(4, left)}px`;
|
|
6183
6342
|
popup.style.display = "block";
|
|
@@ -6217,11 +6376,17 @@ var Toolbar = class {
|
|
|
6217
6376
|
e.preventDefault();
|
|
6218
6377
|
});
|
|
6219
6378
|
const d3b = on(swatches, "click", (e) => {
|
|
6220
|
-
const sw = e.target
|
|
6221
|
-
if (sw) applyColor(
|
|
6379
|
+
const sw = e.target?.closest(".an-color-swatch");
|
|
6380
|
+
if (sw) applyColor(
|
|
6381
|
+
/** @type {HTMLElement} */
|
|
6382
|
+
sw.dataset.color
|
|
6383
|
+
);
|
|
6222
6384
|
});
|
|
6223
6385
|
const d4 = on(colorInput, "change", (e) => {
|
|
6224
|
-
applyColor(
|
|
6386
|
+
applyColor(
|
|
6387
|
+
/** @type {HTMLInputElement} */
|
|
6388
|
+
e.target.value
|
|
6389
|
+
);
|
|
6225
6390
|
});
|
|
6226
6391
|
const d5 = on(document, "click", (e) => {
|
|
6227
6392
|
if (isOpen && !wrap.contains(e.target) && !popup.contains(e.target)) closePopup();
|
|
@@ -6234,9 +6399,9 @@ var Toolbar = class {
|
|
|
6234
6399
|
passive: true,
|
|
6235
6400
|
capture: true
|
|
6236
6401
|
});
|
|
6237
|
-
|
|
6238
|
-
this._disposers.push(d1, d2, d2b, d3, d3b, d4, d5, d6, () => document.removeEventListener("scroll", onScrollResize, { capture: true }), () =>
|
|
6239
|
-
if (popup.parentNode) 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();
|
|
6240
6405
|
});
|
|
6241
6406
|
this._colorPickerClosers.push(closePopup);
|
|
6242
6407
|
this._disposers.push(() => {
|
|
@@ -6280,7 +6445,7 @@ var Toolbar = class {
|
|
|
6280
6445
|
/** @type {Range|null} */
|
|
6281
6446
|
let _savedRange = null;
|
|
6282
6447
|
const dMousedown = on(select, "mousedown", () => {
|
|
6283
|
-
const sel =
|
|
6448
|
+
const sel = globalThis.getSelection();
|
|
6284
6449
|
_savedRange = sel && sel.rangeCount ? sel.getRangeAt(0).cloneRange() : null;
|
|
6285
6450
|
});
|
|
6286
6451
|
const disposer = on(select, "change", (e) => {
|
|
@@ -6289,7 +6454,7 @@ var Toolbar = class {
|
|
|
6289
6454
|
if (!value || selectedOpt.disabled) return;
|
|
6290
6455
|
this.context.invoke("editor.focus");
|
|
6291
6456
|
if (_savedRange) try {
|
|
6292
|
-
const sel =
|
|
6457
|
+
const sel = globalThis.getSelection();
|
|
6293
6458
|
if (sel) {
|
|
6294
6459
|
sel.removeAllRanges();
|
|
6295
6460
|
sel.addRange(_savedRange);
|
|
@@ -6354,17 +6519,25 @@ var Toolbar = class {
|
|
|
6354
6519
|
if (!this.el) return;
|
|
6355
6520
|
const btnMap = this._btnMap || /* @__PURE__ */ new Map();
|
|
6356
6521
|
this.el.querySelectorAll("button[data-btn]").forEach((btn) => {
|
|
6357
|
-
const def = btnMap.get(
|
|
6522
|
+
const def = btnMap.get(
|
|
6523
|
+
/** @type {HTMLElement} */
|
|
6524
|
+
btn.dataset.btn
|
|
6525
|
+
);
|
|
6358
6526
|
if (def && typeof def.isActive === "function") btn.classList.toggle("active", !!def.isActive(this.context));
|
|
6359
|
-
if (def && typeof def.isDisabled === "function")
|
|
6527
|
+
if (def && typeof def.isDisabled === "function")
|
|
6528
|
+
/** @type {HTMLButtonElement} */ btn.disabled = !!def.isDisabled(this.context);
|
|
6360
6529
|
});
|
|
6361
6530
|
this.el.querySelectorAll("select[data-btn]").forEach((select) => {
|
|
6362
|
-
const def = btnMap.get(
|
|
6531
|
+
const def = btnMap.get(
|
|
6532
|
+
/** @type {HTMLElement} */
|
|
6533
|
+
select.dataset.btn
|
|
6534
|
+
);
|
|
6363
6535
|
if (!def || typeof def.getValue !== "function") return;
|
|
6364
6536
|
let raw = (def.getValue(this.context) || "").replace(/["']/g, "").trim();
|
|
6365
6537
|
if (!raw) raw = this.options.defaultFontFamily || this.options.fontFamilies && this.options.fontFamilies[0] || "";
|
|
6366
|
-
const
|
|
6367
|
-
|
|
6538
|
+
const sel = select;
|
|
6539
|
+
const matched = Array.from(sel.options).find((opt) => opt.value && opt.value.toLowerCase() === raw.toLowerCase());
|
|
6540
|
+
sel.value = matched ? matched.value : "";
|
|
6368
6541
|
});
|
|
6369
6542
|
}
|
|
6370
6543
|
/**
|
|
@@ -6484,7 +6657,7 @@ var Statusbar = class {
|
|
|
6484
6657
|
this._dragDisposers.forEach((d) => d());
|
|
6485
6658
|
this._dragDisposers = null;
|
|
6486
6659
|
}
|
|
6487
|
-
|
|
6660
|
+
this.el?.remove();
|
|
6488
6661
|
this.el = null;
|
|
6489
6662
|
}
|
|
6490
6663
|
_bindResize(handle) {
|
|
@@ -6548,7 +6721,7 @@ var Statusbar = class {
|
|
|
6548
6721
|
if (!this._wordCountEl || !this._charCountEl) return;
|
|
6549
6722
|
const text = this.context.layoutInfo.editable.textContent || "";
|
|
6550
6723
|
const words = _countWords(text);
|
|
6551
|
-
const chars = text.
|
|
6724
|
+
const chars = text.replaceAll("\n", "").length;
|
|
6552
6725
|
const maxWords = this.options.maxWords || 0;
|
|
6553
6726
|
const maxChars = this.options.maxChars || 0;
|
|
6554
6727
|
const LS = this.context.locale.statusbar;
|
|
@@ -6570,7 +6743,7 @@ var Statusbar = class {
|
|
|
6570
6743
|
* @returns {number}
|
|
6571
6744
|
*/
|
|
6572
6745
|
getCharCount() {
|
|
6573
|
-
return (this.context.layoutInfo.editable.innerText || "").
|
|
6746
|
+
return (this.context.layoutInfo.editable.innerText || "").replaceAll("\n", "").length;
|
|
6574
6747
|
}
|
|
6575
6748
|
};
|
|
6576
6749
|
//#endregion
|
|
@@ -6663,7 +6836,7 @@ var Clipboard = class {
|
|
|
6663
6836
|
if (el.querySelector("a, strong, em, b, i, ul, ol, li, table, img, blockquote, pre, code, h1, h2, h3, h4, h5, h6")) continue;
|
|
6664
6837
|
const parent = el.parentNode;
|
|
6665
6838
|
while (el.firstChild) parent.insertBefore(el.firstChild, el);
|
|
6666
|
-
|
|
6839
|
+
el.remove();
|
|
6667
6840
|
}
|
|
6668
6841
|
doc.querySelectorAll("*").forEach((el) => {
|
|
6669
6842
|
el.removeAttribute("class");
|
|
@@ -6705,7 +6878,7 @@ var Clipboard = class {
|
|
|
6705
6878
|
this._forcePlain = !!val;
|
|
6706
6879
|
}
|
|
6707
6880
|
_onPaste(event) {
|
|
6708
|
-
const clipboardData = event.clipboardData ||
|
|
6881
|
+
const clipboardData = event.clipboardData || globalThis.clipboardData;
|
|
6709
6882
|
if (!clipboardData) return;
|
|
6710
6883
|
const forcePlain = this._forcePlain;
|
|
6711
6884
|
this._forcePlain = false;
|
|
@@ -6749,7 +6922,6 @@ var Clipboard = class {
|
|
|
6749
6922
|
if (this.options.pasteStripAttributes) html = this._stripAttributes(html);
|
|
6750
6923
|
execCommand("insertHTML", html);
|
|
6751
6924
|
this.context.invoke("editor.afterCommand");
|
|
6752
|
-
return;
|
|
6753
6925
|
}
|
|
6754
6926
|
}
|
|
6755
6927
|
_onDragover(event) {
|
|
@@ -6781,17 +6953,17 @@ var Clipboard = class {
|
|
|
6781
6953
|
this.options.onImageUpload(files);
|
|
6782
6954
|
return;
|
|
6783
6955
|
}
|
|
6784
|
-
const UNSUPPORTED = [
|
|
6956
|
+
const UNSUPPORTED = new Set([
|
|
6785
6957
|
"image/tiff",
|
|
6786
6958
|
"image/x-tiff",
|
|
6787
6959
|
"image/bmp",
|
|
6788
6960
|
"image/x-bmp",
|
|
6789
6961
|
"image/x-ms-bmp"
|
|
6790
|
-
];
|
|
6962
|
+
]);
|
|
6791
6963
|
const maxBytes = (this.options.maxImageSize || 5) * 1024 * 1024;
|
|
6792
6964
|
files.forEach((file) => {
|
|
6793
6965
|
if (!file || !file.type.startsWith("image/")) return;
|
|
6794
|
-
if (UNSUPPORTED.
|
|
6966
|
+
if (UNSUPPORTED.has(file.type)) {
|
|
6795
6967
|
const message = `Image format "${file.type}" is not supported for display in web browsers. Please convert to PNG, JPEG, or WebP first.`;
|
|
6796
6968
|
this.context.triggerEvent("imageError", {
|
|
6797
6969
|
file,
|
|
@@ -6843,10 +7015,10 @@ var Clipboard = class {
|
|
|
6843
7015
|
*/
|
|
6844
7016
|
_dataUrlToBlob(dataUrl) {
|
|
6845
7017
|
const [header, b64] = dataUrl.split(",");
|
|
6846
|
-
const mime =
|
|
7018
|
+
const mime = /:(.*?);/.exec(header)?.[1] ?? "image/png";
|
|
6847
7019
|
const binary = atob(b64);
|
|
6848
7020
|
const arr = new Uint8Array(binary.length);
|
|
6849
|
-
for (let i = 0; i < binary.length; i++) arr[i] = binary.
|
|
7021
|
+
for (let i = 0; i < binary.length; i++) arr[i] = binary.codePointAt(i);
|
|
6850
7022
|
return new Blob([arr], { type: mime });
|
|
6851
7023
|
}
|
|
6852
7024
|
/**
|
|
@@ -6914,7 +7086,7 @@ var Clipboard = class {
|
|
|
6914
7086
|
}
|
|
6915
7087
|
}
|
|
6916
7088
|
if (!range) return;
|
|
6917
|
-
const sel =
|
|
7089
|
+
const sel = globalThis.getSelection();
|
|
6918
7090
|
if (sel) {
|
|
6919
7091
|
sel.removeAllRanges();
|
|
6920
7092
|
sel.addRange(range);
|
|
@@ -6926,7 +7098,7 @@ var Clipboard = class {
|
|
|
6926
7098
|
* @returns {string}
|
|
6927
7099
|
*/
|
|
6928
7100
|
_escapeHTML(str) {
|
|
6929
|
-
return str.
|
|
7101
|
+
return str.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """).replaceAll("'", "'");
|
|
6930
7102
|
}
|
|
6931
7103
|
};
|
|
6932
7104
|
//#endregion
|
|
@@ -6963,7 +7135,7 @@ var Placeholder = class {
|
|
|
6963
7135
|
_update() {
|
|
6964
7136
|
const editable = this.context.layoutInfo.editable;
|
|
6965
7137
|
const isFocused = document.activeElement === editable;
|
|
6966
|
-
const isEmpty = !(editable.textContent.
|
|
7138
|
+
const isEmpty = !(editable.textContent.replaceAll("", "").trim().length > 0) && !editable.querySelector("img, table, hr, .an-video-wrapper");
|
|
6967
7139
|
editable.classList.toggle("an-placeholder", isEmpty && !isFocused);
|
|
6968
7140
|
}
|
|
6969
7141
|
};
|
|
@@ -6991,7 +7163,7 @@ var Codeview = class {
|
|
|
6991
7163
|
destroy() {
|
|
6992
7164
|
this._disposers.forEach((d) => d());
|
|
6993
7165
|
this._disposers = [];
|
|
6994
|
-
|
|
7166
|
+
this._textarea?.remove();
|
|
6995
7167
|
this._textarea = null;
|
|
6996
7168
|
}
|
|
6997
7169
|
toggle() {
|
|
@@ -7022,7 +7194,7 @@ var Codeview = class {
|
|
|
7022
7194
|
if (!this._active || !this._textarea) return;
|
|
7023
7195
|
const { editable } = this.context.layoutInfo;
|
|
7024
7196
|
editable.innerHTML = sanitiseHTML(this._textarea.value, { allowIframes: true });
|
|
7025
|
-
this._textarea.
|
|
7197
|
+
this._textarea.remove();
|
|
7026
7198
|
this._textarea = null;
|
|
7027
7199
|
editable.style.display = "";
|
|
7028
7200
|
this._active = false;
|
|
@@ -7046,7 +7218,7 @@ var Codeview = class {
|
|
|
7046
7218
|
}).split("\n").map((line) => {
|
|
7047
7219
|
const stripped = line.trim();
|
|
7048
7220
|
if (!stripped) return "";
|
|
7049
|
-
if (
|
|
7221
|
+
if (stripped.startsWith("</")) indent = Math.max(0, indent - 1);
|
|
7050
7222
|
const out = " ".repeat(indent) + stripped;
|
|
7051
7223
|
if (/^<[^/!][^>]*[^/]>/.test(stripped) && !INLINE_RE.test(stripped) && !/^<(br|hr|img|input|link|meta)/.test(stripped)) indent++;
|
|
7052
7224
|
return out;
|
|
@@ -7135,7 +7307,7 @@ var LinkDialog = class {
|
|
|
7135
7307
|
destroy() {
|
|
7136
7308
|
this._disposers.forEach((d) => d());
|
|
7137
7309
|
this._disposers = [];
|
|
7138
|
-
if (this._dialog && this._dialog.parentNode) this._dialog.
|
|
7310
|
+
if (this._dialog && this._dialog.parentNode) this._dialog.remove();
|
|
7139
7311
|
this._dialog = null;
|
|
7140
7312
|
}
|
|
7141
7313
|
/**
|
|
@@ -7158,8 +7330,13 @@ var LinkDialog = class {
|
|
|
7158
7330
|
"aria-label": L.ariaLabel
|
|
7159
7331
|
});
|
|
7160
7332
|
const box = createElement("div", { class: "an-dialog-box" });
|
|
7333
|
+
const header = createElement("div", { class: "an-dialog-header" });
|
|
7334
|
+
const iconEl = createElement("span", { class: "an-dialog-icon" });
|
|
7335
|
+
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>`;
|
|
7161
7336
|
const title = createElement("h3", { class: "an-dialog-title" });
|
|
7162
7337
|
title.textContent = L.title;
|
|
7338
|
+
header.appendChild(iconEl);
|
|
7339
|
+
header.appendChild(title);
|
|
7163
7340
|
const urlLabel = createElement("label", { class: "an-label" });
|
|
7164
7341
|
urlLabel.textContent = L.url;
|
|
7165
7342
|
const urlInput = createElement("input", {
|
|
@@ -7204,8 +7381,9 @@ var LinkDialog = class {
|
|
|
7204
7381
|
cancelBtn.textContent = L.cancelBtn;
|
|
7205
7382
|
btnRow.appendChild(insertBtn);
|
|
7206
7383
|
btnRow.appendChild(cancelBtn);
|
|
7207
|
-
box.append(
|
|
7384
|
+
box.append(header, urlLabel, urlInput, textLabel, textInput, tabLabel, btnRow);
|
|
7208
7385
|
overlay.appendChild(box);
|
|
7386
|
+
makeDraggable(header, box);
|
|
7209
7387
|
const d1 = on(insertBtn, "click", () => this._onInsert());
|
|
7210
7388
|
const d2 = on(cancelBtn, "click", () => this._close());
|
|
7211
7389
|
const d3 = on(overlay, "click", (e) => {
|
|
@@ -7227,7 +7405,7 @@ var LinkDialog = class {
|
|
|
7227
7405
|
return overlay;
|
|
7228
7406
|
}
|
|
7229
7407
|
_prefill() {
|
|
7230
|
-
const sel =
|
|
7408
|
+
const sel = globalThis.getSelection();
|
|
7231
7409
|
let anchor = null;
|
|
7232
7410
|
if (sel && sel.rangeCount > 0) {
|
|
7233
7411
|
let node = sel.getRangeAt(0).startContainer;
|
|
@@ -7314,7 +7492,7 @@ var ImageDialog = class {
|
|
|
7314
7492
|
destroy() {
|
|
7315
7493
|
this._disposers.forEach((d) => d());
|
|
7316
7494
|
this._disposers = [];
|
|
7317
|
-
if (this._dialog && this._dialog.parentNode) this._dialog.
|
|
7495
|
+
if (this._dialog && this._dialog.parentNode) this._dialog.remove();
|
|
7318
7496
|
this._dialog = null;
|
|
7319
7497
|
}
|
|
7320
7498
|
show() {
|
|
@@ -7335,8 +7513,13 @@ var ImageDialog = class {
|
|
|
7335
7513
|
"aria-label": L.ariaLabel
|
|
7336
7514
|
});
|
|
7337
7515
|
const box = createElement("div", { class: "an-dialog-box" });
|
|
7516
|
+
const header = createElement("div", { class: "an-dialog-header" });
|
|
7517
|
+
const iconEl = createElement("span", { class: "an-dialog-icon" });
|
|
7518
|
+
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>`;
|
|
7338
7519
|
const title = createElement("h3", { class: "an-dialog-title" });
|
|
7339
7520
|
title.textContent = L.title;
|
|
7521
|
+
header.appendChild(iconEl);
|
|
7522
|
+
header.appendChild(title);
|
|
7340
7523
|
const urlLabel = createElement("label", { class: "an-label" });
|
|
7341
7524
|
urlLabel.textContent = L.imageUrl;
|
|
7342
7525
|
const urlInput = createElement("input", {
|
|
@@ -7355,7 +7538,7 @@ var ImageDialog = class {
|
|
|
7355
7538
|
autocomplete: "off"
|
|
7356
7539
|
});
|
|
7357
7540
|
this._altInput = altInput;
|
|
7358
|
-
box.append(
|
|
7541
|
+
box.append(header, urlLabel, urlInput, altLabel, altInput);
|
|
7359
7542
|
const alignLabel = createElement("label", { class: "an-label" });
|
|
7360
7543
|
alignLabel.textContent = L.alignment;
|
|
7361
7544
|
const alignRow = createElement("div", { class: "an-align-row" });
|
|
@@ -7424,6 +7607,7 @@ var ImageDialog = class {
|
|
|
7424
7607
|
btnRow.appendChild(cancelBtn);
|
|
7425
7608
|
box.append(btnRow);
|
|
7426
7609
|
overlay.appendChild(box);
|
|
7610
|
+
makeDraggable(header, box);
|
|
7427
7611
|
const d1 = on(insertBtn, "click", () => this._onInsert());
|
|
7428
7612
|
const d2 = on(cancelBtn, "click", () => this._close());
|
|
7429
7613
|
const d3 = on(overlay, "click", (e) => {
|
|
@@ -7540,7 +7724,7 @@ var VideoDialog = class {
|
|
|
7540
7724
|
destroy() {
|
|
7541
7725
|
this._disposers.forEach((d) => d());
|
|
7542
7726
|
this._disposers = [];
|
|
7543
|
-
if (this._dialog && this._dialog.parentNode) this._dialog.
|
|
7727
|
+
if (this._dialog && this._dialog.parentNode) this._dialog.remove();
|
|
7544
7728
|
this._dialog = null;
|
|
7545
7729
|
}
|
|
7546
7730
|
show() {
|
|
@@ -7561,8 +7745,13 @@ var VideoDialog = class {
|
|
|
7561
7745
|
"aria-label": L.ariaLabel
|
|
7562
7746
|
});
|
|
7563
7747
|
const box = createElement("div", { class: "an-dialog-box" });
|
|
7748
|
+
const header = createElement("div", { class: "an-dialog-header" });
|
|
7749
|
+
const iconEl = createElement("span", { class: "an-dialog-icon" });
|
|
7750
|
+
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>`;
|
|
7564
7751
|
const title = createElement("h3", { class: "an-dialog-title" });
|
|
7565
7752
|
title.textContent = L.title;
|
|
7753
|
+
header.appendChild(iconEl);
|
|
7754
|
+
header.appendChild(title);
|
|
7566
7755
|
const urlLabel = createElement("label", { class: "an-label" });
|
|
7567
7756
|
urlLabel.textContent = L.videoUrl;
|
|
7568
7757
|
const urlInput = createElement("input", {
|
|
@@ -7598,8 +7787,9 @@ var VideoDialog = class {
|
|
|
7598
7787
|
cancelBtn.textContent = L.cancelBtn;
|
|
7599
7788
|
btnRow.appendChild(insertBtn);
|
|
7600
7789
|
btnRow.appendChild(cancelBtn);
|
|
7601
|
-
box.append(
|
|
7790
|
+
box.append(header, urlLabel, urlInput, hintEl, widthLabel, widthInput, btnRow);
|
|
7602
7791
|
overlay.appendChild(box);
|
|
7792
|
+
makeDraggable(header, box);
|
|
7603
7793
|
const d0 = on(urlInput, "input", () => {
|
|
7604
7794
|
const info = this._parseVideoUrl(urlInput.value.trim());
|
|
7605
7795
|
hintEl.textContent = info ? this.context.locale.videoDialog.detected(info.type) : urlInput.value ? this.context.locale.videoDialog.unknownFormat : "";
|
|
@@ -7620,7 +7810,7 @@ var VideoDialog = class {
|
|
|
7620
7810
|
}
|
|
7621
7811
|
_onInsert() {
|
|
7622
7812
|
const rawUrl = this._urlInput.value.trim();
|
|
7623
|
-
const width = Math.max(80, parseInt(this._widthInput.value, 10) || 560);
|
|
7813
|
+
const width = Math.max(80, Number.parseInt(this._widthInput.value, 10) || 560);
|
|
7624
7814
|
if (!rawUrl) {
|
|
7625
7815
|
this._urlInput.focus();
|
|
7626
7816
|
return;
|
|
@@ -7663,22 +7853,22 @@ var VideoDialog = class {
|
|
|
7663
7853
|
} catch {
|
|
7664
7854
|
return null;
|
|
7665
7855
|
}
|
|
7666
|
-
const ytWatch =
|
|
7856
|
+
const ytWatch = /(?:youtube\.com\/watch\?(?:.*&)?v=|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/.exec(url);
|
|
7667
7857
|
if (ytWatch) return {
|
|
7668
7858
|
type: "YouTube",
|
|
7669
7859
|
embedUrl: `https://www.youtube.com/embed/${ytWatch[1]}`
|
|
7670
7860
|
};
|
|
7671
|
-
const ytShort =
|
|
7861
|
+
const ytShort = /youtu\.be\/([a-zA-Z0-9_-]{11})/.exec(url);
|
|
7672
7862
|
if (ytShort) return {
|
|
7673
7863
|
type: "YouTube",
|
|
7674
7864
|
embedUrl: `https://www.youtube.com/embed/${ytShort[1]}`
|
|
7675
7865
|
};
|
|
7676
|
-
const ytShorts =
|
|
7866
|
+
const ytShorts = /youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/.exec(url);
|
|
7677
7867
|
if (ytShorts) return {
|
|
7678
7868
|
type: "YouTube Shorts",
|
|
7679
7869
|
embedUrl: `https://www.youtube.com/embed/${ytShorts[1]}`
|
|
7680
7870
|
};
|
|
7681
|
-
const vimeo =
|
|
7871
|
+
const vimeo = /vimeo\.com\/(\d+)/.exec(url);
|
|
7682
7872
|
if (vimeo) return {
|
|
7683
7873
|
type: "Vimeo",
|
|
7684
7874
|
embedUrl: `https://player.vimeo.com/video/${vimeo[1]}`
|
|
@@ -7702,7 +7892,7 @@ var VideoDialog = class {
|
|
|
7702
7892
|
const iframeTitle = `${info.type} video player`;
|
|
7703
7893
|
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>`;
|
|
7704
7894
|
}
|
|
7705
|
-
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.
|
|
7895
|
+
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>`;
|
|
7706
7896
|
const safeSrc = (() => {
|
|
7707
7897
|
try {
|
|
7708
7898
|
const p = new URL(url);
|
|
@@ -7713,7 +7903,7 @@ var VideoDialog = class {
|
|
|
7713
7903
|
}
|
|
7714
7904
|
})();
|
|
7715
7905
|
if (!safeSrc) return null;
|
|
7716
|
-
return `<div class="an-video-wrapper" style="position:relative;display:block;width:${width}px;max-width:100%"><video src="${safeSrc.
|
|
7906
|
+
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>`;
|
|
7717
7907
|
}
|
|
7718
7908
|
};
|
|
7719
7909
|
//#endregion
|
|
@@ -7782,9 +7972,9 @@ var ImageResizer = class {
|
|
|
7782
7972
|
};
|
|
7783
7973
|
this._disposers.push(on(editable, "click", (e) => this._onEditorClick(e)), on(editable, "contextmenu", (e) => {
|
|
7784
7974
|
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
7785
|
-
const img = e.target
|
|
7975
|
+
const img = e.target?.closest("img");
|
|
7786
7976
|
if (img) this._select(img);
|
|
7787
|
-
}), on(document, "click", (e) => this._onDocClick(e)), on(
|
|
7977
|
+
}), 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 }));
|
|
7788
7978
|
return this;
|
|
7789
7979
|
}
|
|
7790
7980
|
destroy() {
|
|
@@ -7799,7 +7989,7 @@ var ImageResizer = class {
|
|
|
7799
7989
|
this._positionRaf = null;
|
|
7800
7990
|
}
|
|
7801
7991
|
this._deselect();
|
|
7802
|
-
if (this._overlay && this._overlay.parentNode) this._overlay.
|
|
7992
|
+
if (this._overlay && this._overlay.parentNode) this._overlay.remove();
|
|
7803
7993
|
this._overlay = null;
|
|
7804
7994
|
}
|
|
7805
7995
|
/** @returns {HTMLImageElement|null} */
|
|
@@ -8001,7 +8191,7 @@ var VideoResizer = class {
|
|
|
8001
8191
|
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
8002
8192
|
const wrapper = this._findWrapper(e.target);
|
|
8003
8193
|
if (wrapper) this._select(wrapper);
|
|
8004
|
-
}), on(document, "click", (e) => this._onDocClick(e)), on(
|
|
8194
|
+
}), 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) => {
|
|
8005
8195
|
if (e.target instanceof Element && e.target.closest(".an-video-wrapper")) e.preventDefault();
|
|
8006
8196
|
}));
|
|
8007
8197
|
return this;
|
|
@@ -8018,7 +8208,7 @@ var VideoResizer = class {
|
|
|
8018
8208
|
this._positionRaf = null;
|
|
8019
8209
|
}
|
|
8020
8210
|
this._deselect();
|
|
8021
|
-
|
|
8211
|
+
this._overlay?.remove();
|
|
8022
8212
|
this._overlay = null;
|
|
8023
8213
|
}
|
|
8024
8214
|
/** @returns {HTMLElement|null} */
|
|
@@ -8039,7 +8229,7 @@ var VideoResizer = class {
|
|
|
8039
8229
|
*/
|
|
8040
8230
|
_findWrapper(el) {
|
|
8041
8231
|
if (!el || !(el instanceof Element)) return null;
|
|
8042
|
-
if (el.classList
|
|
8232
|
+
if (el.classList?.contains("an-video-wrapper")) return el;
|
|
8043
8233
|
const w = el.closest(".an-video-wrapper");
|
|
8044
8234
|
if (w) return w;
|
|
8045
8235
|
return null;
|
|
@@ -8072,7 +8262,7 @@ var VideoResizer = class {
|
|
|
8072
8262
|
_onDocClick(e) {
|
|
8073
8263
|
if (!this._activeWrapper) return;
|
|
8074
8264
|
if (this._activeWrapper.contains(e.target)) return;
|
|
8075
|
-
if (this._overlay
|
|
8265
|
+
if (this._overlay?.contains(e.target)) return;
|
|
8076
8266
|
if (e.target.closest(".an-contextmenu")) return;
|
|
8077
8267
|
this._deselect();
|
|
8078
8268
|
}
|
|
@@ -8192,19 +8382,19 @@ var LinkTooltip = class {
|
|
|
8192
8382
|
document.body.appendChild(this._el);
|
|
8193
8383
|
const editable = this.context.layoutInfo.editable;
|
|
8194
8384
|
this._disposers.push(on(editable, "mouseover", (e) => {
|
|
8195
|
-
const anchor = e.target
|
|
8385
|
+
const anchor = e.target?.closest("a[href]");
|
|
8196
8386
|
if (anchor && editable.contains(anchor)) this._scheduleShow(anchor);
|
|
8197
8387
|
}), on(editable, "mouseout", (e) => {
|
|
8198
8388
|
const to = e.relatedTarget;
|
|
8199
8389
|
if (!to || !editable.contains(to) && !this._el.contains(to)) this._scheduleHide();
|
|
8200
|
-
}));
|
|
8390
|
+
}), on(globalThis, "scroll", () => this._hide(), { passive: true }), on(globalThis, "resize", () => this._hide(), { passive: true }));
|
|
8201
8391
|
return this;
|
|
8202
8392
|
}
|
|
8203
8393
|
destroy() {
|
|
8204
8394
|
this._clearTimers();
|
|
8205
8395
|
this._disposers.forEach((d) => d());
|
|
8206
8396
|
this._disposers = [];
|
|
8207
|
-
if (this._el && this._el.parentNode) this._el.
|
|
8397
|
+
if (this._el && this._el.parentNode) this._el.remove();
|
|
8208
8398
|
this._el = null;
|
|
8209
8399
|
}
|
|
8210
8400
|
_buildTooltip() {
|
|
@@ -8289,8 +8479,8 @@ var LinkTooltip = class {
|
|
|
8289
8479
|
const margin = 6;
|
|
8290
8480
|
let top = rect.bottom + margin;
|
|
8291
8481
|
let left = rect.left;
|
|
8292
|
-
if (top + tipH >
|
|
8293
|
-
if (left + tipW >
|
|
8482
|
+
if (top + tipH > globalThis.innerHeight - margin) top = rect.top - tipH - margin;
|
|
8483
|
+
if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
|
|
8294
8484
|
if (left < margin) left = margin;
|
|
8295
8485
|
this._el.style.top = `${top}px`;
|
|
8296
8486
|
this._el.style.left = `${left}px`;
|
|
@@ -8305,12 +8495,12 @@ var LinkTooltip = class {
|
|
|
8305
8495
|
}
|
|
8306
8496
|
}
|
|
8307
8497
|
_openLink() {
|
|
8308
|
-
const url = this._activeAnchor
|
|
8309
|
-
if (url)
|
|
8498
|
+
const url = this._activeAnchor?.getAttribute("href");
|
|
8499
|
+
if (url) globalThis.open(url, "_blank", "noopener,noreferrer");
|
|
8310
8500
|
this._hide();
|
|
8311
8501
|
}
|
|
8312
8502
|
_copyLink() {
|
|
8313
|
-
const url = this._activeAnchor
|
|
8503
|
+
const url = this._activeAnchor?.getAttribute("href");
|
|
8314
8504
|
if (url) navigator.clipboard.writeText(url).catch(() => {
|
|
8315
8505
|
const ta = document.createElement("textarea");
|
|
8316
8506
|
ta.value = url;
|
|
@@ -8319,7 +8509,7 @@ var LinkTooltip = class {
|
|
|
8319
8509
|
document.body.appendChild(ta);
|
|
8320
8510
|
ta.select();
|
|
8321
8511
|
document.execCommand("copy");
|
|
8322
|
-
|
|
8512
|
+
ta.remove();
|
|
8323
8513
|
});
|
|
8324
8514
|
if (this._copyBtn) {
|
|
8325
8515
|
this._copyBtn.classList.add("an-link-tooltip-btn--copied");
|
|
@@ -8330,7 +8520,7 @@ var LinkTooltip = class {
|
|
|
8330
8520
|
const anchor = this._activeAnchor;
|
|
8331
8521
|
if (!anchor) return;
|
|
8332
8522
|
this._hide();
|
|
8333
|
-
const sel =
|
|
8523
|
+
const sel = globalThis.getSelection();
|
|
8334
8524
|
const range = document.createRange();
|
|
8335
8525
|
range.selectNodeContents(anchor);
|
|
8336
8526
|
sel.removeAllRanges();
|
|
@@ -8341,7 +8531,7 @@ var LinkTooltip = class {
|
|
|
8341
8531
|
const anchor = this._activeAnchor;
|
|
8342
8532
|
if (!anchor) return;
|
|
8343
8533
|
this._hide();
|
|
8344
|
-
const sel =
|
|
8534
|
+
const sel = globalThis.getSelection();
|
|
8345
8535
|
const range = document.createRange();
|
|
8346
8536
|
range.selectNode(anchor);
|
|
8347
8537
|
sel.removeAllRanges();
|
|
@@ -8382,21 +8572,22 @@ var ImageTooltip = class {
|
|
|
8382
8572
|
const editable = this.context.layoutInfo.editable;
|
|
8383
8573
|
this._disposers.push(on(editable, "mouseover", (e) => {
|
|
8384
8574
|
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
8385
|
-
const img = e.target
|
|
8575
|
+
const img = e.target?.closest("img");
|
|
8386
8576
|
if (img && editable.contains(img) && !img.closest("a[href]")) this._scheduleShow(img);
|
|
8387
8577
|
}, { passive: true }), on(editable, "mouseout", (e) => {
|
|
8388
8578
|
const to = e.relatedTarget;
|
|
8389
8579
|
if (!to || !editable.contains(to) && !this._el.contains(to)) this._scheduleHide();
|
|
8390
8580
|
}, { passive: true }), on(document, "click", (e) => {
|
|
8391
|
-
|
|
8392
|
-
|
|
8581
|
+
const et = e.target;
|
|
8582
|
+
if (this._activeImg && !this._activeImg.contains(et) && !this._el.contains(et)) this._hide();
|
|
8583
|
+
}), on(globalThis, "scroll", () => this._hide(), { passive: true }), on(globalThis, "resize", () => this._hide(), { passive: true }));
|
|
8393
8584
|
return this;
|
|
8394
8585
|
}
|
|
8395
8586
|
destroy() {
|
|
8396
8587
|
this._clearTimers();
|
|
8397
8588
|
this._disposers.forEach((d) => d());
|
|
8398
8589
|
this._disposers = [];
|
|
8399
|
-
|
|
8590
|
+
this._el?.remove();
|
|
8400
8591
|
this._el = null;
|
|
8401
8592
|
}
|
|
8402
8593
|
_buildTooltip() {
|
|
@@ -8473,7 +8664,7 @@ var ImageTooltip = class {
|
|
|
8473
8664
|
clearTimeout(this._hideTimer);
|
|
8474
8665
|
this._hideTimer = setTimeout(() => this._hide(), HIDE_DELAY$3);
|
|
8475
8666
|
}
|
|
8476
|
-
_show(
|
|
8667
|
+
_show(_img) {
|
|
8477
8668
|
this._el.style.display = "flex";
|
|
8478
8669
|
requestAnimationFrame(() => {
|
|
8479
8670
|
if (this._activeImg) this._positionNear(this._activeImg);
|
|
@@ -8497,8 +8688,8 @@ var ImageTooltip = class {
|
|
|
8497
8688
|
const margin = 6;
|
|
8498
8689
|
let top = rect.bottom + margin;
|
|
8499
8690
|
let left = rect.left + (rect.width - tipW) / 2;
|
|
8500
|
-
if (top + tipH >
|
|
8501
|
-
if (left + tipW >
|
|
8691
|
+
if (top + tipH > globalThis.innerHeight - margin) top = rect.top - tipH - margin;
|
|
8692
|
+
if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
|
|
8502
8693
|
if (left < margin) left = margin;
|
|
8503
8694
|
this._el.style.top = `${top}px`;
|
|
8504
8695
|
this._el.style.left = `${left}px`;
|
|
@@ -8554,8 +8745,8 @@ var ImageTooltip = class {
|
|
|
8554
8745
|
const img = this._activeImg;
|
|
8555
8746
|
if (!img) return;
|
|
8556
8747
|
const current = img.style.transform || "";
|
|
8557
|
-
const match =
|
|
8558
|
-
const next = ((match ? parseFloat(match[1]) : 0) + delta + 360) % 360;
|
|
8748
|
+
const match = /rotate\((-?[\d.]+)deg\)/.exec(current);
|
|
8749
|
+
const next = ((match ? Number.parseFloat(match[1]) : 0) + delta + 360) % 360;
|
|
8559
8750
|
const cleaned = current.replace(/rotate\(-?[\d.]+deg\)/, "").trim();
|
|
8560
8751
|
img.style.transform = cleaned ? `${cleaned} rotate(${next}deg)` : next === 0 ? "" : `rotate(${next}deg)`;
|
|
8561
8752
|
this.context.invoke("editor.afterCommand");
|
|
@@ -8570,8 +8761,8 @@ var ImageTooltip = class {
|
|
|
8570
8761
|
this._hide();
|
|
8571
8762
|
this.context.invoke("imageResizer.deselect");
|
|
8572
8763
|
const figure = img.closest("figure.an-figure");
|
|
8573
|
-
if (figure
|
|
8574
|
-
else
|
|
8764
|
+
if (figure) figure.remove();
|
|
8765
|
+
else img.remove();
|
|
8575
8766
|
this.context.invoke("editor.afterCommand");
|
|
8576
8767
|
}
|
|
8577
8768
|
_crop() {
|
|
@@ -8590,7 +8781,7 @@ var ImageTooltip = class {
|
|
|
8590
8781
|
this._hide();
|
|
8591
8782
|
const range = document.createRange();
|
|
8592
8783
|
range.selectNodeContents(cap);
|
|
8593
|
-
const sel =
|
|
8784
|
+
const sel = globalThis.getSelection();
|
|
8594
8785
|
if (sel) {
|
|
8595
8786
|
sel.removeAllRanges();
|
|
8596
8787
|
sel.addRange(range);
|
|
@@ -8624,7 +8815,7 @@ var ImageTooltip = class {
|
|
|
8624
8815
|
figure.appendChild(figcaption);
|
|
8625
8816
|
const range = document.createRange();
|
|
8626
8817
|
range.selectNodeContents(figcaption);
|
|
8627
|
-
const sel =
|
|
8818
|
+
const sel = globalThis.getSelection();
|
|
8628
8819
|
if (sel) {
|
|
8629
8820
|
sel.removeAllRanges();
|
|
8630
8821
|
sel.addRange(range);
|
|
@@ -8665,14 +8856,15 @@ var VideoTooltip = class {
|
|
|
8665
8856
|
const editable = this.context.layoutInfo.editable;
|
|
8666
8857
|
this._disposers.push(on(editable, "mouseover", (e) => {
|
|
8667
8858
|
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
8668
|
-
const wrapper = e.target
|
|
8859
|
+
const wrapper = e.target?.closest(".an-video-wrapper");
|
|
8669
8860
|
if (wrapper && editable.contains(wrapper)) this._scheduleShow(wrapper);
|
|
8670
8861
|
}, { passive: true }), on(editable, "mouseout", (e) => {
|
|
8671
8862
|
const to = e.relatedTarget;
|
|
8672
8863
|
if (!to || !editable.contains(to) && !this._el.contains(to)) this._scheduleHide();
|
|
8673
8864
|
}, { passive: true }), on(document, "click", (e) => {
|
|
8674
|
-
|
|
8675
|
-
|
|
8865
|
+
const target = e.target;
|
|
8866
|
+
if (this._activeWrapper && !this._activeWrapper.contains(target) && !this._el.contains(target)) this._hide();
|
|
8867
|
+
}), on(globalThis, "scroll", () => this._hide(), { passive: true }), on(globalThis, "resize", () => this._hide(), { passive: true }));
|
|
8676
8868
|
return this;
|
|
8677
8869
|
}
|
|
8678
8870
|
destroy() {
|
|
@@ -8680,7 +8872,7 @@ var VideoTooltip = class {
|
|
|
8680
8872
|
this._clearTimers();
|
|
8681
8873
|
this._disposers.forEach((d) => d());
|
|
8682
8874
|
this._disposers = [];
|
|
8683
|
-
|
|
8875
|
+
this._el?.remove();
|
|
8684
8876
|
this._el = null;
|
|
8685
8877
|
}
|
|
8686
8878
|
_buildTooltip() {
|
|
@@ -8752,7 +8944,7 @@ var VideoTooltip = class {
|
|
|
8752
8944
|
if (this._hideTimer) return;
|
|
8753
8945
|
this._hideTimer = setTimeout(() => this._hide(), HIDE_DELAY$2);
|
|
8754
8946
|
}
|
|
8755
|
-
_show(
|
|
8947
|
+
_show(_wrapper) {
|
|
8756
8948
|
this._el.style.display = "flex";
|
|
8757
8949
|
requestAnimationFrame(() => {
|
|
8758
8950
|
if (this._activeWrapper) this._positionNear(this._activeWrapper);
|
|
@@ -8777,8 +8969,8 @@ var VideoTooltip = class {
|
|
|
8777
8969
|
const margin = 6;
|
|
8778
8970
|
let top = rect.bottom + margin;
|
|
8779
8971
|
let left = rect.left + (rect.width - tipW) / 2;
|
|
8780
|
-
if (top + tipH >
|
|
8781
|
-
if (left + tipW >
|
|
8972
|
+
if (top + tipH > globalThis.innerHeight - margin) top = rect.top - tipH - margin;
|
|
8973
|
+
if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
|
|
8782
8974
|
if (left < margin) left = margin;
|
|
8783
8975
|
this._el.style.top = `${top}px`;
|
|
8784
8976
|
this._el.style.left = `${left}px`;
|
|
@@ -8832,7 +9024,7 @@ var VideoTooltip = class {
|
|
|
8832
9024
|
if (!wrapper) return;
|
|
8833
9025
|
this._hide();
|
|
8834
9026
|
this.context.invoke("videoResizer.deselect");
|
|
8835
|
-
|
|
9027
|
+
wrapper.remove();
|
|
8836
9028
|
this.context.invoke("editor.afterCommand");
|
|
8837
9029
|
}
|
|
8838
9030
|
_togglePreview() {
|
|
@@ -8976,8 +9168,35 @@ var ICONS$2 = {
|
|
|
8976
9168
|
rowHeight: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="4" y1="7" x2="20" y2="7"/><line x1="4" y1="17" x2="20" y2="17"/><line x1="12" y1="7" x2="12" y2="17"/><path d="M9 10l3-3 3 3"/><path d="M9 14l3 3 3-3"/></svg>`,
|
|
8977
9169
|
tableBorder: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round"><line x1="3" y1="6" x2="21" y2="6" stroke-width="1"/><line x1="3" y1="13" x2="21" y2="13" stroke-width="2"/><line x1="3" y1="20" x2="21" y2="20" stroke-width="3"/></svg>`,
|
|
8978
9170
|
deleteTable: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" 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="1"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="3" y1="15" x2="21" y2="15"/><line x1="9" y1="3" x2="9" y2="21"/><line x1="15" y1="3" x2="15" y2="21"/><line x1="16" y1="16" x2="22" y2="22" stroke="#ef4444"/><line x1="22" y1="16" x2="16" y2="22" stroke="#ef4444"/></svg>`,
|
|
8979
|
-
selectCells: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4 L4 20 L9 15 L12 21 L14 20 L11 14 L17 14 Z" fill="currentColor" opacity="0.15"/><path d="M4 4 L4 20 L9 15 L12 21 L14 20 L11 14 L17 14 Z"/></svg
|
|
9171
|
+
selectCells: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4 L4 20 L9 15 L12 21 L14 20 L11 14 L17 14 Z" fill="currentColor" opacity="0.15"/><path d="M4 4 L4 20 L9 15 L12 21 L14 20 L11 14 L17 14 Z"/></svg>`,
|
|
9172
|
+
cellShade: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 11L8.93 3.36a1 1 0 0 0-1.29.08L3.22 7.8a1 1 0 0 0-.07 1.29L11 20"/><path d="m5 14 5-5"/><path d="M22 22a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2c0-1.5 2.5-5 3.5-5s3.5 3.5 3.5 5z"/></svg>`
|
|
8980
9173
|
};
|
|
9174
|
+
var SHADE_PRESETS = [
|
|
9175
|
+
"#000000",
|
|
9176
|
+
"#434343",
|
|
9177
|
+
"#666666",
|
|
9178
|
+
"#999999",
|
|
9179
|
+
"#b7b7b7",
|
|
9180
|
+
"#cccccc",
|
|
9181
|
+
"#efefef",
|
|
9182
|
+
"#ffffff",
|
|
9183
|
+
"#ff0000",
|
|
9184
|
+
"#ff9900",
|
|
9185
|
+
"#ffff00",
|
|
9186
|
+
"#00ff00",
|
|
9187
|
+
"#00ffff",
|
|
9188
|
+
"#4a86e8",
|
|
9189
|
+
"#9900ff",
|
|
9190
|
+
"#ff00ff",
|
|
9191
|
+
"#f4cccc",
|
|
9192
|
+
"#fce5cd",
|
|
9193
|
+
"#fff2cc",
|
|
9194
|
+
"#d9ead3",
|
|
9195
|
+
"#d0e0e3",
|
|
9196
|
+
"#c9daf8",
|
|
9197
|
+
"#d9d2e9",
|
|
9198
|
+
"#ead1dc"
|
|
9199
|
+
];
|
|
8981
9200
|
var TableTooltip = class {
|
|
8982
9201
|
/** @param {import('../Context.js').Context} context */
|
|
8983
9202
|
constructor(context) {
|
|
@@ -8992,6 +9211,9 @@ var TableTooltip = class {
|
|
|
8992
9211
|
this._sizeApply = null;
|
|
8993
9212
|
this._sizeTitleEl = null;
|
|
8994
9213
|
this._sizeInputEl = null;
|
|
9214
|
+
this._shadePopover = null;
|
|
9215
|
+
this._shadeTitleEl = null;
|
|
9216
|
+
this._shadeColorStrip = null;
|
|
8995
9217
|
this._selectMode = false;
|
|
8996
9218
|
this._selectedCells = [];
|
|
8997
9219
|
this._selectStart = null;
|
|
@@ -9004,6 +9226,8 @@ var TableTooltip = class {
|
|
|
9004
9226
|
document.body.appendChild(this._el);
|
|
9005
9227
|
this._sizePopover = this._buildSizePopover();
|
|
9006
9228
|
document.body.appendChild(this._sizePopover);
|
|
9229
|
+
this._shadePopover = this._buildCellShadePopover();
|
|
9230
|
+
document.body.appendChild(this._shadePopover);
|
|
9007
9231
|
const editable = this.context.layoutInfo.editable;
|
|
9008
9232
|
this._editable = editable;
|
|
9009
9233
|
const onSelMousedown = (e) => {
|
|
@@ -9030,20 +9254,24 @@ var TableTooltip = class {
|
|
|
9030
9254
|
this._disposers.push(on(editable, "mousedown", onSelMousedown), on(editable, "mousemove", onSelMousemove), on(document, "mouseup", onSelMouseup));
|
|
9031
9255
|
this._disposers.push(on(editable, "mouseover", (e) => {
|
|
9032
9256
|
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
9033
|
-
const table = e.target
|
|
9257
|
+
const table = e.target?.closest("table");
|
|
9034
9258
|
if (table && editable.contains(table)) {
|
|
9035
|
-
const cell = e.target
|
|
9036
|
-
if (cell)
|
|
9259
|
+
const cell = e.target?.closest("td, th");
|
|
9260
|
+
if (cell) {
|
|
9261
|
+
this._activeCell = cell;
|
|
9262
|
+
this._syncShadeStrip();
|
|
9263
|
+
}
|
|
9037
9264
|
this._scheduleShow(table);
|
|
9038
9265
|
}
|
|
9039
9266
|
}, { passive: true }), on(editable, "mouseout", (e) => {
|
|
9040
9267
|
if (this._selectMode) return;
|
|
9041
9268
|
const to = e.relatedTarget;
|
|
9042
|
-
if (!to || !editable.contains(to) && !this._el.contains(to) && !
|
|
9269
|
+
if (!to || !editable.contains(to) && !this._el.contains(to) && !this._sizePopover?.contains(to)) this._scheduleHide();
|
|
9043
9270
|
}, { passive: true }), on(document, "click", (e) => {
|
|
9044
|
-
|
|
9045
|
-
if (this.
|
|
9046
|
-
|
|
9271
|
+
const et = e.target;
|
|
9272
|
+
if (this._selectMode && this._activeTable?.contains(et)) return;
|
|
9273
|
+
if (this._activeTable && !this._activeTable.contains(et) && !this._el.contains(et) && !this._sizePopover?.contains(et)) this._hide();
|
|
9274
|
+
}), on(document, "selectionchange", () => this._syncShadeStrip()), on(globalThis, "scroll", () => this._hide(), { passive: true }), on(globalThis, "resize", () => this._hide(), { passive: true }));
|
|
9047
9275
|
this._initResize();
|
|
9048
9276
|
return this;
|
|
9049
9277
|
}
|
|
@@ -9169,10 +9397,12 @@ var TableTooltip = class {
|
|
|
9169
9397
|
this._clearTimers();
|
|
9170
9398
|
this._disposers.forEach((d) => d());
|
|
9171
9399
|
this._disposers = [];
|
|
9172
|
-
if (this._el && this._el.parentNode) this._el.
|
|
9400
|
+
if (this._el && this._el.parentNode) this._el.remove();
|
|
9173
9401
|
this._el = null;
|
|
9174
|
-
if (this._sizePopover && this._sizePopover.parentNode) this._sizePopover.
|
|
9402
|
+
if (this._sizePopover && this._sizePopover.parentNode) this._sizePopover.remove();
|
|
9175
9403
|
this._sizePopover = null;
|
|
9404
|
+
if (this._shadePopover && this._shadePopover.parentNode) this._shadePopover.remove();
|
|
9405
|
+
this._shadePopover = null;
|
|
9176
9406
|
}
|
|
9177
9407
|
_buildTooltip() {
|
|
9178
9408
|
const L = this.context.locale.tooltips.table;
|
|
@@ -9200,6 +9430,24 @@ var TableTooltip = class {
|
|
|
9200
9430
|
el.appendChild(this._makeBtn(ICONS$2.mergeCells, L.mergeCells, () => this._mergeCells()));
|
|
9201
9431
|
el.appendChild(this._makeBtn(ICONS$2.unmergeCells, L.unmergeCells, () => this._unmergeCells()));
|
|
9202
9432
|
el.appendChild(this._sep());
|
|
9433
|
+
const shadeBtn = createElement("button", {
|
|
9434
|
+
type: "button",
|
|
9435
|
+
class: "an-link-tooltip-btn an-link-tooltip-btn--shade",
|
|
9436
|
+
title: L.cellBackground
|
|
9437
|
+
});
|
|
9438
|
+
const shadeSvgWrap = createElement("span", { class: "an-bubble-btn-svg" });
|
|
9439
|
+
shadeSvgWrap.innerHTML = ICONS$2.cellShade;
|
|
9440
|
+
const shadeStrip = createElement("span", { class: "an-link-tooltip-color-strip" });
|
|
9441
|
+
shadeBtn.appendChild(shadeSvgWrap);
|
|
9442
|
+
shadeBtn.appendChild(shadeStrip);
|
|
9443
|
+
this._shadeColorStrip = shadeStrip;
|
|
9444
|
+
this._disposers.push(on(shadeBtn, "click", (e) => {
|
|
9445
|
+
e.preventDefault();
|
|
9446
|
+
e.stopPropagation();
|
|
9447
|
+
this._openCellShadePopover();
|
|
9448
|
+
}));
|
|
9449
|
+
el.appendChild(shadeBtn);
|
|
9450
|
+
el.appendChild(this._sep());
|
|
9203
9451
|
el.appendChild(this._makeBtn(ICONS$2.colWidth, L.columnWidth, () => this._openSizePopover("col")));
|
|
9204
9452
|
el.appendChild(this._makeBtn(ICONS$2.rowHeight, L.rowHeight, () => this._openSizePopover("row")));
|
|
9205
9453
|
el.appendChild(this._makeBtn(ICONS$2.tableBorder, L.tableBorderWidth, () => this._openSizePopover("border")));
|
|
@@ -9208,6 +9456,7 @@ var TableTooltip = class {
|
|
|
9208
9456
|
this._disposers.push(on(el, "mouseenter", () => this._clearTimers()), on(el, "mouseleave", () => {
|
|
9209
9457
|
if (this._selectMode) return;
|
|
9210
9458
|
if (this._sizePopover && this._sizePopover.style.display !== "none") return;
|
|
9459
|
+
if (this._shadePopover && this._shadePopover.style.display !== "none") return;
|
|
9211
9460
|
this._scheduleHide();
|
|
9212
9461
|
}));
|
|
9213
9462
|
return el;
|
|
@@ -9254,10 +9503,16 @@ var TableTooltip = class {
|
|
|
9254
9503
|
_show() {
|
|
9255
9504
|
if (!this._activeTable) return;
|
|
9256
9505
|
this._el.style.display = "flex";
|
|
9506
|
+
this._syncShadeStrip();
|
|
9257
9507
|
requestAnimationFrame(() => {
|
|
9258
9508
|
if (this._activeTable) this._positionNear(this._activeTable);
|
|
9259
9509
|
});
|
|
9260
9510
|
}
|
|
9511
|
+
_syncShadeStrip() {
|
|
9512
|
+
if (!this._shadeColorStrip || !this._el || this._el.style.display === "none") return;
|
|
9513
|
+
const cell = this._getCell();
|
|
9514
|
+
this._shadeColorStrip.style.background = cell?.style.backgroundColor || "transparent";
|
|
9515
|
+
}
|
|
9261
9516
|
_hide() {
|
|
9262
9517
|
this._el.style.display = "none";
|
|
9263
9518
|
this._activeTable = null;
|
|
@@ -9286,20 +9541,20 @@ var TableTooltip = class {
|
|
|
9286
9541
|
let left = rect.left + (rect.width - tipW) / 2;
|
|
9287
9542
|
let top = rect.top - tipH - margin;
|
|
9288
9543
|
if (top < margin) top = rect.bottom + margin;
|
|
9289
|
-
if (left + tipW >
|
|
9544
|
+
if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
|
|
9290
9545
|
if (left < margin) left = margin;
|
|
9291
9546
|
this._el.style.left = `${left}px`;
|
|
9292
9547
|
this._el.style.top = `${top}px`;
|
|
9293
9548
|
}
|
|
9294
9549
|
_getCell() {
|
|
9295
|
-
const sel =
|
|
9550
|
+
const sel = globalThis.getSelection();
|
|
9296
9551
|
if (sel && sel.rangeCount) {
|
|
9297
9552
|
let container = sel.getRangeAt(0).commonAncestorContainer;
|
|
9298
9553
|
if (container.nodeType === 3) container = container.parentElement;
|
|
9299
|
-
const cellFromSel = container
|
|
9300
|
-
if (cellFromSel && this._activeTable
|
|
9554
|
+
const cellFromSel = container?.closest("td, th");
|
|
9555
|
+
if (cellFromSel && this._activeTable?.contains(cellFromSel)) return cellFromSel;
|
|
9301
9556
|
}
|
|
9302
|
-
return this._activeCell || this._activeTable
|
|
9557
|
+
return this._activeCell || this._activeTable?.querySelector("td, th");
|
|
9303
9558
|
}
|
|
9304
9559
|
_toggleSelectMode() {
|
|
9305
9560
|
this._selectMode = !this._selectMode;
|
|
@@ -9398,11 +9653,12 @@ var TableTooltip = class {
|
|
|
9398
9653
|
const table = cells[0].closest("table");
|
|
9399
9654
|
if (!table) return;
|
|
9400
9655
|
const allRows = Array.from(table.querySelectorAll("tr"));
|
|
9401
|
-
const
|
|
9656
|
+
const selectedRows = [...new Set(cells.map((c) => c.closest("tr")).filter(Boolean))];
|
|
9657
|
+
const refRow = selectedRows.reduce((best, r) => {
|
|
9402
9658
|
const bi = allRows.indexOf(best);
|
|
9403
9659
|
const ri = allRows.indexOf(r);
|
|
9404
9660
|
return position === "above" ? ri < bi ? r : best : ri > bi ? r : best;
|
|
9405
|
-
});
|
|
9661
|
+
}, selectedRows[0]);
|
|
9406
9662
|
const colCount = Array.from(refRow.cells).reduce((sum, c) => sum + (c.colSpan || 1), 0);
|
|
9407
9663
|
const newRow = document.createElement("tr");
|
|
9408
9664
|
const refCells = Array.from(refRow.cells);
|
|
@@ -9445,7 +9701,7 @@ var TableTooltip = class {
|
|
|
9445
9701
|
if (selectedRows.filter((r) => r.closest("tbody")).length >= totalBodyRows) return;
|
|
9446
9702
|
this._activeCell = null;
|
|
9447
9703
|
this._clearSelection();
|
|
9448
|
-
selectedRows.forEach((r) => r.
|
|
9704
|
+
selectedRows.forEach((r) => r.remove());
|
|
9449
9705
|
requestAnimationFrame(() => this._positionNear(this._activeTable));
|
|
9450
9706
|
this.context.invoke("editor.afterCommand");
|
|
9451
9707
|
}
|
|
@@ -9467,7 +9723,7 @@ var TableTooltip = class {
|
|
|
9467
9723
|
});
|
|
9468
9724
|
this._activeCell = null;
|
|
9469
9725
|
this._clearSelection();
|
|
9470
|
-
cellsToDelete.forEach((c) => c.
|
|
9726
|
+
cellsToDelete.forEach((c) => c.remove());
|
|
9471
9727
|
requestAnimationFrame(() => this._positionNear(this._activeTable));
|
|
9472
9728
|
this.context.invoke("editor.afterCommand");
|
|
9473
9729
|
}
|
|
@@ -9478,7 +9734,7 @@ var TableTooltip = class {
|
|
|
9478
9734
|
if (!table) return;
|
|
9479
9735
|
let selected = this._getSelectedCells().filter((c) => table.contains(c));
|
|
9480
9736
|
if (selected.length < 2) {
|
|
9481
|
-
const sel =
|
|
9737
|
+
const sel = globalThis.getSelection();
|
|
9482
9738
|
if (!sel || sel.rangeCount === 0) return;
|
|
9483
9739
|
const range = sel.getRangeAt(0);
|
|
9484
9740
|
selected = Array.from(table.querySelectorAll("td, th")).filter((c) => {
|
|
@@ -9520,7 +9776,7 @@ var TableTooltip = class {
|
|
|
9520
9776
|
first.rowSpan = maxR - minR + 1;
|
|
9521
9777
|
first.style.verticalAlign = "middle";
|
|
9522
9778
|
first.innerHTML = rectCells.map((c) => c.innerHTML).join("");
|
|
9523
|
-
rectCells.slice(1).forEach((c) => c.
|
|
9779
|
+
rectCells.slice(1).forEach((c) => c.remove());
|
|
9524
9780
|
this._clearSelection();
|
|
9525
9781
|
this.context.invoke("editor.afterCommand");
|
|
9526
9782
|
}
|
|
@@ -9528,7 +9784,7 @@ var TableTooltip = class {
|
|
|
9528
9784
|
const table = this._activeTable;
|
|
9529
9785
|
if (!table) return;
|
|
9530
9786
|
this._hide();
|
|
9531
|
-
if (table.parentNode) table.
|
|
9787
|
+
if (table.parentNode) table.remove();
|
|
9532
9788
|
this.context.invoke("editor.afterCommand");
|
|
9533
9789
|
}
|
|
9534
9790
|
_unmergeCells() {
|
|
@@ -9617,20 +9873,22 @@ var TableTooltip = class {
|
|
|
9617
9873
|
this._sizeInputEl = inputEl;
|
|
9618
9874
|
this._sizeApply = null;
|
|
9619
9875
|
const d1 = on(applyBtn, "click", () => {
|
|
9620
|
-
const val = parseInt(this._sizeInputEl.value, 10);
|
|
9876
|
+
const val = Number.parseInt(this._sizeInputEl.value, 10);
|
|
9621
9877
|
if (val > 0 && typeof this._sizeApply === "function") this._sizeApply(val);
|
|
9622
9878
|
this._hideSizePopover();
|
|
9623
9879
|
});
|
|
9624
9880
|
const d2 = on(cancelBtn, "click", () => this._hideSizePopover());
|
|
9625
9881
|
const d3 = on(inputEl, "keydown", (e) => {
|
|
9626
|
-
|
|
9882
|
+
const ke = e;
|
|
9883
|
+
if (ke.key === "Enter") {
|
|
9627
9884
|
e.preventDefault();
|
|
9628
9885
|
applyBtn.click();
|
|
9629
9886
|
}
|
|
9630
|
-
if (
|
|
9887
|
+
if (ke.key === "Escape") this._hideSizePopover();
|
|
9631
9888
|
});
|
|
9632
9889
|
const d4 = on(document, "click", (e) => {
|
|
9633
|
-
|
|
9890
|
+
const et = e.target;
|
|
9891
|
+
if (this._sizePopover && this._sizePopover.style.display !== "none" && !this._sizePopover.contains(et) && !this._el.contains(et)) this._hideSizePopover();
|
|
9634
9892
|
});
|
|
9635
9893
|
const d5 = on(popover, "mouseenter", () => this._clearTimers());
|
|
9636
9894
|
const d6 = on(popover, "mouseleave", () => this._scheduleHide());
|
|
@@ -9644,11 +9902,11 @@ var TableTooltip = class {
|
|
|
9644
9902
|
const table = cell.closest("table");
|
|
9645
9903
|
if (!table) return;
|
|
9646
9904
|
const firstCell = table.querySelector("td, th");
|
|
9647
|
-
const currentPx = firstCell ? parseInt(firstCell.style.borderWidth, 10) || parseInt(
|
|
9905
|
+
const currentPx = firstCell ? Number.parseInt(firstCell.style.borderWidth, 10) || Number.parseInt(globalThis.getComputedStyle(firstCell).borderWidth, 10) || 1 : 1;
|
|
9648
9906
|
this._sizeTitleEl.textContent = this.context.locale.tooltips.table.tableBorderWidthPx;
|
|
9649
9907
|
this._sizeInputEl.min = "0";
|
|
9650
9908
|
this._sizeInputEl.max = "10";
|
|
9651
|
-
this._sizeInputEl.value = currentPx;
|
|
9909
|
+
this._sizeInputEl.value = String(currentPx);
|
|
9652
9910
|
this._sizeApply = (val) => {
|
|
9653
9911
|
const cells = Array.from(table.querySelectorAll("td, th"));
|
|
9654
9912
|
if (val === 0) cells.forEach((c) => {
|
|
@@ -9703,8 +9961,8 @@ var TableTooltip = class {
|
|
|
9703
9961
|
const ph = this._sizePopover.offsetHeight || 110;
|
|
9704
9962
|
let left = tipRect.left;
|
|
9705
9963
|
let top = tipRect.bottom + 6;
|
|
9706
|
-
if (left + pw >
|
|
9707
|
-
if (top + ph >
|
|
9964
|
+
if (left + pw > globalThis.innerWidth - 8) left = globalThis.innerWidth - pw - 8;
|
|
9965
|
+
if (top + ph > globalThis.innerHeight - 8) top = tipRect.top - ph - 6;
|
|
9708
9966
|
this._sizePopover.style.left = `${left}px`;
|
|
9709
9967
|
this._sizePopover.style.top = `${top}px`;
|
|
9710
9968
|
if (this._sizeInputEl) {
|
|
@@ -9717,6 +9975,84 @@ var TableTooltip = class {
|
|
|
9717
9975
|
if (this._sizePopover) this._sizePopover.style.display = "none";
|
|
9718
9976
|
this._sizeApply = null;
|
|
9719
9977
|
}
|
|
9978
|
+
_buildCellShadePopover() {
|
|
9979
|
+
const pop = createElement("div", { class: "an-cell-shade-popover" });
|
|
9980
|
+
pop.style.display = "none";
|
|
9981
|
+
const title = createElement("div", { class: "an-size-popover-title" });
|
|
9982
|
+
pop.appendChild(title);
|
|
9983
|
+
this._shadeTitleEl = title;
|
|
9984
|
+
const palette = createElement("div", { class: "an-context-color-palette" });
|
|
9985
|
+
SHADE_PRESETS.forEach((color) => {
|
|
9986
|
+
const sw = createElement("div", {
|
|
9987
|
+
class: "an-context-color-swatch",
|
|
9988
|
+
title: color
|
|
9989
|
+
});
|
|
9990
|
+
sw.style.background = color;
|
|
9991
|
+
this._disposers.push(on(sw, "click", (e) => {
|
|
9992
|
+
e.stopPropagation();
|
|
9993
|
+
this._applyCellShade(color);
|
|
9994
|
+
}));
|
|
9995
|
+
palette.appendChild(sw);
|
|
9996
|
+
});
|
|
9997
|
+
pop.appendChild(palette);
|
|
9998
|
+
const noShadeRow = createElement("div", { class: "an-context-color-custom" });
|
|
9999
|
+
const noShadeBtn = createElement("button", {
|
|
10000
|
+
type: "button",
|
|
10001
|
+
class: "an-shade-no-color"
|
|
10002
|
+
});
|
|
10003
|
+
this._disposers.push(on(noShadeBtn, "click", () => this._applyCellShade("")));
|
|
10004
|
+
noShadeRow.appendChild(noShadeBtn);
|
|
10005
|
+
pop.appendChild(noShadeRow);
|
|
10006
|
+
this._shadeNoBtn = noShadeBtn;
|
|
10007
|
+
const customRow = createElement("div", { class: "an-context-color-custom" });
|
|
10008
|
+
const colorInput = createElement("input", {
|
|
10009
|
+
type: "color",
|
|
10010
|
+
class: "an-shade-color-input",
|
|
10011
|
+
value: "#ffffff"
|
|
10012
|
+
});
|
|
10013
|
+
const customLabel = createElement("span");
|
|
10014
|
+
customLabel.textContent = "Custom…";
|
|
10015
|
+
this._disposers.push(on(colorInput, "change", () => this._applyCellShade(colorInput.value)));
|
|
10016
|
+
customRow.appendChild(colorInput);
|
|
10017
|
+
customRow.appendChild(customLabel);
|
|
10018
|
+
pop.appendChild(customRow);
|
|
10019
|
+
this._disposers.push(on(pop, "mousedown", (e) => e.preventDefault()), on(pop, "mouseenter", () => this._clearTimers()), on(pop, "mouseleave", () => this._scheduleHide()));
|
|
10020
|
+
this._disposers.push(on(document, "click", (e) => {
|
|
10021
|
+
const et = e.target;
|
|
10022
|
+
if (this._shadePopover && this._shadePopover.style.display !== "none" && !this._shadePopover.contains(et) && !this._el?.contains(et)) this._hideCellShadePopover();
|
|
10023
|
+
}));
|
|
10024
|
+
return pop;
|
|
10025
|
+
}
|
|
10026
|
+
_openCellShadePopover() {
|
|
10027
|
+
if (!this._shadePopover) return;
|
|
10028
|
+
const L = this.context.locale.tooltips.table;
|
|
10029
|
+
if (this._shadeTitleEl) this._shadeTitleEl.textContent = L.cellBackground;
|
|
10030
|
+
if (this._shadeNoBtn) this._shadeNoBtn.textContent = L.noShading;
|
|
10031
|
+
this._shadePopover.style.display = "block";
|
|
10032
|
+
requestAnimationFrame(() => {
|
|
10033
|
+
if (!this._shadePopover || !this._el) return;
|
|
10034
|
+
const pw = this._shadePopover.offsetWidth || 170;
|
|
10035
|
+
const ph = this._shadePopover.offsetHeight || 120;
|
|
10036
|
+
const tipRect = this._el.getBoundingClientRect();
|
|
10037
|
+
let left = tipRect.left;
|
|
10038
|
+
let top = tipRect.bottom + 6;
|
|
10039
|
+
if (left + pw > globalThis.innerWidth - 8) left = globalThis.innerWidth - pw - 8;
|
|
10040
|
+
if (top + ph > globalThis.innerHeight - 8) top = tipRect.top - ph - 6;
|
|
10041
|
+
this._shadePopover.style.left = `${Math.max(8, left)}px`;
|
|
10042
|
+
this._shadePopover.style.top = `${Math.max(8, top)}px`;
|
|
10043
|
+
});
|
|
10044
|
+
}
|
|
10045
|
+
_hideCellShadePopover() {
|
|
10046
|
+
if (this._shadePopover) this._shadePopover.style.display = "none";
|
|
10047
|
+
}
|
|
10048
|
+
_applyCellShade(color) {
|
|
10049
|
+
(this._selectMode ? this._selectedCells : [this._getCell()]).forEach((cell) => {
|
|
10050
|
+
if (cell) cell.style.backgroundColor = color;
|
|
10051
|
+
});
|
|
10052
|
+
if (this._shadeColorStrip) this._shadeColorStrip.style.background = color || "transparent";
|
|
10053
|
+
this._hideCellShadePopover();
|
|
10054
|
+
this.context.invoke("editor.afterCommand");
|
|
10055
|
+
}
|
|
9720
10056
|
};
|
|
9721
10057
|
//#endregion
|
|
9722
10058
|
//#region src/js/module/CodeTooltip.js
|
|
@@ -9749,13 +10085,14 @@ var CodeTooltip = class {
|
|
|
9749
10085
|
const editable = this.context.layoutInfo.editable;
|
|
9750
10086
|
this._disposers.push(on(editable, "mouseover", (e) => {
|
|
9751
10087
|
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
9752
|
-
const pre = e.target
|
|
10088
|
+
const pre = e.target?.closest("pre");
|
|
9753
10089
|
if (pre && editable.contains(pre)) this._scheduleShow(pre);
|
|
9754
10090
|
}), on(editable, "mouseout", (e) => {
|
|
9755
10091
|
const to = e.relatedTarget;
|
|
9756
10092
|
if (!to || !editable.contains(to) && !this._el.contains(to)) this._scheduleHide();
|
|
9757
10093
|
}), on(document, "click", (e) => {
|
|
9758
|
-
|
|
10094
|
+
const et = e.target;
|
|
10095
|
+
if (this._activePre && !this._activePre.contains(et) && !this._el.contains(et)) this._hide();
|
|
9759
10096
|
}));
|
|
9760
10097
|
return this;
|
|
9761
10098
|
}
|
|
@@ -9763,7 +10100,7 @@ var CodeTooltip = class {
|
|
|
9763
10100
|
this._clearTimers();
|
|
9764
10101
|
this._disposers.forEach((d) => d());
|
|
9765
10102
|
this._disposers = [];
|
|
9766
|
-
|
|
10103
|
+
this._el?.remove();
|
|
9767
10104
|
this._el = null;
|
|
9768
10105
|
}
|
|
9769
10106
|
_buildTooltip() {
|
|
@@ -9790,6 +10127,7 @@ var CodeTooltip = class {
|
|
|
9790
10127
|
["python", "Python"],
|
|
9791
10128
|
["html", "HTML"],
|
|
9792
10129
|
["css", "CSS"],
|
|
10130
|
+
["scss", "SCSS"],
|
|
9793
10131
|
["json", "JSON"],
|
|
9794
10132
|
["xml", "XML"],
|
|
9795
10133
|
["bash", "Bash / Shell"],
|
|
@@ -9888,21 +10226,21 @@ var CodeTooltip = class {
|
|
|
9888
10226
|
let top = rect.top - tipH - margin;
|
|
9889
10227
|
let left = rect.left + (rect.width - tipW) / 2;
|
|
9890
10228
|
if (top < margin) top = rect.bottom + margin;
|
|
9891
|
-
if (left + tipW >
|
|
10229
|
+
if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
|
|
9892
10230
|
if (left < margin) left = margin;
|
|
9893
10231
|
this._el.style.top = `${top}px`;
|
|
9894
10232
|
this._el.style.left = `${left}px`;
|
|
9895
10233
|
}
|
|
9896
10234
|
_syncWrapBtn() {
|
|
9897
10235
|
if (!this._activePre || !this._wrapBtn) return;
|
|
9898
|
-
const wrapped = (this._activePre.style.whiteSpace || "").includes("pre-wrap") ||
|
|
10236
|
+
const wrapped = (this._activePre.style.whiteSpace || "").includes("pre-wrap") || globalThis.getComputedStyle(this._activePre).whiteSpace === "pre-wrap";
|
|
9899
10237
|
this._wrapBtn.classList.toggle("active", wrapped);
|
|
9900
10238
|
this._wrapBtn.title = wrapped ? this.context.locale.tooltips.code.disableWordWrap : this.context.locale.tooltips.code.enableWordWrap;
|
|
9901
10239
|
}
|
|
9902
10240
|
_syncLangSelect() {
|
|
9903
10241
|
if (!this._activePre || !this._langSelect) return;
|
|
9904
10242
|
const codeEl = this._activePre.querySelector("code");
|
|
9905
|
-
const fromAttr = this._activePre.
|
|
10243
|
+
const fromAttr = this._activePre.dataset.language || "";
|
|
9906
10244
|
const fromClass = codeEl ? (_LANG_CLASS_RE.exec(codeEl.className) || [])[1] || "" : "";
|
|
9907
10245
|
this._langSelect.value = fromAttr || fromClass || "";
|
|
9908
10246
|
}
|
|
@@ -9921,7 +10259,7 @@ var CodeTooltip = class {
|
|
|
9921
10259
|
document.execCommand("copy");
|
|
9922
10260
|
this._flashCopied();
|
|
9923
10261
|
} catch (_) {}
|
|
9924
|
-
|
|
10262
|
+
ta.remove();
|
|
9925
10263
|
}
|
|
9926
10264
|
}
|
|
9927
10265
|
_flashCopied() {
|
|
@@ -9945,10 +10283,26 @@ var CodeTooltip = class {
|
|
|
9945
10283
|
this.context.invoke("editor.afterCommand");
|
|
9946
10284
|
this._positionNear(pre);
|
|
9947
10285
|
}
|
|
10286
|
+
/**
|
|
10287
|
+
* Applies a language to a given <pre> element: sets classes, data-language,
|
|
10288
|
+
* and triggers Prism highlighting. Called by the auto-detect flow.
|
|
10289
|
+
* @param {HTMLElement} pre
|
|
10290
|
+
* @param {string} lang - Prism language identifier, e.g. 'javascript'
|
|
10291
|
+
*/
|
|
10292
|
+
applyLanguage(pre, lang) {
|
|
10293
|
+
if (!pre || !lang) return;
|
|
10294
|
+
const savedPre = this._activePre;
|
|
10295
|
+
this._activePre = pre;
|
|
10296
|
+
if (this._langSelect) this._langSelect.value = lang;
|
|
10297
|
+
this._onLangChange();
|
|
10298
|
+
if (this._langSelect) this._langSelect.value = lang;
|
|
10299
|
+
this._activePre = savedPre || pre;
|
|
10300
|
+
}
|
|
9948
10301
|
_onLangChange() {
|
|
9949
10302
|
const pre = this._activePre;
|
|
9950
10303
|
if (!pre) return;
|
|
9951
10304
|
const lang = this._langSelect.value;
|
|
10305
|
+
const _w = globalThis;
|
|
9952
10306
|
let codeEl = pre.querySelector("code");
|
|
9953
10307
|
if (!codeEl) {
|
|
9954
10308
|
codeEl = document.createElement("code");
|
|
@@ -9958,16 +10312,16 @@ var CodeTooltip = class {
|
|
|
9958
10312
|
}
|
|
9959
10313
|
codeEl.className = lang ? `language-${lang}` : "";
|
|
9960
10314
|
pre.className = lang ? `language-${lang}` : "";
|
|
9961
|
-
if (lang) pre.
|
|
9962
|
-
else pre.
|
|
10315
|
+
if (lang) pre.dataset.language = lang;
|
|
10316
|
+
else delete pre.dataset.language;
|
|
9963
10317
|
const applyPrism = () => {
|
|
9964
10318
|
codeEl.querySelectorAll("br").forEach((br) => br.replaceWith("\n"));
|
|
9965
|
-
|
|
10319
|
+
_w.Prism.highlightElement(codeEl);
|
|
9966
10320
|
this.context.invoke("editor.afterCommand");
|
|
9967
10321
|
};
|
|
9968
10322
|
if (lang) {
|
|
9969
|
-
if (
|
|
9970
|
-
if (
|
|
10323
|
+
if (_w.Prism !== void 0) {
|
|
10324
|
+
if (_w.Prism.languages[lang]) {
|
|
9971
10325
|
applyPrism();
|
|
9972
10326
|
return;
|
|
9973
10327
|
}
|
|
@@ -9975,7 +10329,7 @@ var CodeTooltip = class {
|
|
|
9975
10329
|
return;
|
|
9976
10330
|
} else if (this._prismScript) {
|
|
9977
10331
|
this._prismScript.addEventListener("load", () => {
|
|
9978
|
-
if (
|
|
10332
|
+
if (_w.Prism.languages[lang]) applyPrism();
|
|
9979
10333
|
else this._loadPrismComponent(lang, applyPrism);
|
|
9980
10334
|
}, { once: true });
|
|
9981
10335
|
return;
|
|
@@ -9988,7 +10342,8 @@ var CodeTooltip = class {
|
|
|
9988
10342
|
* Called once at initialize time. Fire-and-forget; errors are silent.
|
|
9989
10343
|
*/
|
|
9990
10344
|
_ensurePrism() {
|
|
9991
|
-
|
|
10345
|
+
const _w = globalThis;
|
|
10346
|
+
if (!this.context.options.codeHighlight || _w.Prism) return;
|
|
9992
10347
|
const cdn = this.context.options.codeHighlightCDN;
|
|
9993
10348
|
const themeHref = `${cdn}/themes/prism-tomorrow.min.css`;
|
|
9994
10349
|
const scriptSrc = `${cdn}/prism.min.js`;
|
|
@@ -10000,7 +10355,7 @@ var CodeTooltip = class {
|
|
|
10000
10355
|
}
|
|
10001
10356
|
const existingScript = document.querySelector(`script[src="${scriptSrc}"]`);
|
|
10002
10357
|
if (existingScript) {
|
|
10003
|
-
this._prismScript =
|
|
10358
|
+
this._prismScript = _w.Prism ? null : existingScript;
|
|
10004
10359
|
return;
|
|
10005
10360
|
}
|
|
10006
10361
|
const script = document.createElement("script");
|
|
@@ -10020,10 +10375,11 @@ var CodeTooltip = class {
|
|
|
10020
10375
|
* @param {Function} cb – called once the grammar is ready
|
|
10021
10376
|
*/
|
|
10022
10377
|
_loadPrismComponent(lang, cb) {
|
|
10378
|
+
const _w = globalThis;
|
|
10023
10379
|
const src = `${this.context.options.codeHighlightCDN}/components/prism-${lang}.min.js`;
|
|
10024
10380
|
if (document.querySelector(`script[src="${src}"]`)) {
|
|
10025
10381
|
const poll = setInterval(() => {
|
|
10026
|
-
if (
|
|
10382
|
+
if (_w.Prism?.languages[lang]) {
|
|
10027
10383
|
clearInterval(poll);
|
|
10028
10384
|
cb();
|
|
10029
10385
|
}
|
|
@@ -10054,7 +10410,7 @@ var CodeTooltip = class {
|
|
|
10054
10410
|
const pre = this._activePre;
|
|
10055
10411
|
if (!pre) return;
|
|
10056
10412
|
this._hide();
|
|
10057
|
-
|
|
10413
|
+
pre.remove();
|
|
10058
10414
|
this.context.invoke("editor.afterCommand");
|
|
10059
10415
|
}
|
|
10060
10416
|
};
|
|
@@ -12409,7 +12765,7 @@ var EmojiDialog = class {
|
|
|
12409
12765
|
destroy() {
|
|
12410
12766
|
this._disposers.forEach((d) => d());
|
|
12411
12767
|
this._disposers = [];
|
|
12412
|
-
if (this._dialog && this._dialog.parentNode) this._dialog.
|
|
12768
|
+
if (this._dialog && this._dialog.parentNode) this._dialog.remove();
|
|
12413
12769
|
this._dialog = null;
|
|
12414
12770
|
}
|
|
12415
12771
|
show() {
|
|
@@ -12436,15 +12792,19 @@ var EmojiDialog = class {
|
|
|
12436
12792
|
});
|
|
12437
12793
|
const box = createElement("div", { class: "an-dialog-box an-emoji-box" });
|
|
12438
12794
|
const titleRow = createElement("div", { class: "an-icon-title-row" });
|
|
12795
|
+
const titleGroup = createElement("div", { class: "an-dialog-title-group" });
|
|
12796
|
+
const iconEl = createElement("span", { class: "an-dialog-icon an-dialog-icon--sm" });
|
|
12797
|
+
iconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M8 13s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/></svg>`;
|
|
12439
12798
|
const title = createElement("h3", { class: "an-dialog-title" });
|
|
12440
12799
|
title.textContent = L.title;
|
|
12800
|
+
titleGroup.append(iconEl, title);
|
|
12441
12801
|
const closeBtn = createElement("button", {
|
|
12442
12802
|
type: "button",
|
|
12443
12803
|
class: "an-icon-close",
|
|
12444
12804
|
"aria-label": L.close
|
|
12445
12805
|
});
|
|
12446
12806
|
closeBtn.innerHTML = "×";
|
|
12447
|
-
titleRow.append(
|
|
12807
|
+
titleRow.append(titleGroup, closeBtn);
|
|
12448
12808
|
const searchInput = createElement("input", {
|
|
12449
12809
|
type: "search",
|
|
12450
12810
|
class: "an-input an-icon-search",
|
|
@@ -12466,7 +12826,7 @@ var EmojiDialog = class {
|
|
|
12466
12826
|
class: "an-icon-cat",
|
|
12467
12827
|
"data-cat": id
|
|
12468
12828
|
});
|
|
12469
|
-
tab.textContent = L.categories
|
|
12829
|
+
tab.textContent = L.categories?.[id] || label;
|
|
12470
12830
|
catBar.appendChild(tab);
|
|
12471
12831
|
});
|
|
12472
12832
|
this._catBar = catBar;
|
|
@@ -12493,6 +12853,7 @@ var EmojiDialog = class {
|
|
|
12493
12853
|
btnRow.appendChild(cancelBtn);
|
|
12494
12854
|
box.append(titleRow, searchInput, catBar, grid, btnRow);
|
|
12495
12855
|
overlay.appendChild(box);
|
|
12856
|
+
makeDraggable(titleRow, box);
|
|
12496
12857
|
const d1 = on(closeBtn, "click", () => this._close());
|
|
12497
12858
|
const d2 = on(cancelBtn, "click", () => this._close());
|
|
12498
12859
|
const d3 = on(overlay, "click", (e) => {
|
|
@@ -12500,7 +12861,7 @@ var EmojiDialog = class {
|
|
|
12500
12861
|
});
|
|
12501
12862
|
const d4 = on(searchInput, "input", () => this._filterEmojis(searchInput.value, this._activeCat));
|
|
12502
12863
|
const d5 = on(catBar, "click", (e) => {
|
|
12503
|
-
const tab = e.target
|
|
12864
|
+
const tab = e.target?.closest("[data-cat]");
|
|
12504
12865
|
if (tab) {
|
|
12505
12866
|
this._activeCat = tab.dataset.cat;
|
|
12506
12867
|
this._updateCatTabs();
|
|
@@ -12508,7 +12869,7 @@ var EmojiDialog = class {
|
|
|
12508
12869
|
}
|
|
12509
12870
|
});
|
|
12510
12871
|
const d6 = on(grid, "click", (e) => {
|
|
12511
|
-
const cell = e.target
|
|
12872
|
+
const cell = e.target?.closest(".an-emoji-cell");
|
|
12512
12873
|
if (cell) this._onEmojiClick(cell.dataset.char);
|
|
12513
12874
|
});
|
|
12514
12875
|
this._disposers.push(d1, d2, d3, d4, d5, d6);
|
|
@@ -12516,17 +12877,22 @@ var EmojiDialog = class {
|
|
|
12516
12877
|
}
|
|
12517
12878
|
_updateCatTabs() {
|
|
12518
12879
|
this._catBar.querySelectorAll(".an-icon-cat").forEach((tab) => {
|
|
12519
|
-
tab.classList.toggle(
|
|
12880
|
+
tab.classList.toggle(
|
|
12881
|
+
"active",
|
|
12882
|
+
/** @type {HTMLElement} */
|
|
12883
|
+
tab.dataset.cat === this._activeCat
|
|
12884
|
+
);
|
|
12520
12885
|
});
|
|
12521
12886
|
}
|
|
12522
12887
|
_filterEmojis(query, cat) {
|
|
12523
12888
|
const q = (query || "").trim().toLowerCase();
|
|
12524
12889
|
let count = 0;
|
|
12525
12890
|
this._grid.querySelectorAll(".an-emoji-cell").forEach((cell) => {
|
|
12526
|
-
const
|
|
12527
|
-
const
|
|
12891
|
+
const hCell = cell;
|
|
12892
|
+
const matchCat = !cat || cat === "all" || hCell.dataset.cat === cat;
|
|
12893
|
+
const matchQuery = !q || hCell.dataset.keywords.includes(q) || hCell.dataset.char === q;
|
|
12528
12894
|
const visible = matchCat && matchQuery;
|
|
12529
|
-
|
|
12895
|
+
hCell.style.display = visible ? "" : "none";
|
|
12530
12896
|
if (visible) count++;
|
|
12531
12897
|
});
|
|
12532
12898
|
let empty = this._grid.querySelector(".an-icon-empty");
|
|
@@ -12535,13 +12901,13 @@ var EmojiDialog = class {
|
|
|
12535
12901
|
empty.textContent = "No emojis found";
|
|
12536
12902
|
this._grid.appendChild(empty);
|
|
12537
12903
|
}
|
|
12538
|
-
empty.style.display = count > 0 ? "none" : "";
|
|
12904
|
+
/** @type {HTMLElement} */ empty.style.display = count > 0 ? "none" : "";
|
|
12539
12905
|
}
|
|
12540
12906
|
_onEmojiClick(char) {
|
|
12541
12907
|
const savedRange = this._savedRange;
|
|
12542
12908
|
const editable = this.context.layoutInfo.editable;
|
|
12543
12909
|
if (savedRange) savedRange.select();
|
|
12544
|
-
const sel =
|
|
12910
|
+
const sel = globalThis.getSelection();
|
|
12545
12911
|
let range = sel && sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
|
|
12546
12912
|
if (!range) {
|
|
12547
12913
|
range = document.createRange();
|
|
@@ -12549,9 +12915,9 @@ var EmojiDialog = class {
|
|
|
12549
12915
|
range.collapse(false);
|
|
12550
12916
|
}
|
|
12551
12917
|
const _sc = range.startContainer;
|
|
12552
|
-
const _tdAnchor = (_sc.nodeType === 1 ? _sc : _sc.parentElement)?.closest
|
|
12918
|
+
const _tdAnchor = (_sc.nodeType === 1 ? _sc : _sc.parentElement)?.closest("td, th");
|
|
12553
12919
|
range.deleteContents();
|
|
12554
|
-
if (_tdAnchor
|
|
12920
|
+
if (_tdAnchor?.isConnected && !_tdAnchor.contains(range.startContainer)) {
|
|
12555
12921
|
range.setStart(_tdAnchor, 0);
|
|
12556
12922
|
range.collapse(true);
|
|
12557
12923
|
}
|
|
@@ -12571,7 +12937,7 @@ var EmojiDialog = class {
|
|
|
12571
12937
|
if (this._dialog) {
|
|
12572
12938
|
this._dialog.style.display = "flex";
|
|
12573
12939
|
this._removeTrap = trapFocus(this._dialog, () => this._close());
|
|
12574
|
-
setTimeout(() => this._searchInput
|
|
12940
|
+
setTimeout(() => this._searchInput?.focus(), 50);
|
|
12575
12941
|
}
|
|
12576
12942
|
}
|
|
12577
12943
|
_close() {
|
|
@@ -12878,7 +13244,7 @@ var IconDialog = class {
|
|
|
12878
13244
|
destroy() {
|
|
12879
13245
|
this._disposers.forEach((d) => d());
|
|
12880
13246
|
this._disposers = [];
|
|
12881
|
-
|
|
13247
|
+
this._dialog?.remove();
|
|
12882
13248
|
this._dialog = null;
|
|
12883
13249
|
}
|
|
12884
13250
|
show() {
|
|
@@ -12909,15 +13275,19 @@ var IconDialog = class {
|
|
|
12909
13275
|
});
|
|
12910
13276
|
const box = createElement("div", { class: "an-dialog-box an-icon-box" });
|
|
12911
13277
|
const titleRow = createElement("div", { class: "an-icon-title-row" });
|
|
13278
|
+
const titleGroup = createElement("div", { class: "an-dialog-title-group" });
|
|
13279
|
+
const iconEl = createElement("span", { class: "an-dialog-icon an-dialog-icon--sm" });
|
|
13280
|
+
iconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>`;
|
|
12912
13281
|
const title = createElement("h3", { class: "an-dialog-title" });
|
|
12913
13282
|
title.textContent = L.title;
|
|
13283
|
+
titleGroup.append(iconEl, title);
|
|
12914
13284
|
const closeBtn = createElement("button", {
|
|
12915
13285
|
type: "button",
|
|
12916
13286
|
class: "an-icon-close",
|
|
12917
13287
|
"aria-label": L.close
|
|
12918
13288
|
});
|
|
12919
13289
|
closeBtn.innerHTML = "×";
|
|
12920
|
-
titleRow.append(
|
|
13290
|
+
titleRow.append(titleGroup, closeBtn);
|
|
12921
13291
|
const searchInput = createElement("input", {
|
|
12922
13292
|
type: "search",
|
|
12923
13293
|
class: "an-input an-icon-search",
|
|
@@ -12939,7 +13309,7 @@ var IconDialog = class {
|
|
|
12939
13309
|
class: "an-icon-cat",
|
|
12940
13310
|
"data-cat": id
|
|
12941
13311
|
});
|
|
12942
|
-
tab.textContent = L.categories
|
|
13312
|
+
tab.textContent = L.categories?.[id] || label;
|
|
12943
13313
|
catBar.appendChild(tab);
|
|
12944
13314
|
});
|
|
12945
13315
|
this._catBar = catBar;
|
|
@@ -13032,6 +13402,7 @@ var IconDialog = class {
|
|
|
13032
13402
|
this._insertBtn = insertBtn;
|
|
13033
13403
|
box.append(titleRow, searchInput, catBar, grid, optRow, preview, btnRow);
|
|
13034
13404
|
overlay.appendChild(box);
|
|
13405
|
+
makeDraggable(titleRow, box);
|
|
13035
13406
|
const d1 = on(closeBtn, "click", () => this._close());
|
|
13036
13407
|
const d2 = on(cancelBtn, "click", () => this._close());
|
|
13037
13408
|
const d3 = on(insertBtn, "click", () => this._onInsert());
|
|
@@ -13040,7 +13411,7 @@ var IconDialog = class {
|
|
|
13040
13411
|
});
|
|
13041
13412
|
const d5 = on(searchInput, "input", () => this._filterIcons(searchInput.value, this._activeCat));
|
|
13042
13413
|
const d6 = on(catBar, "click", (e) => {
|
|
13043
|
-
const tab = e.target
|
|
13414
|
+
const tab = e.target?.closest("[data-cat]");
|
|
13044
13415
|
if (tab) {
|
|
13045
13416
|
this._activeCat = tab.dataset.cat;
|
|
13046
13417
|
this._updateCatTabs();
|
|
@@ -13048,7 +13419,7 @@ var IconDialog = class {
|
|
|
13048
13419
|
}
|
|
13049
13420
|
});
|
|
13050
13421
|
const d7 = on(grid, "click", (e) => {
|
|
13051
|
-
const cell = e.target
|
|
13422
|
+
const cell = e.target?.closest(".an-icon-cell");
|
|
13052
13423
|
if (cell) this._selectIcon(cell.dataset.name);
|
|
13053
13424
|
});
|
|
13054
13425
|
const d8 = on(styleSelect, "change", () => this._updatePreview(this._selectedIcon));
|
|
@@ -13060,19 +13431,24 @@ var IconDialog = class {
|
|
|
13060
13431
|
}
|
|
13061
13432
|
_updateCatTabs() {
|
|
13062
13433
|
this._catBar.querySelectorAll(".an-icon-cat").forEach((tab) => {
|
|
13063
|
-
tab.classList.toggle(
|
|
13434
|
+
tab.classList.toggle(
|
|
13435
|
+
"active",
|
|
13436
|
+
/** @type {HTMLElement} */
|
|
13437
|
+
tab.dataset.cat === this._activeCat
|
|
13438
|
+
);
|
|
13064
13439
|
});
|
|
13065
13440
|
}
|
|
13066
13441
|
_filterIcons(query, cat) {
|
|
13067
13442
|
const q = (query || "").trim().toLowerCase();
|
|
13068
13443
|
let visibleCount = 0;
|
|
13069
13444
|
this._grid.querySelectorAll(".an-icon-cell").forEach((cell) => {
|
|
13070
|
-
const
|
|
13071
|
-
const
|
|
13445
|
+
const hCell = cell;
|
|
13446
|
+
const name = hCell.dataset.name;
|
|
13447
|
+
const cellCat = hCell.dataset.cat;
|
|
13072
13448
|
const matchesCat = !cat || cat === "all" || cellCat === cat;
|
|
13073
13449
|
const matchesQuery = !q || name.includes(q);
|
|
13074
13450
|
const visible = matchesCat && matchesQuery;
|
|
13075
|
-
|
|
13451
|
+
hCell.style.display = visible ? "" : "none";
|
|
13076
13452
|
if (visible) visibleCount++;
|
|
13077
13453
|
});
|
|
13078
13454
|
let empty = this._grid.querySelector(".an-icon-empty");
|
|
@@ -13081,12 +13457,16 @@ var IconDialog = class {
|
|
|
13081
13457
|
empty.textContent = "No icons found";
|
|
13082
13458
|
this._grid.appendChild(empty);
|
|
13083
13459
|
}
|
|
13084
|
-
empty.style.display = visibleCount > 0 ? "none" : "";
|
|
13460
|
+
/** @type {HTMLElement} */ empty.style.display = visibleCount > 0 ? "none" : "";
|
|
13085
13461
|
}
|
|
13086
13462
|
_selectIcon(name) {
|
|
13087
13463
|
this._selectedIcon = name;
|
|
13088
13464
|
this._grid.querySelectorAll(".an-icon-cell").forEach((cell) => {
|
|
13089
|
-
cell.classList.toggle(
|
|
13465
|
+
cell.classList.toggle(
|
|
13466
|
+
"active",
|
|
13467
|
+
/** @type {HTMLElement} */
|
|
13468
|
+
cell.dataset.name === name
|
|
13469
|
+
);
|
|
13090
13470
|
});
|
|
13091
13471
|
this._insertBtn.removeAttribute("disabled");
|
|
13092
13472
|
this._updatePreview(name);
|
|
@@ -13097,17 +13477,17 @@ var IconDialog = class {
|
|
|
13097
13477
|
this._preview.innerHTML = "<span class=\"an-icon-preview-hint\">Select an icon</span>";
|
|
13098
13478
|
return;
|
|
13099
13479
|
}
|
|
13100
|
-
const cls = this._styleSelect
|
|
13101
|
-
const size = this._sizeSelect
|
|
13102
|
-
const color =
|
|
13480
|
+
const cls = this._styleSelect?.value || "fa-solid";
|
|
13481
|
+
const size = this._sizeSelect?.value || "1em";
|
|
13482
|
+
const color = this._useColorCb?.checked ?? false ? this._colorInput?.value ?? "" : "";
|
|
13103
13483
|
const styleAttr = [size ? `font-size:${size}` : "", color ? `color:${color}` : ""].filter(Boolean).join(";");
|
|
13104
13484
|
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>`;
|
|
13105
13485
|
}
|
|
13106
13486
|
_onInsert() {
|
|
13107
13487
|
if (!this._selectedIcon) return;
|
|
13108
|
-
const cls = this._styleSelect
|
|
13109
|
-
const size = this._sizeSelect
|
|
13110
|
-
const color =
|
|
13488
|
+
const cls = this._styleSelect?.value || "fa-solid";
|
|
13489
|
+
const size = this._sizeSelect?.value || "";
|
|
13490
|
+
const color = this._useColorCb?.checked ?? false ? this._colorInput?.value ?? "" : "";
|
|
13111
13491
|
const styleParts = [size ? `font-size:${size}` : "", color ? `color:${color}` : ""].filter(Boolean);
|
|
13112
13492
|
const iconEl = document.createElement("i");
|
|
13113
13493
|
iconEl.className = `${cls} fa-${this._selectedIcon}`;
|
|
@@ -13117,15 +13497,15 @@ var IconDialog = class {
|
|
|
13117
13497
|
const savedRange = this._savedRange;
|
|
13118
13498
|
const editable = this.context.layoutInfo.editable;
|
|
13119
13499
|
if (savedRange) savedRange.select();
|
|
13120
|
-
const sel =
|
|
13121
|
-
let range = sel
|
|
13500
|
+
const sel = globalThis.getSelection();
|
|
13501
|
+
let range = (sel?.rangeCount ?? 0) > 0 ? sel.getRangeAt(0) : null;
|
|
13122
13502
|
if (!range) {
|
|
13123
13503
|
range = document.createRange();
|
|
13124
13504
|
range.selectNodeContents(editable);
|
|
13125
13505
|
range.collapse(false);
|
|
13126
13506
|
}
|
|
13127
13507
|
const _sc = range.startContainer;
|
|
13128
|
-
const _tdAnchor = (_sc.nodeType === 1 ? _sc : _sc.parentElement)?.closest
|
|
13508
|
+
const _tdAnchor = (_sc.nodeType === 1 ? _sc : _sc.parentElement)?.closest("td, th");
|
|
13129
13509
|
range.deleteContents();
|
|
13130
13510
|
if (_tdAnchor && _tdAnchor.isConnected && !_tdAnchor.contains(range.startContainer)) {
|
|
13131
13511
|
range.setStart(_tdAnchor, 0);
|
|
@@ -13157,7 +13537,7 @@ var IconDialog = class {
|
|
|
13157
13537
|
if (this._dialog) {
|
|
13158
13538
|
this._dialog.style.display = "flex";
|
|
13159
13539
|
this._removeTrap = trapFocus(this._dialog, () => this._close());
|
|
13160
|
-
setTimeout(() => this._searchInput
|
|
13540
|
+
setTimeout(() => this._searchInput?.focus(), 50);
|
|
13161
13541
|
}
|
|
13162
13542
|
}
|
|
13163
13543
|
_close() {
|
|
@@ -13258,7 +13638,7 @@ var defaultItems = [
|
|
|
13258
13638
|
icon: ICONS.paste,
|
|
13259
13639
|
action: (ctx) => {
|
|
13260
13640
|
if (!navigator.clipboard) return;
|
|
13261
|
-
const editable = ctx.layoutInfo
|
|
13641
|
+
const editable = ctx.layoutInfo?.editable;
|
|
13262
13642
|
if (!editable) return;
|
|
13263
13643
|
const doInsert = (html, text) => {
|
|
13264
13644
|
editable.focus();
|
|
@@ -13383,29 +13763,29 @@ var ContextMenu = class {
|
|
|
13383
13763
|
this.el.style.display = "none";
|
|
13384
13764
|
document.body.appendChild(this.el);
|
|
13385
13765
|
this._renderItems(this._items);
|
|
13386
|
-
const editable = this.context.layoutInfo
|
|
13766
|
+
const editable = this.context.layoutInfo?.editable;
|
|
13387
13767
|
if (editable) this._disposers.push(on(editable, "contextmenu", (e) => this._onContextMenu(e)));
|
|
13388
13768
|
this._disposers.push(on(document, "click", (e) => this._maybeHide(e)));
|
|
13389
13769
|
this._disposers.push(on(document, "keydown", (e) => {
|
|
13390
13770
|
if (e.key === "Escape") this.hide();
|
|
13391
13771
|
}));
|
|
13392
|
-
this._disposers.push(on(
|
|
13772
|
+
this._disposers.push(on(globalThis, "scroll", () => this.hide(), { passive: true }));
|
|
13393
13773
|
return this;
|
|
13394
13774
|
}
|
|
13395
13775
|
destroy() {
|
|
13396
13776
|
this._menuDisposers.forEach((d) => {
|
|
13397
13777
|
try {
|
|
13398
13778
|
d();
|
|
13399
|
-
} catch (
|
|
13779
|
+
} catch (_e) {}
|
|
13400
13780
|
});
|
|
13401
13781
|
this._menuDisposers = [];
|
|
13402
13782
|
this._disposers.forEach((d) => {
|
|
13403
13783
|
try {
|
|
13404
13784
|
d();
|
|
13405
|
-
} catch (
|
|
13785
|
+
} catch (_e) {}
|
|
13406
13786
|
});
|
|
13407
13787
|
this._disposers = [];
|
|
13408
|
-
if (this.el
|
|
13788
|
+
if (this.el) this.el.remove();
|
|
13409
13789
|
this.el = null;
|
|
13410
13790
|
}
|
|
13411
13791
|
_renderItems(items) {
|
|
@@ -13433,8 +13813,8 @@ var ContextMenu = class {
|
|
|
13433
13813
|
backBtn.appendChild(createElement("span", { class: "an-context-label" }, [backLabel]));
|
|
13434
13814
|
const off = on(backBtn, "click", (e) => {
|
|
13435
13815
|
e.stopPropagation();
|
|
13436
|
-
const curLeft = parseFloat(this.el.style.left);
|
|
13437
|
-
const curTop = parseFloat(this.el.style.top);
|
|
13816
|
+
const curLeft = Number.parseFloat(this.el.style.left);
|
|
13817
|
+
const curTop = Number.parseFloat(this.el.style.top);
|
|
13438
13818
|
this._renderItems(it.navigate());
|
|
13439
13819
|
this._reposition(curLeft, curTop);
|
|
13440
13820
|
});
|
|
@@ -13477,8 +13857,8 @@ var ContextMenu = class {
|
|
|
13477
13857
|
btn.appendChild(chevron);
|
|
13478
13858
|
const off = on(btn, "click", (e) => {
|
|
13479
13859
|
e.stopPropagation();
|
|
13480
|
-
const curLeft = parseFloat(this.el.style.left);
|
|
13481
|
-
const curTop = parseFloat(this.el.style.top);
|
|
13860
|
+
const curLeft = Number.parseFloat(this.el.style.left);
|
|
13861
|
+
const curTop = Number.parseFloat(this.el.style.top);
|
|
13482
13862
|
this._renderItems(it.navigate());
|
|
13483
13863
|
this._reposition(curLeft, curTop);
|
|
13484
13864
|
});
|
|
@@ -13593,20 +13973,20 @@ var ContextMenu = class {
|
|
|
13593
13973
|
});
|
|
13594
13974
|
this._menuDisposers.push(offHeader);
|
|
13595
13975
|
const offMove = on(gridEl, "mousemove", (e) => {
|
|
13596
|
-
const cell = e.target
|
|
13976
|
+
const cell = e.target?.closest("[data-row]");
|
|
13597
13977
|
if (!cell) return;
|
|
13598
13978
|
setHighlight(+cell.dataset.row, +cell.dataset.col);
|
|
13599
13979
|
});
|
|
13600
13980
|
const offLeave = on(gridEl, "mouseleave", () => setHighlight(0, 0));
|
|
13601
13981
|
const offClick = on(gridEl, "click", (e) => {
|
|
13602
|
-
const cell = e.target
|
|
13982
|
+
const cell = e.target?.closest("[data-row]");
|
|
13603
13983
|
if (!cell) return;
|
|
13604
13984
|
const rows = +cell.dataset.row;
|
|
13605
13985
|
const cols = +cell.dataset.col;
|
|
13606
|
-
const editable = this.context.layoutInfo
|
|
13986
|
+
const editable = this.context.layoutInfo?.editable;
|
|
13607
13987
|
if (editable && this._savedRange) {
|
|
13608
13988
|
editable.focus();
|
|
13609
|
-
const sel =
|
|
13989
|
+
const sel = globalThis.getSelection();
|
|
13610
13990
|
sel.removeAllRanges();
|
|
13611
13991
|
sel.addRange(this._savedRange.cloneRange());
|
|
13612
13992
|
}
|
|
@@ -13624,7 +14004,7 @@ var ContextMenu = class {
|
|
|
13624
14004
|
class: "an-context-item",
|
|
13625
14005
|
"data-name": it.name || ""
|
|
13626
14006
|
});
|
|
13627
|
-
if (typeof it.disabled === "function" ? it.disabled(this.context) : !!it.disabled) btn.disabled = true;
|
|
14007
|
+
if (typeof it.disabled === "function" ? it.disabled(this.context) : !!it.disabled) /** @type {HTMLButtonElement} */ btn.disabled = true;
|
|
13628
14008
|
if (it.icon) {
|
|
13629
14009
|
const iconSpan = createElement("span", {
|
|
13630
14010
|
class: "an-context-icon",
|
|
@@ -13648,15 +14028,15 @@ var ContextMenu = class {
|
|
|
13648
14028
|
});
|
|
13649
14029
|
}
|
|
13650
14030
|
_onContextMenu(event) {
|
|
13651
|
-
const editable = this.context.layoutInfo
|
|
14031
|
+
const editable = this.context.layoutInfo?.editable;
|
|
13652
14032
|
if (!editable) return;
|
|
13653
14033
|
if (!editable.contains(event.target)) return;
|
|
13654
14034
|
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
13655
14035
|
event.preventDefault();
|
|
13656
|
-
const winSel =
|
|
14036
|
+
const winSel = globalThis.getSelection();
|
|
13657
14037
|
this._savedRange = winSel && winSel.rangeCount > 0 ? winSel.getRangeAt(0).cloneRange() : null;
|
|
13658
14038
|
this._renderItems(this._items);
|
|
13659
|
-
|
|
14039
|
+
const openX = event.clientX;
|
|
13660
14040
|
let openY = event.clientY;
|
|
13661
14041
|
if (this._savedRange && !this._savedRange.collapsed) try {
|
|
13662
14042
|
const selRect = this._savedRange.getBoundingClientRect();
|
|
@@ -13685,9 +14065,9 @@ var ContextMenu = class {
|
|
|
13685
14065
|
const h = this.el.offsetHeight;
|
|
13686
14066
|
let left = rx;
|
|
13687
14067
|
let top = ry;
|
|
13688
|
-
if (left + w >
|
|
14068
|
+
if (left + w > globalThis.innerWidth - 8) left = globalThis.innerWidth - w - 8;
|
|
13689
14069
|
if (left < 8) left = 8;
|
|
13690
|
-
if (top + h >
|
|
14070
|
+
if (top + h > globalThis.innerHeight - 8) top = globalThis.innerHeight - h - 8;
|
|
13691
14071
|
if (top < 8) top = 8;
|
|
13692
14072
|
this.el.style.left = `${left}px`;
|
|
13693
14073
|
this.el.style.top = `${top}px`;
|
|
@@ -13708,17 +14088,17 @@ var ContextMenu = class {
|
|
|
13708
14088
|
let node = range.startContainer;
|
|
13709
14089
|
if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
|
|
13710
14090
|
if (!node) return type === "foreColor" ? "#000000" : "transparent";
|
|
13711
|
-
const cs =
|
|
14091
|
+
const cs = globalThis.getComputedStyle(node);
|
|
13712
14092
|
if (type === "foreColor") return cs.color || "#000000";
|
|
13713
14093
|
const bg = cs.backgroundColor;
|
|
13714
14094
|
return !bg || bg === "rgba(0, 0, 0, 0)" || bg === "transparent" ? "transparent" : bg;
|
|
13715
14095
|
}
|
|
13716
14096
|
/** Restore selection, apply a color command, then hide the menu. */
|
|
13717
14097
|
_applyColor(type, color) {
|
|
13718
|
-
const editable = this.context.layoutInfo
|
|
14098
|
+
const editable = this.context.layoutInfo?.editable;
|
|
13719
14099
|
if (!editable || !this._savedRange) return;
|
|
13720
14100
|
editable.focus();
|
|
13721
|
-
const sel =
|
|
14101
|
+
const sel = globalThis.getSelection();
|
|
13722
14102
|
sel.removeAllRanges();
|
|
13723
14103
|
sel.addRange(this._savedRange.cloneRange());
|
|
13724
14104
|
document.execCommand(type, false, color);
|
|
@@ -13733,15 +14113,15 @@ var ContextMenu = class {
|
|
|
13733
14113
|
copyFormat() {
|
|
13734
14114
|
const range = this._savedRange;
|
|
13735
14115
|
if (!range) return;
|
|
13736
|
-
const editable = this.context.layoutInfo
|
|
14116
|
+
const editable = this.context.layoutInfo?.editable;
|
|
13737
14117
|
let node = range.startContainer;
|
|
13738
14118
|
if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
|
|
13739
14119
|
if (!node || !editable || !editable.contains(node)) return;
|
|
13740
|
-
const cs =
|
|
14120
|
+
const cs = globalThis.getComputedStyle(node);
|
|
13741
14121
|
const explicitFontFamily = this._findExplicitStyle(node, editable, "fontFamily");
|
|
13742
14122
|
const explicitFontSize = this._findExplicitStyle(node, editable, "fontSize");
|
|
13743
14123
|
this._copiedFormat = {
|
|
13744
|
-
bold: parseInt(cs.fontWeight, 10) >= 700,
|
|
14124
|
+
bold: Number.parseInt(cs.fontWeight, 10) >= 700,
|
|
13745
14125
|
italic: cs.fontStyle === "italic" || cs.fontStyle === "oblique",
|
|
13746
14126
|
underline: (cs.textDecorationLine || "").includes("underline"),
|
|
13747
14127
|
strikethrough: (cs.textDecorationLine || "").includes("line-through"),
|
|
@@ -13772,10 +14152,10 @@ var ContextMenu = class {
|
|
|
13772
14152
|
pasteFormat() {
|
|
13773
14153
|
if (!this._copiedFormat || !this._savedRange) return;
|
|
13774
14154
|
const fmt = this._copiedFormat;
|
|
13775
|
-
const editable = this.context.layoutInfo
|
|
14155
|
+
const editable = this.context.layoutInfo?.editable;
|
|
13776
14156
|
if (!editable) return;
|
|
13777
14157
|
editable.focus();
|
|
13778
|
-
const sel =
|
|
14158
|
+
const sel = globalThis.getSelection();
|
|
13779
14159
|
sel.removeAllRanges();
|
|
13780
14160
|
sel.addRange(this._savedRange.cloneRange());
|
|
13781
14161
|
document.execCommand("removeFormat");
|
|
@@ -13792,14 +14172,14 @@ var ContextMenu = class {
|
|
|
13792
14172
|
const preExisting = new Set(editable.querySelectorAll("font[size=\"7\"]"));
|
|
13793
14173
|
document.execCommand("fontSize", false, "7");
|
|
13794
14174
|
editable.querySelectorAll("font[size=\"7\"]").forEach((el) => {
|
|
13795
|
-
if (!preExisting.has(el)) el.
|
|
14175
|
+
if (!preExisting.has(el)) /** @type {HTMLElement} */ el.dataset.anTmp = marker;
|
|
13796
14176
|
});
|
|
13797
14177
|
editable.querySelectorAll(`[data-an-tmp="${marker}"]`).forEach((el) => {
|
|
13798
14178
|
const span = document.createElement("span");
|
|
13799
14179
|
span.style.fontSize = fmt.fontSize;
|
|
13800
14180
|
el.parentNode.insertBefore(span, el);
|
|
13801
14181
|
while (el.firstChild) span.appendChild(el.firstChild);
|
|
13802
|
-
el.
|
|
14182
|
+
el.remove();
|
|
13803
14183
|
});
|
|
13804
14184
|
}
|
|
13805
14185
|
this.context.invoke("editor.afterCommand");
|
|
@@ -13807,10 +14187,10 @@ var ContextMenu = class {
|
|
|
13807
14187
|
/** Strip all inline formatting from the saved selection. */
|
|
13808
14188
|
removeFormat() {
|
|
13809
14189
|
if (!this._savedRange) return;
|
|
13810
|
-
const editable = this.context.layoutInfo
|
|
14190
|
+
const editable = this.context.layoutInfo?.editable;
|
|
13811
14191
|
if (!editable) return;
|
|
13812
14192
|
editable.focus();
|
|
13813
|
-
const sel =
|
|
14193
|
+
const sel = globalThis.getSelection();
|
|
13814
14194
|
sel.removeAllRanges();
|
|
13815
14195
|
sel.addRange(this._savedRange.cloneRange());
|
|
13816
14196
|
document.execCommand("removeFormat");
|
|
@@ -13822,7 +14202,7 @@ var ContextMenu = class {
|
|
|
13822
14202
|
while (el = iter.nextNode()) {
|
|
13823
14203
|
if (!editable.contains(el) || el === editable) continue;
|
|
13824
14204
|
try {
|
|
13825
|
-
if (range.intersectsNode(el)) el.removeAttribute("style");
|
|
14205
|
+
if (range.intersectsNode(el)) /** @type {Element} */ el.removeAttribute("style");
|
|
13826
14206
|
} catch {}
|
|
13827
14207
|
}
|
|
13828
14208
|
this.context.invoke("editor.afterCommand");
|
|
@@ -13924,14 +14304,14 @@ var ShortcutsDialog = class {
|
|
|
13924
14304
|
destroy() {
|
|
13925
14305
|
this._disposers.forEach((d) => d());
|
|
13926
14306
|
this._disposers = [];
|
|
13927
|
-
|
|
14307
|
+
this._dialog?.remove();
|
|
13928
14308
|
this._dialog = null;
|
|
13929
14309
|
}
|
|
13930
14310
|
show() {
|
|
13931
14311
|
if (this._dialog) {
|
|
13932
14312
|
this._dialog.style.display = "flex";
|
|
13933
14313
|
this._removeTrap = trapFocus(this._dialog, () => this._close());
|
|
13934
|
-
setTimeout(() => this._closeBtn
|
|
14314
|
+
setTimeout(() => this._closeBtn?.focus(), 50);
|
|
13935
14315
|
}
|
|
13936
14316
|
}
|
|
13937
14317
|
_close() {
|
|
@@ -14037,7 +14417,7 @@ var FindReplace = class {
|
|
|
14037
14417
|
this._clearHighlights();
|
|
14038
14418
|
this._disposers.forEach((d) => d());
|
|
14039
14419
|
this._disposers = [];
|
|
14040
|
-
if (this._dialog && this._dialog.parentNode) this._dialog.
|
|
14420
|
+
if (this._dialog && this._dialog.parentNode) this._dialog.remove();
|
|
14041
14421
|
this._dialog = null;
|
|
14042
14422
|
}
|
|
14043
14423
|
/**
|
|
@@ -14084,8 +14464,8 @@ var FindReplace = class {
|
|
|
14084
14464
|
const replaceActions = this._dialog.querySelector(".an-fr-replace-actions");
|
|
14085
14465
|
const title = this._dialog.querySelector(".an-dialog-title");
|
|
14086
14466
|
const isReplace = this._mode === "replace";
|
|
14087
|
-
if (replaceRow) replaceRow.style.display = isReplace ? "" : "none";
|
|
14088
|
-
if (replaceActions) replaceActions.style.display = isReplace ? "" : "none";
|
|
14467
|
+
if (replaceRow) /** @type {HTMLElement} */ replaceRow.style.display = isReplace ? "" : "none";
|
|
14468
|
+
if (replaceActions) /** @type {HTMLElement} */ replaceActions.style.display = isReplace ? "" : "none";
|
|
14089
14469
|
if (title) title.textContent = isReplace ? this.context.locale.findReplace.findReplaceTitle : this.context.locale.findReplace.findTitle;
|
|
14090
14470
|
}
|
|
14091
14471
|
_buildDialog() {
|
|
@@ -14096,106 +14476,123 @@ var FindReplace = class {
|
|
|
14096
14476
|
"aria-modal": "true",
|
|
14097
14477
|
"aria-label": L.findReplaceTitle
|
|
14098
14478
|
});
|
|
14099
|
-
const box = createElement("div", { class: "an-dialog-box" });
|
|
14100
|
-
const
|
|
14479
|
+
const box = createElement("div", { class: "an-dialog-box an-fr-box" });
|
|
14480
|
+
const header = createElement("div", { class: "an-fr-header" });
|
|
14481
|
+
const titleGroup = createElement("div", { class: "an-dialog-title-group" });
|
|
14482
|
+
const iconEl = createElement("span", { class: "an-dialog-icon an-dialog-icon--sm" });
|
|
14483
|
+
iconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>`;
|
|
14101
14484
|
const title = createElement("h3", { class: "an-dialog-title" });
|
|
14102
14485
|
title.textContent = L.findTitle;
|
|
14486
|
+
titleGroup.append(iconEl, title);
|
|
14103
14487
|
const closeBtn = createElement("button", {
|
|
14104
14488
|
type: "button",
|
|
14105
14489
|
class: "an-icon-close",
|
|
14106
|
-
|
|
14490
|
+
title: L.close,
|
|
14491
|
+
"aria-label": L.close
|
|
14107
14492
|
});
|
|
14108
|
-
closeBtn.
|
|
14493
|
+
closeBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>`;
|
|
14109
14494
|
this._closeBtn = closeBtn;
|
|
14110
|
-
|
|
14111
|
-
box.appendChild(
|
|
14112
|
-
const
|
|
14495
|
+
header.append(titleGroup, closeBtn);
|
|
14496
|
+
box.appendChild(header);
|
|
14497
|
+
const searchBar = createElement("div", { class: "an-fr-search-bar" });
|
|
14113
14498
|
const findInput = createElement("input", {
|
|
14114
14499
|
type: "text",
|
|
14115
|
-
class: "an-input",
|
|
14500
|
+
class: "an-input an-fr-input",
|
|
14116
14501
|
placeholder: L.findPlaceholder,
|
|
14117
14502
|
"aria-label": L.searchAriaLabel
|
|
14118
14503
|
});
|
|
14119
14504
|
this._findInput = findInput;
|
|
14120
|
-
findRow.appendChild(findInput);
|
|
14121
|
-
box.appendChild(findRow);
|
|
14122
|
-
const optRow = createElement("div", { class: "an-fr-options-row" });
|
|
14123
|
-
const caseLabel = createElement("label", { class: "an-label an-label-inline" });
|
|
14124
14505
|
const caseCheckbox = createElement("input", {
|
|
14125
14506
|
type: "checkbox",
|
|
14126
|
-
|
|
14507
|
+
style: "display:none",
|
|
14508
|
+
"aria-hidden": "true"
|
|
14127
14509
|
});
|
|
14128
14510
|
this._caseCheckbox = caseCheckbox;
|
|
14129
|
-
|
|
14130
|
-
|
|
14131
|
-
|
|
14132
|
-
|
|
14133
|
-
|
|
14134
|
-
|
|
14511
|
+
const caseBtn = createElement("button", {
|
|
14512
|
+
type: "button",
|
|
14513
|
+
class: "an-fr-icon-btn",
|
|
14514
|
+
title: "Case sensitive",
|
|
14515
|
+
"aria-label": "Case sensitive"
|
|
14516
|
+
});
|
|
14517
|
+
caseBtn.textContent = "Aa";
|
|
14135
14518
|
const prevBtn = createElement("button", {
|
|
14136
14519
|
type: "button",
|
|
14137
|
-
class: "an-btn"
|
|
14520
|
+
class: "an-fr-icon-btn",
|
|
14521
|
+
title: "Previous (Shift+Enter)",
|
|
14522
|
+
"aria-label": "Previous"
|
|
14138
14523
|
});
|
|
14139
|
-
prevBtn.
|
|
14524
|
+
prevBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>`;
|
|
14140
14525
|
const nextBtn = createElement("button", {
|
|
14141
14526
|
type: "button",
|
|
14142
|
-
class: "an-
|
|
14527
|
+
class: "an-fr-icon-btn",
|
|
14528
|
+
title: "Next (Enter)",
|
|
14529
|
+
"aria-label": "Next"
|
|
14143
14530
|
});
|
|
14144
|
-
nextBtn.
|
|
14145
|
-
|
|
14146
|
-
|
|
14531
|
+
nextBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>`;
|
|
14532
|
+
const counter = createElement("span", { class: "an-fr-counter" });
|
|
14533
|
+
this._counterEl = counter;
|
|
14534
|
+
searchBar.append(findInput, caseCheckbox, caseBtn, prevBtn, nextBtn, counter);
|
|
14535
|
+
box.appendChild(searchBar);
|
|
14147
14536
|
const replaceRow = createElement("div", { class: "an-fr-replace-row" });
|
|
14148
14537
|
replaceRow.style.display = "none";
|
|
14149
14538
|
const replaceInput = createElement("input", {
|
|
14150
14539
|
type: "text",
|
|
14151
|
-
class: "an-input",
|
|
14540
|
+
class: "an-input an-fr-input",
|
|
14152
14541
|
placeholder: L.replacePlaceholder,
|
|
14153
14542
|
"aria-label": L.replaceAriaLabel
|
|
14154
14543
|
});
|
|
14155
14544
|
this._replaceInput = replaceInput;
|
|
14156
|
-
replaceRow.appendChild(replaceInput);
|
|
14157
|
-
box.appendChild(replaceRow);
|
|
14158
|
-
const replaceActions = createElement("div", { class: "an-dialog-actions an-fr-replace-actions" });
|
|
14159
|
-
replaceActions.style.display = "none";
|
|
14160
14545
|
const replaceBtn = createElement("button", {
|
|
14161
14546
|
type: "button",
|
|
14162
|
-
class: "an-btn"
|
|
14547
|
+
class: "an-btn an-fr-replace-btn"
|
|
14163
14548
|
});
|
|
14164
14549
|
replaceBtn.textContent = L.replaceBtn;
|
|
14165
14550
|
const replaceAllBtn = createElement("button", {
|
|
14166
14551
|
type: "button",
|
|
14167
|
-
class: "an-btn an-btn-primary"
|
|
14552
|
+
class: "an-btn an-btn-primary an-fr-replace-btn"
|
|
14168
14553
|
});
|
|
14169
14554
|
replaceAllBtn.textContent = L.replaceAllBtn;
|
|
14170
|
-
|
|
14555
|
+
replaceRow.append(replaceInput, replaceBtn, replaceAllBtn);
|
|
14556
|
+
box.appendChild(replaceRow);
|
|
14557
|
+
const replaceActions = createElement("div", { class: "an-fr-replace-actions" });
|
|
14558
|
+
replaceActions.style.display = "none";
|
|
14171
14559
|
box.appendChild(replaceActions);
|
|
14172
14560
|
overlay.appendChild(box);
|
|
14561
|
+
makeDraggable(header, box);
|
|
14173
14562
|
const d1 = on(closeBtn, "click", () => this._close());
|
|
14174
14563
|
const d2 = on(overlay, "click", (e) => {
|
|
14175
14564
|
if (e.target === overlay) this._close();
|
|
14176
14565
|
});
|
|
14177
14566
|
const d3 = on(findInput, "input", () => this._onSearch());
|
|
14178
|
-
const d4 = on(
|
|
14567
|
+
const d4 = on(caseBtn, "click", () => {
|
|
14568
|
+
this._caseSensitive = !this._caseSensitive;
|
|
14569
|
+
caseCheckbox.checked = this._caseSensitive;
|
|
14570
|
+
caseBtn.classList.toggle("an-fr-icon-btn--active", this._caseSensitive);
|
|
14571
|
+
this._onSearch();
|
|
14572
|
+
});
|
|
14573
|
+
const d5 = on(caseCheckbox, "change", () => {
|
|
14179
14574
|
this._caseSensitive = caseCheckbox.checked;
|
|
14575
|
+
caseBtn.classList.toggle("an-fr-icon-btn--active", this._caseSensitive);
|
|
14180
14576
|
this._onSearch();
|
|
14181
14577
|
});
|
|
14182
|
-
const
|
|
14183
|
-
const
|
|
14184
|
-
const
|
|
14185
|
-
const
|
|
14186
|
-
const
|
|
14187
|
-
|
|
14578
|
+
const d6 = on(nextBtn, "click", () => this._next());
|
|
14579
|
+
const d7 = on(prevBtn, "click", () => this._prev());
|
|
14580
|
+
const d8 = on(replaceBtn, "click", () => this._replace());
|
|
14581
|
+
const d9 = on(replaceAllBtn, "click", () => this._replaceAll());
|
|
14582
|
+
const d10 = on(findInput, "keydown", (e) => {
|
|
14583
|
+
const ke = e;
|
|
14584
|
+
if (ke.key === "Enter") {
|
|
14188
14585
|
e.preventDefault();
|
|
14189
|
-
|
|
14586
|
+
ke.shiftKey ? this._prev() : this._next();
|
|
14190
14587
|
}
|
|
14191
14588
|
});
|
|
14192
|
-
const
|
|
14589
|
+
const d11 = on(replaceInput, "keydown", (e) => {
|
|
14193
14590
|
if (e.key === "Enter") {
|
|
14194
14591
|
e.preventDefault();
|
|
14195
14592
|
this._replace();
|
|
14196
14593
|
}
|
|
14197
14594
|
});
|
|
14198
|
-
this._disposers.push(d1, d2, d3, d4, d5, d6, d7, d8, d9, d10);
|
|
14595
|
+
this._disposers.push(d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11);
|
|
14199
14596
|
return overlay;
|
|
14200
14597
|
}
|
|
14201
14598
|
_onSearch() {
|
|
@@ -14263,15 +14660,19 @@ var FindReplace = class {
|
|
|
14263
14660
|
const re = this._queryRegex;
|
|
14264
14661
|
const MAX_RESULTS = 500;
|
|
14265
14662
|
const walker = document.createTreeWalker(root, 4);
|
|
14266
|
-
let node;
|
|
14267
|
-
while (
|
|
14663
|
+
let node = walker.nextNode();
|
|
14664
|
+
while (node && results.length < MAX_RESULTS) {
|
|
14268
14665
|
re.lastIndex = 0;
|
|
14269
14666
|
let m;
|
|
14270
|
-
while ((m = re.exec(
|
|
14667
|
+
while ((m = re.exec(
|
|
14668
|
+
/** @type {Text} */
|
|
14669
|
+
node.textContent
|
|
14670
|
+
)) !== null && results.length < MAX_RESULTS) results.push({
|
|
14271
14671
|
node,
|
|
14272
14672
|
start: m.index,
|
|
14273
14673
|
end: m.index + m[0].length
|
|
14274
14674
|
});
|
|
14675
|
+
node = walker.nextNode();
|
|
14275
14676
|
}
|
|
14276
14677
|
return results;
|
|
14277
14678
|
}
|
|
@@ -14306,7 +14707,7 @@ var FindReplace = class {
|
|
|
14306
14707
|
const parent = match.mark.parentNode;
|
|
14307
14708
|
const textNode = document.createTextNode(replacement);
|
|
14308
14709
|
parent.insertBefore(textNode, match.mark);
|
|
14309
|
-
|
|
14710
|
+
match.mark.remove();
|
|
14310
14711
|
parent.normalize();
|
|
14311
14712
|
this.context.invoke("editor.afterCommand");
|
|
14312
14713
|
const savedIndex = this._currentIndex;
|
|
@@ -14324,7 +14725,7 @@ var FindReplace = class {
|
|
|
14324
14725
|
if (!mark || !mark.parentNode) return;
|
|
14325
14726
|
const textNode = document.createTextNode(replacement);
|
|
14326
14727
|
mark.parentNode.insertBefore(textNode, mark);
|
|
14327
|
-
mark.
|
|
14728
|
+
mark.remove();
|
|
14328
14729
|
});
|
|
14329
14730
|
if (this.context.layoutInfo.editable) this.context.layoutInfo.editable.normalize();
|
|
14330
14731
|
this._matches = [];
|
|
@@ -14343,7 +14744,7 @@ var FindReplace = class {
|
|
|
14343
14744
|
const parent = mark.parentNode;
|
|
14344
14745
|
if (!parent) return;
|
|
14345
14746
|
while (mark.firstChild) parent.insertBefore(mark.firstChild, mark);
|
|
14346
|
-
|
|
14747
|
+
mark.remove();
|
|
14347
14748
|
});
|
|
14348
14749
|
editable.normalize();
|
|
14349
14750
|
this._matches = [];
|
|
@@ -14394,7 +14795,7 @@ function drawCropToCanvas(img, naturalRect, renderW, renderH) {
|
|
|
14394
14795
|
resolve(null);
|
|
14395
14796
|
}
|
|
14396
14797
|
};
|
|
14397
|
-
if (img.src.startsWith("data:") || img.src.startsWith("blob:") || img.src.startsWith(
|
|
14798
|
+
if (img.src.startsWith("data:") || img.src.startsWith("blob:") || img.src.startsWith(globalThis.location.origin)) {
|
|
14398
14799
|
tryDraw(img);
|
|
14399
14800
|
return;
|
|
14400
14801
|
}
|
|
@@ -14556,9 +14957,10 @@ var ImageCropOverlay = class {
|
|
|
14556
14957
|
}), on(h, "touchstart", (e) => {
|
|
14557
14958
|
e.preventDefault();
|
|
14558
14959
|
e.stopPropagation();
|
|
14960
|
+
const te = e;
|
|
14559
14961
|
this._startHandleDrag({
|
|
14560
|
-
clientX:
|
|
14561
|
-
clientY:
|
|
14962
|
+
clientX: te.touches[0].clientX,
|
|
14963
|
+
clientY: te.touches[0].clientY
|
|
14562
14964
|
}, id);
|
|
14563
14965
|
}, { passive: false }));
|
|
14564
14966
|
this._handles[id] = h;
|
|
@@ -14575,9 +14977,10 @@ var ImageCropOverlay = class {
|
|
|
14575
14977
|
if (e.target !== cropBox && e.target !== grid) return;
|
|
14576
14978
|
e.preventDefault();
|
|
14577
14979
|
e.stopPropagation();
|
|
14980
|
+
const te2 = e;
|
|
14578
14981
|
this._startBoxMove({
|
|
14579
|
-
clientX:
|
|
14580
|
-
clientY:
|
|
14982
|
+
clientX: te2.touches[0].clientX,
|
|
14983
|
+
clientY: te2.touches[0].clientY
|
|
14581
14984
|
});
|
|
14582
14985
|
}, { passive: false }));
|
|
14583
14986
|
const infoEl = document.createElement("div");
|
|
@@ -14650,8 +15053,8 @@ var ImageCropOverlay = class {
|
|
|
14650
15053
|
this._cropBox.style.top = `${y}px`;
|
|
14651
15054
|
this._cropBox.style.width = `${w}px`;
|
|
14652
15055
|
this._cropBox.style.height = `${h}px`;
|
|
14653
|
-
const vw =
|
|
14654
|
-
const vh =
|
|
15056
|
+
const vw = globalThis.innerWidth;
|
|
15057
|
+
const vh = globalThis.innerHeight;
|
|
14655
15058
|
this._scrim.style.clipPath = [
|
|
14656
15059
|
`polygon(`,
|
|
14657
15060
|
`0 0, ${vw}px 0, ${vw}px ${vh}px, 0 ${vh}px, 0 0,`,
|
|
@@ -14675,7 +15078,7 @@ var ImageCropOverlay = class {
|
|
|
14675
15078
|
}
|
|
14676
15079
|
const margin = 8;
|
|
14677
15080
|
let tbTop = y + h + margin;
|
|
14678
|
-
if (tbTop + 40 >
|
|
15081
|
+
if (tbTop + 40 > globalThis.innerHeight - margin) tbTop = y - 40 - margin;
|
|
14679
15082
|
this._toolbar.style.left = `${x}px`;
|
|
14680
15083
|
this._toolbar.style.top = `${tbTop}px`;
|
|
14681
15084
|
}
|
|
@@ -14739,9 +15142,10 @@ var ImageCropOverlay = class {
|
|
|
14739
15142
|
_attachDocDrag(onMove) {
|
|
14740
15143
|
const onTouchMove = (e) => {
|
|
14741
15144
|
e.preventDefault();
|
|
15145
|
+
const te3 = e;
|
|
14742
15146
|
onMove({
|
|
14743
|
-
clientX:
|
|
14744
|
-
clientY:
|
|
15147
|
+
clientX: te3.touches[0].clientX,
|
|
15148
|
+
clientY: te3.touches[0].clientY
|
|
14745
15149
|
});
|
|
14746
15150
|
};
|
|
14747
15151
|
const cleanup = () => {
|
|
@@ -14801,7 +15205,7 @@ var ImageCropOverlay = class {
|
|
|
14801
15205
|
this._close(false);
|
|
14802
15206
|
return;
|
|
14803
15207
|
}
|
|
14804
|
-
const fmt =
|
|
15208
|
+
const fmt = /^data:image\/(jpe?g)/i.exec(img.src) ? "image/jpeg" : "image/png";
|
|
14805
15209
|
const quality = fmt === "image/jpeg" ? .92 : void 0;
|
|
14806
15210
|
const newSrc = canvas.toDataURL(fmt, quality);
|
|
14807
15211
|
this._close(false);
|
|
@@ -14841,7 +15245,7 @@ var ImageCropOverlay = class {
|
|
|
14841
15245
|
banner.textContent = msg;
|
|
14842
15246
|
document.body.appendChild(banner);
|
|
14843
15247
|
setTimeout(() => {
|
|
14844
|
-
|
|
15248
|
+
banner.remove();
|
|
14845
15249
|
}, 4e3);
|
|
14846
15250
|
}
|
|
14847
15251
|
/**
|
|
@@ -14856,7 +15260,7 @@ var ImageCropOverlay = class {
|
|
|
14856
15260
|
this._cropBox,
|
|
14857
15261
|
this._toolbar
|
|
14858
15262
|
].forEach((el) => {
|
|
14859
|
-
|
|
15263
|
+
el?.remove();
|
|
14860
15264
|
});
|
|
14861
15265
|
this._scrim = null;
|
|
14862
15266
|
this._cropBox = null;
|
|
@@ -14877,7 +15281,7 @@ var ImageCropOverlay = class {
|
|
|
14877
15281
|
*
|
|
14878
15282
|
* Activated when both `autoSave` and `autoSaveRestore` options are true.
|
|
14879
15283
|
* On initialize it checks localStorage for a draft that is within the
|
|
14880
|
-
* `autoSaveRestoreTimeout` day
|
|
15284
|
+
* `autoSaveRestoreTimeout` day globalThis. If one is found a dismissible banner
|
|
14881
15285
|
* is prepended to the editor container.
|
|
14882
15286
|
*/
|
|
14883
15287
|
var AutoSaveRestore = class {
|
|
@@ -14963,7 +15367,7 @@ var AutoSaveRestore = class {
|
|
|
14963
15367
|
this._removeBanner();
|
|
14964
15368
|
}
|
|
14965
15369
|
_removeBanner() {
|
|
14966
|
-
|
|
15370
|
+
this._banner?.remove();
|
|
14967
15371
|
this._banner = null;
|
|
14968
15372
|
}
|
|
14969
15373
|
};
|
|
@@ -15026,8 +15430,8 @@ var MarkdownShortcuts = class {
|
|
|
15026
15430
|
* @returns {{ text: string, range: Range, lineNode: Node } | null}
|
|
15027
15431
|
*/
|
|
15028
15432
|
_getLineContext() {
|
|
15029
|
-
const sel =
|
|
15030
|
-
if (!sel
|
|
15433
|
+
const sel = globalThis.getSelection();
|
|
15434
|
+
if (!sel?.rangeCount) return null;
|
|
15031
15435
|
const range = sel.getRangeAt(0);
|
|
15032
15436
|
if (!range.collapsed) return null;
|
|
15033
15437
|
const editable = this.context.layoutInfo.editable;
|
|
@@ -15046,7 +15450,7 @@ var MarkdownShortcuts = class {
|
|
|
15046
15450
|
}
|
|
15047
15451
|
_isBlock(node) {
|
|
15048
15452
|
if (node.nodeType !== Node.ELEMENT_NODE) return false;
|
|
15049
|
-
const display =
|
|
15453
|
+
const display = globalThis.getComputedStyle(node).display;
|
|
15050
15454
|
return display === "block" || display === "list-item" || display === "table-cell";
|
|
15051
15455
|
}
|
|
15052
15456
|
/** Applies block rule on Space key. Returns true if a rule fired. */
|
|
@@ -15077,7 +15481,7 @@ var MarkdownShortcuts = class {
|
|
|
15077
15481
|
}
|
|
15078
15482
|
];
|
|
15079
15483
|
for (const { re, handler } of blockPatterns) {
|
|
15080
|
-
const m =
|
|
15484
|
+
const m = re.exec(text);
|
|
15081
15485
|
if (m) {
|
|
15082
15486
|
handler(m);
|
|
15083
15487
|
return true;
|
|
@@ -15101,8 +15505,8 @@ var MarkdownShortcuts = class {
|
|
|
15101
15505
|
return false;
|
|
15102
15506
|
}
|
|
15103
15507
|
_selectLineAndDelete() {
|
|
15104
|
-
const sel =
|
|
15105
|
-
if (!sel
|
|
15508
|
+
const sel = globalThis.getSelection();
|
|
15509
|
+
if (!sel?.rangeCount) return;
|
|
15106
15510
|
const range = sel.getRangeAt(0);
|
|
15107
15511
|
const startRange = document.createRange();
|
|
15108
15512
|
startRange.setStart(range.startContainer.parentNode || range.startContainer, 0);
|
|
@@ -15140,8 +15544,8 @@ var MarkdownShortcuts = class {
|
|
|
15140
15544
|
this.context.triggerEvent("change", this.context.getHTML());
|
|
15141
15545
|
}
|
|
15142
15546
|
_onInput() {
|
|
15143
|
-
const sel =
|
|
15144
|
-
if (!sel
|
|
15547
|
+
const sel = globalThis.getSelection();
|
|
15548
|
+
if (!sel?.rangeCount) return;
|
|
15145
15549
|
const range = sel.getRangeAt(0);
|
|
15146
15550
|
if (!range.collapsed) return;
|
|
15147
15551
|
if (!this.context.layoutInfo.editable.contains(range.startContainer)) return;
|
|
@@ -15169,7 +15573,7 @@ var MarkdownShortcuts = class {
|
|
|
15169
15573
|
];
|
|
15170
15574
|
const upToCursor = text.slice(0, offset);
|
|
15171
15575
|
for (const { re, tag } of inlineRules) {
|
|
15172
|
-
const m =
|
|
15576
|
+
const m = re.exec(upToCursor);
|
|
15173
15577
|
if (!m) continue;
|
|
15174
15578
|
const matchStart = upToCursor.length - m[0].length;
|
|
15175
15579
|
const matchEnd = offset;
|
|
@@ -15180,11 +15584,8 @@ var MarkdownShortcuts = class {
|
|
|
15180
15584
|
el.textContent = innerText;
|
|
15181
15585
|
const beforeNode = document.createTextNode(before);
|
|
15182
15586
|
const afterNode = document.createTextNode("" + after);
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
parent.insertBefore(el, node);
|
|
15186
|
-
parent.insertBefore(afterNode, node);
|
|
15187
|
-
parent.removeChild(node);
|
|
15587
|
+
/** @type {ChildNode} */ node.before(beforeNode, el, afterNode);
|
|
15588
|
+
/** @type {ChildNode} */ node.remove();
|
|
15188
15589
|
const newRange = document.createRange();
|
|
15189
15590
|
newRange.setStart(afterNode, 1);
|
|
15190
15591
|
newRange.collapse(true);
|
|
@@ -15255,12 +15656,12 @@ var _ACTIONS = {
|
|
|
15255
15656
|
strikethrough: (ctx) => ctx.invoke("editor.strikethrough"),
|
|
15256
15657
|
link: (ctx) => ctx.invoke("linkDialog.show"),
|
|
15257
15658
|
removeFormat: (ctx) => {
|
|
15258
|
-
const editable = ctx.layoutInfo
|
|
15659
|
+
const editable = ctx.layoutInfo?.editable;
|
|
15259
15660
|
if (!editable) return;
|
|
15260
15661
|
editable.focus();
|
|
15261
15662
|
document.execCommand("removeFormat");
|
|
15262
|
-
const sel =
|
|
15263
|
-
if (sel
|
|
15663
|
+
const sel = globalThis.getSelection();
|
|
15664
|
+
if (sel?.rangeCount > 0 && !sel.getRangeAt(0).collapsed) {
|
|
15264
15665
|
const range = sel.getRangeAt(0);
|
|
15265
15666
|
const ancestor = range.commonAncestorContainer;
|
|
15266
15667
|
const root = ancestor.nodeType === 1 ? ancestor : ancestor.parentElement;
|
|
@@ -15318,13 +15719,15 @@ var BubbleToolbar = class {
|
|
|
15318
15719
|
const d6 = this.context.on("contextMenu:hide", () => {
|
|
15319
15720
|
this._contextMenuOpen = false;
|
|
15320
15721
|
});
|
|
15321
|
-
|
|
15722
|
+
const d7 = on(globalThis, "scroll", () => this._hide(), { passive: true });
|
|
15723
|
+
const d8 = on(globalThis, "resize", () => this._hide(), { passive: true });
|
|
15724
|
+
this._disposers.push(d1, d2, d3, d4, d5, d6, d7, d8);
|
|
15322
15725
|
return this;
|
|
15323
15726
|
}
|
|
15324
15727
|
destroy() {
|
|
15325
|
-
|
|
15728
|
+
this._el?.remove();
|
|
15326
15729
|
this._el = null;
|
|
15327
|
-
|
|
15730
|
+
this._picker?.remove();
|
|
15328
15731
|
this._picker = null;
|
|
15329
15732
|
this._disposers.forEach((d) => d());
|
|
15330
15733
|
this._disposers = [];
|
|
@@ -15432,20 +15835,22 @@ var BubbleToolbar = class {
|
|
|
15432
15835
|
picker.appendChild(customRow);
|
|
15433
15836
|
document.body.appendChild(picker);
|
|
15434
15837
|
this._picker = picker;
|
|
15435
|
-
|
|
15436
|
-
|
|
15437
|
-
|
|
15838
|
+
const pickerAny = picker;
|
|
15839
|
+
pickerAny._paletteEl = palette;
|
|
15840
|
+
pickerAny._noColorBtn = noColorBtn;
|
|
15841
|
+
pickerAny._colorInput = colorInput;
|
|
15438
15842
|
}
|
|
15439
15843
|
_openColorPicker(type, anchorBtn) {
|
|
15440
|
-
const sel =
|
|
15441
|
-
if (sel
|
|
15844
|
+
const sel = globalThis.getSelection();
|
|
15845
|
+
if (sel?.rangeCount > 0) this._savedRange = sel.getRangeAt(0).cloneRange();
|
|
15442
15846
|
this._pickerType = type;
|
|
15443
|
-
const
|
|
15444
|
-
const
|
|
15847
|
+
const pickerAny = this._picker;
|
|
15848
|
+
const palette = pickerAny._paletteEl;
|
|
15849
|
+
const noColorBtn = pickerAny._noColorBtn;
|
|
15445
15850
|
if (type === "hiliteColor") {
|
|
15446
15851
|
if (!palette.contains(noColorBtn)) palette.appendChild(noColorBtn);
|
|
15447
|
-
} else if (palette.contains(noColorBtn))
|
|
15448
|
-
this._picker._colorInput.value = type === "foreColor" ? "#000000" : "#ffff00";
|
|
15852
|
+
} else if (palette.contains(noColorBtn)) noColorBtn.remove();
|
|
15853
|
+
/** @type {any} */ this._picker._colorInput.value = type === "foreColor" ? "#000000" : "#ffff00";
|
|
15449
15854
|
this._picker.style.display = "block";
|
|
15450
15855
|
const pw = this._picker.offsetWidth;
|
|
15451
15856
|
const ph = this._picker.offsetHeight;
|
|
@@ -15453,7 +15858,7 @@ var BubbleToolbar = class {
|
|
|
15453
15858
|
let top = toolbarRect.top - ph - 6;
|
|
15454
15859
|
if (top < 8) top = toolbarRect.bottom + 6;
|
|
15455
15860
|
let left = anchorBtn.getBoundingClientRect().left;
|
|
15456
|
-
left = Math.max(8, Math.min(left,
|
|
15861
|
+
left = Math.max(8, Math.min(left, globalThis.innerWidth - pw - 8));
|
|
15457
15862
|
this._picker.style.left = `${left}px`;
|
|
15458
15863
|
this._picker.style.top = `${top}px`;
|
|
15459
15864
|
}
|
|
@@ -15463,10 +15868,10 @@ var BubbleToolbar = class {
|
|
|
15463
15868
|
}
|
|
15464
15869
|
/** Restore the saved selection, apply execCommand, update the color strip, then close the picker. */
|
|
15465
15870
|
_applyColor(type, color) {
|
|
15466
|
-
const editable = this.context.layoutInfo
|
|
15871
|
+
const editable = this.context.layoutInfo?.editable;
|
|
15467
15872
|
if (!editable || !this._savedRange) return;
|
|
15468
15873
|
editable.focus();
|
|
15469
|
-
const sel =
|
|
15874
|
+
const sel = globalThis.getSelection();
|
|
15470
15875
|
sel.removeAllRanges();
|
|
15471
15876
|
try {
|
|
15472
15877
|
sel.addRange(this._savedRange.cloneRange());
|
|
@@ -15477,9 +15882,8 @@ var BubbleToolbar = class {
|
|
|
15477
15882
|
if (!document.execCommand(cmd, false, color) && cmd === "hiliteColor") document.execCommand("backColor", false, color);
|
|
15478
15883
|
this.context.invoke("editor.afterCommand");
|
|
15479
15884
|
const name = type === "hiliteColor" ? "hiliteColor" : "foreColor";
|
|
15480
|
-
const
|
|
15481
|
-
|
|
15482
|
-
if (strip) strip.style.background = color === "transparent" ? "transparent" : color;
|
|
15885
|
+
const strip = (this._el?.querySelector(`[data-name="${name}"]`))?.querySelector(".an-bubble-color-strip");
|
|
15886
|
+
if (strip) /** @type {HTMLElement} */ strip.style.background = color === "transparent" ? "transparent" : color;
|
|
15483
15887
|
this._closeColorPicker();
|
|
15484
15888
|
this._syncActive();
|
|
15485
15889
|
}
|
|
@@ -15493,8 +15897,16 @@ var BubbleToolbar = class {
|
|
|
15493
15897
|
const gap = 8;
|
|
15494
15898
|
let left = rect.left + rect.width / 2 - bw / 2;
|
|
15495
15899
|
let top = rect.top - bh - gap;
|
|
15496
|
-
left = Math.max(8, Math.min(left,
|
|
15900
|
+
left = Math.max(8, Math.min(left, globalThis.innerWidth - bw - 8));
|
|
15497
15901
|
if (top < 8) top = rect.bottom + gap;
|
|
15902
|
+
const tableTooltipEl = document.querySelector(".an-table-tooltip");
|
|
15903
|
+
if (tableTooltipEl && tableTooltipEl.style.display !== "none") {
|
|
15904
|
+
const ttRect = tableTooltipEl.getBoundingClientRect();
|
|
15905
|
+
if (top < ttRect.bottom + gap && top + bh > ttRect.top - gap) {
|
|
15906
|
+
top = rect.bottom + gap;
|
|
15907
|
+
if (top + bh > globalThis.innerHeight - 8) top = ttRect.bottom + gap;
|
|
15908
|
+
}
|
|
15909
|
+
}
|
|
15498
15910
|
el.style.top = `${top}px`;
|
|
15499
15911
|
el.style.left = `${left}px`;
|
|
15500
15912
|
el.style.visibility = "";
|
|
@@ -15518,20 +15930,18 @@ var BubbleToolbar = class {
|
|
|
15518
15930
|
/** Read the current selection's color and update the color-strip indicators. */
|
|
15519
15931
|
_syncColorStrips() {
|
|
15520
15932
|
if (!this._el) return;
|
|
15521
|
-
const sel =
|
|
15933
|
+
const sel = globalThis.getSelection();
|
|
15522
15934
|
if (!sel || !sel.rangeCount) return;
|
|
15523
15935
|
let node = sel.getRangeAt(0).startContainer;
|
|
15524
15936
|
if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
|
|
15525
15937
|
if (!node) return;
|
|
15526
|
-
const cs =
|
|
15527
|
-
const
|
|
15528
|
-
|
|
15529
|
-
|
|
15530
|
-
const hiliteBtn = this._el.querySelector("[data-name=\"hiliteColor\"]");
|
|
15531
|
-
const hiliteStrip = hiliteBtn && hiliteBtn.querySelector(".an-bubble-color-strip");
|
|
15938
|
+
const cs = globalThis.getComputedStyle(node);
|
|
15939
|
+
const foreStrip = this._el.querySelector("[data-name=\"foreColor\"]")?.querySelector(".an-bubble-color-strip");
|
|
15940
|
+
if (foreStrip) /** @type {HTMLElement} */ foreStrip.style.background = cs.color || "#000000";
|
|
15941
|
+
const hiliteStrip = this._el.querySelector("[data-name=\"hiliteColor\"]")?.querySelector(".an-bubble-color-strip");
|
|
15532
15942
|
if (hiliteStrip) {
|
|
15533
15943
|
const bg = cs.backgroundColor;
|
|
15534
|
-
hiliteStrip.style.background = !bg || bg === "rgba(0, 0, 0, 0)" || bg === "transparent" ? "transparent" : bg;
|
|
15944
|
+
/** @type {HTMLElement} */ hiliteStrip.style.background = !bg || bg === "rgba(0, 0, 0, 0)" || bg === "transparent" ? "transparent" : bg;
|
|
15535
15945
|
}
|
|
15536
15946
|
}
|
|
15537
15947
|
_onSelectionChange() {
|
|
@@ -15539,7 +15949,7 @@ var BubbleToolbar = class {
|
|
|
15539
15949
|
this._rafId = requestAnimationFrame(() => {
|
|
15540
15950
|
if (this._contextMenuOpen) return;
|
|
15541
15951
|
if (this._picker && this._picker.style.display !== "none") return;
|
|
15542
|
-
const sel =
|
|
15952
|
+
const sel = globalThis.getSelection();
|
|
15543
15953
|
if (!sel || sel.isCollapsed || !sel.rangeCount) {
|
|
15544
15954
|
this._hide();
|
|
15545
15955
|
return;
|
|
@@ -15562,8 +15972,8 @@ var BubbleToolbar = class {
|
|
|
15562
15972
|
}
|
|
15563
15973
|
_onMousedown(e) {
|
|
15564
15974
|
if (!this._visible) return;
|
|
15565
|
-
if (this._el
|
|
15566
|
-
if (this._picker
|
|
15975
|
+
if (this._el?.contains(e.target)) return;
|
|
15976
|
+
if (this._picker?.contains(e.target)) return;
|
|
15567
15977
|
if (this.context.layoutInfo.editable.contains(e.target)) return;
|
|
15568
15978
|
this._hide();
|
|
15569
15979
|
}
|
|
@@ -15648,7 +16058,7 @@ var Mention = class {
|
|
|
15648
16058
|
}
|
|
15649
16059
|
destroy() {
|
|
15650
16060
|
clearTimeout(this._debounceTimer);
|
|
15651
|
-
|
|
16061
|
+
this._dropdown?.remove();
|
|
15652
16062
|
this._dropdown = null;
|
|
15653
16063
|
this._disposers.forEach((d) => d());
|
|
15654
16064
|
this._disposers = [];
|
|
@@ -15659,11 +16069,11 @@ var Mention = class {
|
|
|
15659
16069
|
el.setAttribute("role", "listbox");
|
|
15660
16070
|
el.addEventListener("mousedown", (e) => e.preventDefault());
|
|
15661
16071
|
el.addEventListener("click", (e) => {
|
|
15662
|
-
const item = e.target
|
|
16072
|
+
const item = e.target?.closest(".an-mention-item");
|
|
15663
16073
|
if (item) this._select(+item.dataset.index);
|
|
15664
16074
|
});
|
|
15665
16075
|
el.addEventListener("mousemove", (e) => {
|
|
15666
|
-
const item = e.target
|
|
16076
|
+
const item = e.target?.closest(".an-mention-item");
|
|
15667
16077
|
if (item) this._highlightItem(+item.dataset.index);
|
|
15668
16078
|
});
|
|
15669
16079
|
document.body.appendChild(el);
|
|
@@ -15678,7 +16088,7 @@ var Mention = class {
|
|
|
15678
16088
|
const li = document.createElement("div");
|
|
15679
16089
|
li.className = "an-mention-item";
|
|
15680
16090
|
li.setAttribute("role", "option");
|
|
15681
|
-
li.dataset.index = i;
|
|
16091
|
+
li.dataset.index = String(i);
|
|
15682
16092
|
if (item.avatar) {
|
|
15683
16093
|
const img = document.createElement("img");
|
|
15684
16094
|
img.src = item.avatar;
|
|
@@ -15712,8 +16122,8 @@ var Mention = class {
|
|
|
15712
16122
|
const ddw = dd.offsetWidth;
|
|
15713
16123
|
let top = rect.bottom + 4;
|
|
15714
16124
|
let left = rect.left;
|
|
15715
|
-
if (rect.bottom + ddh + 8 >
|
|
15716
|
-
left = Math.max(8, Math.min(left,
|
|
16125
|
+
if (rect.bottom + ddh + 8 > globalThis.innerHeight) top = rect.top - ddh - 4;
|
|
16126
|
+
left = Math.max(8, Math.min(left, globalThis.innerWidth - ddw - 8));
|
|
15717
16127
|
dd.style.top = `${top}px`;
|
|
15718
16128
|
dd.style.left = `${left}px`;
|
|
15719
16129
|
dd.style.visibility = "";
|
|
@@ -15737,7 +16147,7 @@ var Mention = class {
|
|
|
15737
16147
|
* collapsed range is reliable at this point but often empty inside async callbacks.
|
|
15738
16148
|
*/
|
|
15739
16149
|
_captureCaretRect() {
|
|
15740
|
-
if (this._triggerNode
|
|
16150
|
+
if (this._triggerNode?.isConnected) try {
|
|
15741
16151
|
const r = document.createRange();
|
|
15742
16152
|
const end = Math.min(this._triggerOffset + 1, this._triggerNode.textContent.length);
|
|
15743
16153
|
r.setStart(this._triggerNode, this._triggerOffset);
|
|
@@ -15748,13 +16158,13 @@ var Mention = class {
|
|
|
15748
16158
|
return;
|
|
15749
16159
|
}
|
|
15750
16160
|
} catch (_) {}
|
|
15751
|
-
const sel =
|
|
16161
|
+
const sel = globalThis.getSelection();
|
|
15752
16162
|
if (!sel || !sel.rangeCount) return;
|
|
15753
16163
|
const rects = sel.getRangeAt(0).getClientRects();
|
|
15754
16164
|
if (rects.length > 0) this._caretRect = rects[rects.length - 1];
|
|
15755
16165
|
}
|
|
15756
16166
|
_getQueryAtCursor() {
|
|
15757
|
-
const sel =
|
|
16167
|
+
const sel = globalThis.getSelection();
|
|
15758
16168
|
if (!sel || !sel.rangeCount) return null;
|
|
15759
16169
|
const range = sel.getRangeAt(0);
|
|
15760
16170
|
if (!range.collapsed) return null;
|
|
@@ -15811,7 +16221,7 @@ var Mention = class {
|
|
|
15811
16221
|
}
|
|
15812
16222
|
_onDocClick(e) {
|
|
15813
16223
|
if (!this._open) return;
|
|
15814
|
-
if (this._dropdown
|
|
16224
|
+
if (this._dropdown?.contains(e.target)) return;
|
|
15815
16225
|
this._hideDropdown();
|
|
15816
16226
|
}
|
|
15817
16227
|
_select(index) {
|
|
@@ -15820,7 +16230,7 @@ var Mention = class {
|
|
|
15820
16230
|
if (this._triggerNode) {
|
|
15821
16231
|
const node = this._triggerNode;
|
|
15822
16232
|
node.textContent = node.textContent.slice(0, this._triggerOffset) + node.textContent.slice(this._triggerOffset + this._cfg.trigger.length + this._query.length);
|
|
15823
|
-
const sel =
|
|
16233
|
+
const sel = globalThis.getSelection();
|
|
15824
16234
|
const range = document.createRange();
|
|
15825
16235
|
range.setStart(node, this._triggerOffset);
|
|
15826
16236
|
range.collapse(true);
|
|
@@ -15928,7 +16338,7 @@ var Context = class {
|
|
|
15928
16338
|
/**
|
|
15929
16339
|
* Registers and initialises a custom module on this instance.
|
|
15930
16340
|
* @param {string} name
|
|
15931
|
-
* @param {
|
|
16341
|
+
* @param {new (ctx: this) => any} ModuleClass
|
|
15932
16342
|
* @returns {this}
|
|
15933
16343
|
*/
|
|
15934
16344
|
registerModule(name, ModuleClass) {
|
|
@@ -16181,23 +16591,27 @@ var Context = class {
|
|
|
16181
16591
|
a.style.display = "none";
|
|
16182
16592
|
document.body.appendChild(a);
|
|
16183
16593
|
a.click();
|
|
16184
|
-
|
|
16594
|
+
a.remove();
|
|
16185
16595
|
URL.revokeObjectURL(url);
|
|
16186
16596
|
}
|
|
16187
16597
|
/**
|
|
16188
|
-
* Opens the editor content in a new
|
|
16598
|
+
* Opens the editor content in a new globalThis and triggers the browser print dialog.
|
|
16189
16599
|
* @param {string} [title='']
|
|
16190
16600
|
*/
|
|
16191
16601
|
print(title = "") {
|
|
16192
16602
|
const content = this.getHTML();
|
|
16193
|
-
const
|
|
16194
|
-
const
|
|
16195
|
-
|
|
16196
|
-
w
|
|
16197
|
-
w
|
|
16198
|
-
|
|
16603
|
+
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>`;
|
|
16604
|
+
const blob = new Blob([markup], { type: "text/html" });
|
|
16605
|
+
const url = URL.createObjectURL(blob);
|
|
16606
|
+
const w = globalThis.open(url, "_blank");
|
|
16607
|
+
if (!w) {
|
|
16608
|
+
URL.revokeObjectURL(url);
|
|
16609
|
+
return;
|
|
16610
|
+
}
|
|
16611
|
+
w.addEventListener("load", () => {
|
|
16199
16612
|
w.print();
|
|
16200
|
-
|
|
16613
|
+
URL.revokeObjectURL(url);
|
|
16614
|
+
});
|
|
16201
16615
|
}
|
|
16202
16616
|
/**
|
|
16203
16617
|
* Sets whether the editor is disabled (readonly).
|
|
@@ -16235,10 +16649,12 @@ var Context = class {
|
|
|
16235
16649
|
this._disposers.forEach((d) => d());
|
|
16236
16650
|
this._disposers = [];
|
|
16237
16651
|
const container = this.layoutInfo.container;
|
|
16238
|
-
|
|
16652
|
+
const wasDark = container?.classList.contains("an-theme-dark");
|
|
16653
|
+
if (container?.parentNode) {
|
|
16239
16654
|
this.targetEl.style.display = "";
|
|
16240
|
-
container.
|
|
16655
|
+
container.remove();
|
|
16241
16656
|
}
|
|
16657
|
+
if (wasDark && !document.querySelector(".an-container.an-theme-dark")) document.body.classList.remove("an-theme-dark");
|
|
16242
16658
|
if (typeof this.options.onDestroy === "function") this.options.onDestroy(this);
|
|
16243
16659
|
this._alive = false;
|
|
16244
16660
|
this._listeners.clear();
|
|
@@ -16247,7 +16663,8 @@ var Context = class {
|
|
|
16247
16663
|
* Syncs editor HTML back into the original textarea/input for form submission.
|
|
16248
16664
|
*/
|
|
16249
16665
|
_syncToTarget() {
|
|
16250
|
-
if (this.targetEl.tagName === "TEXTAREA" || this.targetEl.tagName === "INPUT")
|
|
16666
|
+
if (this.targetEl.tagName === "TEXTAREA" || this.targetEl.tagName === "INPUT")
|
|
16667
|
+
/** @type {HTMLInputElement} */ this.targetEl.value = this.getHTML();
|
|
16251
16668
|
}
|
|
16252
16669
|
};
|
|
16253
16670
|
//#endregion
|
|
@@ -16301,7 +16718,7 @@ function tail(arr, n = 1) {
|
|
|
16301
16718
|
* @returns {T[]}
|
|
16302
16719
|
*/
|
|
16303
16720
|
function flatten(arr) {
|
|
16304
|
-
return arr.
|
|
16721
|
+
return arr.flat();
|
|
16305
16722
|
}
|
|
16306
16723
|
/**
|
|
16307
16724
|
* Returns unique elements of an array (using Set).
|
|
@@ -16380,7 +16797,7 @@ var env = {
|
|
|
16380
16797
|
/** True if running on mobile */
|
|
16381
16798
|
isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent),
|
|
16382
16799
|
/** True if touch is supported */
|
|
16383
|
-
isTouch: "ontouchstart" in
|
|
16800
|
+
isTouch: "ontouchstart" in globalThis || navigator.maxTouchPoints > 0,
|
|
16384
16801
|
/** Modifier key name depending on platform */
|
|
16385
16802
|
modifierKey: /Macintosh/.test(userAgent) ? "metaKey" : "ctrlKey"
|
|
16386
16803
|
};
|
|
@@ -16504,6 +16921,6 @@ function resolveElements(selector) {
|
|
|
16504
16921
|
return [];
|
|
16505
16922
|
}
|
|
16506
16923
|
//#endregion
|
|
16507
|
-
export { Context, ELEMENT_NODE, TEXT_NODE, WrappedRange, _buttonRegistry, alignCenterBtn, alignJustifyBtn, alignLeftBtn, alignRightBtn, all, ancestors, any, backColorBtn, boldBtn, checklistBtn, children, chunk, clamp, closest, closestPara, codeviewBtn, collapsedRange, compose, createElement, currentRange, debounce, AutumnNote as default, defaultOptions, defaultToolbar, directionBtn, emojiBtn, env, findBtn, findReplaceBtn, first, flatten, fontFamilyBtn, fontSizeBtn, foreColorBtn, fromNativeRange, fullscreenBtn, getButton, groupBy, hrBtn, iconBtn, identity, imageBtn, indentBtn, initial, inlineCodeBtn, insertAfter, isAnchor, isEditable, isElement, isEmpty, isFunction, isImage, isInline, isInsideEditable, isKey, isLi, isList, isModifier, isNil, isPara, isPlainObject, isSelectionInside, isString, isTable, isText, isVoid, italicBtn, key, last, lineHeightBtn, linkBtn, locales, mergeDeep, nextElement, nodeValue, olBtn, on, outdentBtn, outerHtml, paragraphStyleBtn, placeCaret, prevElement, printBtn, rangeFromElement, rect2bnd, redoBtn, registerButton, remove, removeFormatBtn, resolveLocale, sanitiseHTML, sanitiseUrl, shortcutsBtn, splitText, strikeBtn, subscriptBtn, superscriptBtn, tableBtn, tail, throttle, trapFocus, ulBtn, underlineBtn, undoBtn, unique, unwrap, videoBtn, withSavedRange, wrap };
|
|
16924
|
+
export { Context, ELEMENT_NODE, TEXT_NODE, WrappedRange, _buttonRegistry, alignCenterBtn, alignJustifyBtn, alignLeftBtn, alignRightBtn, all, ancestors, any, backColorBtn, boldBtn, checklistBtn, children, chunk, clamp, closest, closestPara, codeviewBtn, collapsedRange, compose, createElement, currentRange, debounce, AutumnNote as default, defaultOptions, defaultToolbar, directionBtn, emojiBtn, env, findBtn, findReplaceBtn, first, flatten, fontFamilyBtn, fontSizeBtn, foreColorBtn, fromNativeRange, fullscreenBtn, getButton, groupBy, hrBtn, iconBtn, identity, imageBtn, indentBtn, initial, inlineCodeBtn, insertAfter, isAnchor, isEditable, isElement, isEmpty, isFunction, isImage, isInline, isInsideEditable, isKey, isLi, isList, isModifier, isNil, isPara, isPlainObject, isSelectionInside, isString, isTable, isText, isVoid, italicBtn, key, last, lineHeightBtn, linkBtn, locales, makeDraggable, mergeDeep, nextElement, nodeValue, olBtn, on, outdentBtn, outerHtml, paragraphStyleBtn, placeCaret, prevElement, printBtn, rangeFromElement, rect2bnd, redoBtn, registerButton, remove, removeFormatBtn, resolveLocale, sanitiseHTML, sanitiseUrl, shortcutsBtn, splitText, strikeBtn, subscriptBtn, superscriptBtn, tableBtn, tail, throttle, trapFocus, ulBtn, underlineBtn, undoBtn, unique, unwrap, videoBtn, withSavedRange, wrap };
|
|
16508
16925
|
|
|
16509
16926
|
//# sourceMappingURL=autumnnote.es.js.map
|