autumnnote 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/autumnnote.css +129 -1
- package/dist/autumnnote.es.js +401 -36
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.umd.js +401 -36
- package/dist/autumnnote.umd.js.map +1 -1
- package/package.json +3 -2
- package/src/js/Context.js +6 -0
- package/src/js/core/sanitise.js +20 -2
- package/src/js/editing/Style.js +120 -7
- package/src/js/module/Buttons.js +5 -4
- package/src/js/module/Clipboard.js +8 -0
- package/src/js/module/CodeTooltip.js +1 -0
- package/src/js/module/ContextMenu.js +146 -8
- package/src/js/module/Editor.js +61 -0
- package/src/js/module/ImageCropOverlay.js +2 -2
- package/src/js/module/ImageDialog.js +17 -2
- package/src/js/module/ImageResizer.js +2 -0
- package/src/js/module/ImageTooltip.js +9 -0
- package/src/js/module/LinkTooltip.js +4 -0
- package/src/js/module/Placeholder.js +2 -1
- package/src/js/module/TableTooltip.js +6 -0
- package/src/js/module/Toolbar.js +21 -3
- package/src/js/module/VideoDialog.js +5 -5
- package/src/js/module/VideoResizer.js +11 -0
- package/src/js/module/VideoTooltip.js +1 -0
- package/src/js/renderer.js +3 -0
- package/src/styles/autumnnote.scss +146 -9
package/dist/autumnnote.es.js
CHANGED
|
@@ -598,14 +598,42 @@ var fontName = (name) => execCommand("fontName", name);
|
|
|
598
598
|
* @param {HTMLElement} [editable] - scoping element to avoid touching nodes outside this editor
|
|
599
599
|
*/
|
|
600
600
|
function fontSize(size, editable = document) {
|
|
601
|
+
const sel = window.getSelection();
|
|
602
|
+
const wasCollapsed = !sel || !sel.rangeCount || sel.getRangeAt(0).collapsed;
|
|
601
603
|
execCommand("fontSize", "7");
|
|
602
|
-
editable
|
|
604
|
+
const scope = editable instanceof HTMLElement ? editable : document;
|
|
605
|
+
const newSpans = [];
|
|
606
|
+
scope.querySelectorAll("font[size=\"7\"]").forEach((el) => {
|
|
603
607
|
const span = document.createElement("span");
|
|
604
608
|
span.style.fontSize = size;
|
|
605
609
|
el.parentNode.insertBefore(span, el);
|
|
606
610
|
while (el.firstChild) span.appendChild(el.firstChild);
|
|
607
611
|
el.parentNode.removeChild(el);
|
|
612
|
+
newSpans.push(span);
|
|
608
613
|
});
|
|
614
|
+
if (sel && newSpans.length > 0) {
|
|
615
|
+
const first = newSpans[0];
|
|
616
|
+
const last = newSpans[newSpans.length - 1];
|
|
617
|
+
try {
|
|
618
|
+
if (wasCollapsed) {
|
|
619
|
+
if (!first.firstChild) first.appendChild(document.createTextNode(""));
|
|
620
|
+
const nr = document.createRange();
|
|
621
|
+
const anchor = first.firstChild;
|
|
622
|
+
nr.setStart(anchor, anchor.textContent.length);
|
|
623
|
+
nr.collapse(true);
|
|
624
|
+
sel.removeAllRanges();
|
|
625
|
+
sel.addRange(nr);
|
|
626
|
+
} else {
|
|
627
|
+
const nr = document.createRange();
|
|
628
|
+
const startNode = first.firstChild || first;
|
|
629
|
+
const endNode = last.lastChild || last;
|
|
630
|
+
nr.setStart(startNode, 0);
|
|
631
|
+
nr.setEnd(endNode, endNode.nodeType === Node.TEXT_NODE ? endNode.textContent.length : endNode.childNodes.length);
|
|
632
|
+
sel.removeAllRanges();
|
|
633
|
+
sel.addRange(nr);
|
|
634
|
+
}
|
|
635
|
+
} catch (_) {}
|
|
636
|
+
}
|
|
609
637
|
}
|
|
610
638
|
/**
|
|
611
639
|
* Wraps the selection in the given block tag (p, h1-h6, blockquote, pre).
|
|
@@ -710,9 +738,24 @@ function toggleInlineCode(editable) {
|
|
|
710
738
|
const codeEl = container && container.closest ? container.closest("code") : null;
|
|
711
739
|
if (codeEl && !codeEl.closest("pre")) {
|
|
712
740
|
const parent = codeEl.parentNode;
|
|
741
|
+
const prevSibling = codeEl.previousSibling;
|
|
742
|
+
const movedChildren = Array.from(codeEl.childNodes);
|
|
713
743
|
while (codeEl.firstChild) parent.insertBefore(codeEl.firstChild, codeEl);
|
|
714
744
|
parent.removeChild(codeEl);
|
|
715
|
-
if (
|
|
745
|
+
if (parent && parent.normalize) parent.normalize();
|
|
746
|
+
if (movedChildren.length > 0) try {
|
|
747
|
+
const firstMoved = movedChildren[0];
|
|
748
|
+
const lastMoved = movedChildren[movedChildren.length - 1];
|
|
749
|
+
const nr = document.createRange();
|
|
750
|
+
const anchorNode = firstMoved.parentNode === parent ? firstMoved : prevSibling ? prevSibling.nextSibling : parent.firstChild;
|
|
751
|
+
if (anchorNode) {
|
|
752
|
+
nr.setStart(anchorNode, 0);
|
|
753
|
+
const endAnchor = lastMoved.parentNode === parent ? lastMoved : anchorNode;
|
|
754
|
+
nr.setEnd(endAnchor, endAnchor.nodeType === Node.TEXT_NODE ? endAnchor.textContent.length : endAnchor.childNodes.length);
|
|
755
|
+
sel.removeAllRanges();
|
|
756
|
+
sel.addRange(nr);
|
|
757
|
+
}
|
|
758
|
+
} catch (_) {}
|
|
716
759
|
} else {
|
|
717
760
|
if (range.collapsed) return;
|
|
718
761
|
try {
|
|
@@ -737,14 +780,17 @@ function toggleInlineCode(editable) {
|
|
|
737
780
|
/**
|
|
738
781
|
* Returns true when the cursor / selection is inside an inline <code>
|
|
739
782
|
* (not nested in a <pre>).
|
|
783
|
+
* Uses startContainer for reliable cross-browser detection regardless of
|
|
784
|
+
* whether the selection is collapsed or a range (commonAncestorContainer
|
|
785
|
+
* can behave inconsistently for range selections on some browsers).
|
|
740
786
|
* @returns {boolean}
|
|
741
787
|
*/
|
|
742
788
|
function isInlineCode() {
|
|
743
789
|
const sel = window.getSelection();
|
|
744
790
|
if (!sel || !sel.rangeCount) return false;
|
|
745
|
-
let
|
|
746
|
-
if (
|
|
747
|
-
const code =
|
|
791
|
+
let sc = sel.getRangeAt(0).startContainer;
|
|
792
|
+
if (sc.nodeType === 3) sc = sc.parentElement;
|
|
793
|
+
const code = sc && sc.closest ? sc.closest("code") : null;
|
|
748
794
|
return !!(code && !code.closest("pre"));
|
|
749
795
|
}
|
|
750
796
|
/**
|
|
@@ -755,7 +801,8 @@ function isInlineCode() {
|
|
|
755
801
|
function toggleChecklist() {
|
|
756
802
|
const sel = window.getSelection();
|
|
757
803
|
if (!sel || !sel.rangeCount) return;
|
|
758
|
-
|
|
804
|
+
const range = sel.getRangeAt(0);
|
|
805
|
+
let container = range.commonAncestorContainer;
|
|
759
806
|
if (container.nodeType === 3) container = container.parentElement;
|
|
760
807
|
const ul = container.closest && container.closest(".an-checklist");
|
|
761
808
|
if (ul) {
|
|
@@ -781,6 +828,45 @@ function toggleChecklist() {
|
|
|
781
828
|
return;
|
|
782
829
|
}
|
|
783
830
|
}
|
|
831
|
+
if (range.collapsed) {
|
|
832
|
+
const BLOCK_TAGS = new Set([
|
|
833
|
+
"P",
|
|
834
|
+
"DIV",
|
|
835
|
+
"H1",
|
|
836
|
+
"H2",
|
|
837
|
+
"H3",
|
|
838
|
+
"H4",
|
|
839
|
+
"H5",
|
|
840
|
+
"H6",
|
|
841
|
+
"BLOCKQUOTE",
|
|
842
|
+
"LI"
|
|
843
|
+
]);
|
|
844
|
+
let block = container;
|
|
845
|
+
while (block && block.parentNode && !BLOCK_TAGS.has(block.tagName)) block = block.parentNode;
|
|
846
|
+
const itemText = block && BLOCK_TAGS.has(block.tagName) ? Array.from(block.childNodes).map((n) => n.textContent).join("").replace(/\u00a0/g, " ") : "";
|
|
847
|
+
const ul = document.createElement("ul");
|
|
848
|
+
ul.className = "an-checklist";
|
|
849
|
+
const li = document.createElement("li");
|
|
850
|
+
const checkbox = document.createElement("input");
|
|
851
|
+
checkbox.type = "checkbox";
|
|
852
|
+
checkbox.contentEditable = "false";
|
|
853
|
+
li.appendChild(checkbox);
|
|
854
|
+
li.appendChild(document.createTextNode(itemText || ""));
|
|
855
|
+
ul.appendChild(li);
|
|
856
|
+
if (block && BLOCK_TAGS.has(block.tagName)) block.parentNode.replaceChild(ul, block);
|
|
857
|
+
else {
|
|
858
|
+
document.execCommand("insertHTML", false, ul.outerHTML);
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
const textNode = li.lastChild;
|
|
862
|
+
const nr = document.createRange();
|
|
863
|
+
const offset = textNode.nodeType === Node.TEXT_NODE ? textNode.textContent.length : 0;
|
|
864
|
+
nr.setStart(textNode, offset);
|
|
865
|
+
nr.collapse(true);
|
|
866
|
+
sel.removeAllRanges();
|
|
867
|
+
sel.addRange(nr);
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
784
870
|
const lines = sel.toString().split(/\r?\n/).filter((l) => l.trim().length > 0);
|
|
785
871
|
if (lines.length === 0) return;
|
|
786
872
|
const items = lines.map((l) => `<li><input type="checkbox" contenteditable="false">${l || ""}</li>`).join("");
|
|
@@ -849,9 +935,9 @@ var underlineBtn = btn("underline", "underline", "Underline (Ctrl+U)", () => und
|
|
|
849
935
|
if (document.queryCommandState("underline")) return true;
|
|
850
936
|
const sel = window.getSelection();
|
|
851
937
|
if (!sel || !sel.rangeCount) return false;
|
|
852
|
-
let
|
|
853
|
-
if (
|
|
854
|
-
return !!(
|
|
938
|
+
let sc = sel.getRangeAt(0).startContainer;
|
|
939
|
+
if (sc.nodeType === 3) sc = sc.parentElement;
|
|
940
|
+
return !!(sc && sc.closest && sc.closest("u"));
|
|
855
941
|
});
|
|
856
942
|
var strikeBtn = btn("strikethrough", "strikethrough", "Strikethrough", () => strikethrough(), () => document.queryCommandState("strikeThrough"));
|
|
857
943
|
var superscriptBtn = btn("superscript", "superscript", "Superscript", () => superscript(), () => document.queryCommandState("superscript"));
|
|
@@ -1254,7 +1340,6 @@ var PROHIBITED_TAGS = [
|
|
|
1254
1340
|
"object",
|
|
1255
1341
|
"embed",
|
|
1256
1342
|
"form",
|
|
1257
|
-
"input",
|
|
1258
1343
|
"button"
|
|
1259
1344
|
];
|
|
1260
1345
|
/** Attributes whose values must be sanitised as URLs. */
|
|
@@ -1278,7 +1363,8 @@ var TRUSTED_IFRAME_HOSTS = new Set([
|
|
|
1278
1363
|
* Uses DOMParser so the sanitisation follows normal browser parsing rules —
|
|
1279
1364
|
* no regex shortcuts that can be bypassed by encoding tricks.
|
|
1280
1365
|
*
|
|
1281
|
-
* - Strips PROHIBITED_TAGS (script, style, iframe, object, embed, form,
|
|
1366
|
+
* - Strips PROHIBITED_TAGS (script, style, iframe, object, embed, form, button)
|
|
1367
|
+
* - Allows input[type="checkbox"] only inside ul.an-checklist li; removes all other <input>
|
|
1282
1368
|
* - Removes all on* event-handler attributes
|
|
1283
1369
|
* - Rejects javascript: and vbscript: URLs in URL attributes
|
|
1284
1370
|
* - Rejects data: URIs everywhere except img[src] (base64 uploads)
|
|
@@ -1317,6 +1403,16 @@ function sanitiseHTML(html, { allowIframes = false } = {}) {
|
|
|
1317
1403
|
}
|
|
1318
1404
|
});
|
|
1319
1405
|
});
|
|
1406
|
+
doc.querySelectorAll("input").forEach((el) => {
|
|
1407
|
+
if (!(el.closest("ul.an-checklist") !== null && el.closest("li") !== null) || el.getAttribute("type") !== "checkbox") el.remove();
|
|
1408
|
+
else Array.from(el.attributes).forEach((attr) => {
|
|
1409
|
+
if (![
|
|
1410
|
+
"type",
|
|
1411
|
+
"checked",
|
|
1412
|
+
"contenteditable"
|
|
1413
|
+
].includes(attr.name)) el.removeAttribute(attr.name);
|
|
1414
|
+
});
|
|
1415
|
+
});
|
|
1320
1416
|
return doc.body.innerHTML;
|
|
1321
1417
|
}
|
|
1322
1418
|
/**
|
|
@@ -1397,7 +1493,12 @@ function renderLayout(targetEl, options) {
|
|
|
1397
1493
|
if (options.maxHeight) editable.style.maxHeight = `${options.maxHeight}px`;
|
|
1398
1494
|
container.appendChild(editable);
|
|
1399
1495
|
if (options.theme === "dark") container.classList.add("an-theme-dark");
|
|
1400
|
-
if (options.readOnly)
|
|
1496
|
+
if (options.readOnly) {
|
|
1497
|
+
container.classList.add("an-disabled");
|
|
1498
|
+
editable.querySelectorAll("ul.an-checklist input[type=\"checkbox\"]").forEach((cb) => {
|
|
1499
|
+
cb.setAttribute("disabled", "");
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1401
1502
|
if (options.direction === "rtl") {
|
|
1402
1503
|
editable.setAttribute("dir", "rtl");
|
|
1403
1504
|
container.classList.add("an-dir-rtl");
|
|
@@ -2276,7 +2377,37 @@ var Editor = class {
|
|
|
2276
2377
|
sel.removeAllRanges();
|
|
2277
2378
|
sel.addRange(nr);
|
|
2278
2379
|
};
|
|
2279
|
-
|
|
2380
|
+
const isReadOnly = () => this.context.layoutInfo.container.classList.contains("an-disabled");
|
|
2381
|
+
this._disposers.push(on(editable, "keydown", onKeydown), on(editable, "beforeinput", onBeforeInput), on(editable, "input", onInput), on(document, "selectionchange", onSelChange), on(editable, "click", onCheckboxClick), on(editable, "mouseup", fixChecklistCursor), on(editable, "keyup", fixChecklistCursor), on(editable, "dragstart", (e) => {
|
|
2382
|
+
if (isReadOnly()) e.preventDefault();
|
|
2383
|
+
}), on(editable, "drop", (e) => {
|
|
2384
|
+
if (isReadOnly()) e.preventDefault();
|
|
2385
|
+
}));
|
|
2386
|
+
/** @type {string|null} 'superscript' | 'subscript' | null */
|
|
2387
|
+
let _compositionSupSub = null;
|
|
2388
|
+
const onCompositionStart = () => {
|
|
2389
|
+
const sel = window.getSelection();
|
|
2390
|
+
if (!sel || !sel.rangeCount) {
|
|
2391
|
+
_compositionSupSub = null;
|
|
2392
|
+
return;
|
|
2393
|
+
}
|
|
2394
|
+
let node = sel.getRangeAt(0).startContainer;
|
|
2395
|
+
if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
|
|
2396
|
+
if (node && node.closest) if (node.closest("sup")) _compositionSupSub = "superscript";
|
|
2397
|
+
else if (node.closest("sub")) _compositionSupSub = "subscript";
|
|
2398
|
+
else _compositionSupSub = null;
|
|
2399
|
+
};
|
|
2400
|
+
const onCompositionEnd = () => {
|
|
2401
|
+
const tag = _compositionSupSub;
|
|
2402
|
+
_compositionSupSub = null;
|
|
2403
|
+
if (!tag) return;
|
|
2404
|
+
const sel = window.getSelection();
|
|
2405
|
+
if (!sel || !sel.rangeCount) return;
|
|
2406
|
+
let node = sel.getRangeAt(0).startContainer;
|
|
2407
|
+
if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
|
|
2408
|
+
if (!(node && node.closest && (tag === "superscript" ? node.closest("sup") : node.closest("sub")))) document.execCommand(tag);
|
|
2409
|
+
};
|
|
2410
|
+
this._disposers.push(on(editable, "compositionstart", onCompositionStart), on(editable, "compositionend", onCompositionEnd));
|
|
2280
2411
|
}
|
|
2281
2412
|
_onKeydown(event) {
|
|
2282
2413
|
const editable = this.context.layoutInfo.editable;
|
|
@@ -2362,6 +2493,7 @@ var Editor = class {
|
|
|
2362
2493
|
}
|
|
2363
2494
|
}
|
|
2364
2495
|
afterCommand() {
|
|
2496
|
+
this._cleanOrphanedFigures();
|
|
2365
2497
|
this.context.invoke("toolbar.refresh");
|
|
2366
2498
|
this.context.invoke("statusbar.update");
|
|
2367
2499
|
this._scheduleSnapshot();
|
|
@@ -2378,6 +2510,16 @@ var Editor = class {
|
|
|
2378
2510
|
this.context.triggerEvent("change", this.getHTML());
|
|
2379
2511
|
}, 400);
|
|
2380
2512
|
}
|
|
2513
|
+
/**
|
|
2514
|
+
* C4: Removes figure.an-figure elements that no longer contain an <img>.
|
|
2515
|
+
* This happens when a user selects only the image (not the whole figure)
|
|
2516
|
+
* and deletes or replaces it, leaving a dangling figcaption.
|
|
2517
|
+
*/
|
|
2518
|
+
_cleanOrphanedFigures() {
|
|
2519
|
+
this.context.layoutInfo.editable.querySelectorAll("figure.an-figure").forEach((fig) => {
|
|
2520
|
+
if (!fig.querySelector("img")) fig.parentNode.removeChild(fig);
|
|
2521
|
+
});
|
|
2522
|
+
}
|
|
2381
2523
|
focus() {
|
|
2382
2524
|
this.context.layoutInfo.editable.focus();
|
|
2383
2525
|
}
|
|
@@ -3109,15 +3251,28 @@ var Toolbar = class {
|
|
|
3109
3251
|
if (def.name === "fontFamily" && !isHeader) opt.style.fontFamily = value;
|
|
3110
3252
|
select.appendChild(opt);
|
|
3111
3253
|
});
|
|
3254
|
+
/** @type {Range|null} */
|
|
3255
|
+
let _savedRange = null;
|
|
3256
|
+
const dMousedown = on(select, "mousedown", () => {
|
|
3257
|
+
const sel = window.getSelection();
|
|
3258
|
+
_savedRange = sel && sel.rangeCount ? sel.getRangeAt(0).cloneRange() : null;
|
|
3259
|
+
});
|
|
3112
3260
|
const disposer = on(select, "change", (e) => {
|
|
3113
3261
|
const value = e.target.value;
|
|
3114
3262
|
const selectedOpt = e.target.options[e.target.selectedIndex];
|
|
3115
3263
|
if (!value || selectedOpt.disabled) return;
|
|
3116
3264
|
this.context.invoke("editor.focus");
|
|
3265
|
+
if (_savedRange) try {
|
|
3266
|
+
const sel = window.getSelection();
|
|
3267
|
+
if (sel) {
|
|
3268
|
+
sel.removeAllRanges();
|
|
3269
|
+
sel.addRange(_savedRange);
|
|
3270
|
+
}
|
|
3271
|
+
} catch (_) {}
|
|
3117
3272
|
def.action(this.context, value);
|
|
3118
3273
|
this.context.invoke("editor.afterCommand");
|
|
3119
3274
|
});
|
|
3120
|
-
this._disposers.push(disposer);
|
|
3275
|
+
this._disposers.push(dMousedown, disposer);
|
|
3121
3276
|
return select;
|
|
3122
3277
|
}
|
|
3123
3278
|
/**
|
|
@@ -3574,9 +3729,25 @@ var Clipboard = class {
|
|
|
3574
3729
|
this.options.onImageUpload(files);
|
|
3575
3730
|
return;
|
|
3576
3731
|
}
|
|
3732
|
+
const UNSUPPORTED = [
|
|
3733
|
+
"image/tiff",
|
|
3734
|
+
"image/x-tiff",
|
|
3735
|
+
"image/bmp",
|
|
3736
|
+
"image/x-bmp",
|
|
3737
|
+
"image/x-ms-bmp"
|
|
3738
|
+
];
|
|
3577
3739
|
const maxBytes = (this.options.maxImageSize || 5) * 1024 * 1024;
|
|
3578
3740
|
files.forEach((file) => {
|
|
3579
3741
|
if (!file || !file.type.startsWith("image/")) return;
|
|
3742
|
+
if (UNSUPPORTED.includes(file.type)) {
|
|
3743
|
+
const message = `Image format "${file.type}" is not supported for display in web browsers. Please convert to PNG, JPEG, or WebP first.`;
|
|
3744
|
+
this.context.triggerEvent("imageError", {
|
|
3745
|
+
file,
|
|
3746
|
+
message
|
|
3747
|
+
});
|
|
3748
|
+
console.warn("[AutumnNote]", message);
|
|
3749
|
+
return;
|
|
3750
|
+
}
|
|
3580
3751
|
if (file.size > maxBytes) {
|
|
3581
3752
|
const message = `Image "${file.name}" exceeds the ${this.options.maxImageSize || 5} MB size limit.`;
|
|
3582
3753
|
this.context.triggerEvent("imageError", {
|
|
@@ -3740,7 +3911,7 @@ var Placeholder = class {
|
|
|
3740
3911
|
_update() {
|
|
3741
3912
|
const editable = this.context.layoutInfo.editable;
|
|
3742
3913
|
const isFocused = document.activeElement === editable;
|
|
3743
|
-
const isEmpty = !editable.textContent.trim() && !editable.querySelector("img, table, hr");
|
|
3914
|
+
const isEmpty = !editable.textContent.trim() && !editable.querySelector("img, table, hr, .an-video-wrapper");
|
|
3744
3915
|
editable.classList.toggle("an-placeholder", isEmpty && !isFocused);
|
|
3745
3916
|
}
|
|
3746
3917
|
};
|
|
@@ -4178,9 +4349,11 @@ var ImageDialog = class {
|
|
|
4178
4349
|
accept: "image/*"
|
|
4179
4350
|
});
|
|
4180
4351
|
this._fileInput = fileInput;
|
|
4352
|
+
const fileHint = createElement("p", { class: "an-dialog-hint" });
|
|
4353
|
+
this._fileHint = fileHint;
|
|
4181
4354
|
const d = on(fileInput, "change", () => this._onFileChange());
|
|
4182
4355
|
this._disposers.push(d);
|
|
4183
|
-
box.append(fileLabel, fileInput);
|
|
4356
|
+
box.append(fileLabel, fileInput, fileHint);
|
|
4184
4357
|
}
|
|
4185
4358
|
const btnRow = createElement("div", { class: "an-dialog-actions" });
|
|
4186
4359
|
const insertBtn = createElement("button", {
|
|
@@ -4220,9 +4393,27 @@ var ImageDialog = class {
|
|
|
4220
4393
|
_onFileChange() {
|
|
4221
4394
|
const file = this._fileInput && this._fileInput.files && this._fileInput.files[0];
|
|
4222
4395
|
if (!file || !file.type.startsWith("image/")) return;
|
|
4396
|
+
if ([
|
|
4397
|
+
"image/tiff",
|
|
4398
|
+
"image/x-tiff",
|
|
4399
|
+
"image/bmp",
|
|
4400
|
+
"image/x-bmp",
|
|
4401
|
+
"image/x-ms-bmp"
|
|
4402
|
+
].includes(file.type)) {
|
|
4403
|
+
const message = `Format "${file.type}" is not supported for display in web browsers. Please convert to PNG, JPEG, or WebP first.`;
|
|
4404
|
+
if (this._fileHint) this._fileHint.textContent = message;
|
|
4405
|
+
this.context.triggerEvent("imageError", {
|
|
4406
|
+
file,
|
|
4407
|
+
message
|
|
4408
|
+
});
|
|
4409
|
+
this._fileInput.value = "";
|
|
4410
|
+
return;
|
|
4411
|
+
}
|
|
4412
|
+
if (this._fileHint) this._fileHint.textContent = "";
|
|
4223
4413
|
const maxSize = (this.options.maxImageSize || 5) * 1024 * 1024;
|
|
4224
4414
|
if (file.size > maxSize) {
|
|
4225
4415
|
const message = `Image file is too large. Maximum allowed size is ${this.options.maxImageSize || 5} MB.`;
|
|
4416
|
+
if (this._fileHint) this._fileHint.textContent = message;
|
|
4226
4417
|
console.warn("[AutumnNote] ImageDialog:", message);
|
|
4227
4418
|
this.context.triggerEvent("imageError", {
|
|
4228
4419
|
file,
|
|
@@ -4534,6 +4725,7 @@ var ImageResizer = class {
|
|
|
4534
4725
|
_resizeDebounce = setTimeout(() => this._updateOverlayPosition(), 100);
|
|
4535
4726
|
};
|
|
4536
4727
|
this._disposers.push(on(editable, "click", (e) => this._onEditorClick(e)), on(editable, "contextmenu", (e) => {
|
|
4728
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
4537
4729
|
const img = e.target.closest("img");
|
|
4538
4730
|
if (img) this._select(img);
|
|
4539
4731
|
}), on(document, "click", (e) => this._onDocClick(e)), on(window, "scroll", () => this._updateOverlayPosition(), { passive: true }), on(window, "resize", onWindowResize, { passive: true }), on(editable, "scroll", () => this._updateOverlayPosition(), { passive: true }));
|
|
@@ -4584,6 +4776,7 @@ var ImageResizer = class {
|
|
|
4584
4776
|
return overlay;
|
|
4585
4777
|
}
|
|
4586
4778
|
_onEditorClick(e) {
|
|
4779
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
4587
4780
|
const img = e.target.closest("img");
|
|
4588
4781
|
if (img) {
|
|
4589
4782
|
e.preventDefault();
|
|
@@ -4740,9 +4933,12 @@ var VideoResizer = class {
|
|
|
4740
4933
|
_resizeDebounce = setTimeout(() => this._updateOverlayPosition(), 100);
|
|
4741
4934
|
};
|
|
4742
4935
|
this._disposers.push(on(editable, "click", (e) => this._onEditorClick(e)), on(editable, "contextmenu", (e) => {
|
|
4936
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
4743
4937
|
const wrapper = this._findWrapper(e.target);
|
|
4744
4938
|
if (wrapper) this._select(wrapper);
|
|
4745
|
-
}), on(document, "click", (e) => this._onDocClick(e)), on(window, "scroll", () => this._updateOverlayPosition(), { passive: true }), on(window, "resize", onWindowResize), on(editable, "scroll", () => this._updateOverlayPosition(), { passive: true }))
|
|
4939
|
+
}), on(document, "click", (e) => this._onDocClick(e)), on(window, "scroll", () => this._updateOverlayPosition(), { passive: true }), on(window, "resize", onWindowResize), on(editable, "scroll", () => this._updateOverlayPosition(), { passive: true }), on(editable, "dragstart", (e) => {
|
|
4940
|
+
if (e.target instanceof Element && e.target.closest(".an-video-wrapper")) e.preventDefault();
|
|
4941
|
+
}));
|
|
4746
4942
|
return this;
|
|
4747
4943
|
}
|
|
4748
4944
|
destroy() {
|
|
@@ -4801,6 +4997,7 @@ var VideoResizer = class {
|
|
|
4801
4997
|
return overlay;
|
|
4802
4998
|
}
|
|
4803
4999
|
_onEditorClick(e) {
|
|
5000
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
4804
5001
|
const wrapper = this._findWrapper(e.target);
|
|
4805
5002
|
if (wrapper) {
|
|
4806
5003
|
e.preventDefault();
|
|
@@ -4999,9 +5196,12 @@ var LinkTooltip = class {
|
|
|
4999
5196
|
}, HIDE_DELAY$4);
|
|
5000
5197
|
}
|
|
5001
5198
|
_show(anchor) {
|
|
5199
|
+
const isReadOnly = this.context.layoutInfo.container.classList.contains("an-disabled");
|
|
5002
5200
|
const url = anchor.getAttribute("href") || "";
|
|
5003
5201
|
this._urlLabel.textContent = this._truncateUrl(url);
|
|
5004
5202
|
this._urlLabel.title = url;
|
|
5203
|
+
this._editBtn.style.display = isReadOnly ? "none" : "";
|
|
5204
|
+
this._unlinkBtn.style.display = isReadOnly ? "none" : "";
|
|
5005
5205
|
this._el.style.display = "flex";
|
|
5006
5206
|
this._positionNear(anchor);
|
|
5007
5207
|
}
|
|
@@ -5115,6 +5315,7 @@ var ImageTooltip = class {
|
|
|
5115
5315
|
document.body.appendChild(this._el);
|
|
5116
5316
|
const editable = this.context.layoutInfo.editable;
|
|
5117
5317
|
this._disposers.push(on(editable, "mouseover", (e) => {
|
|
5318
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
5118
5319
|
const img = e.target.closest("img");
|
|
5119
5320
|
if (img && editable.contains(img) && !img.closest("a[href]")) this._scheduleShow(img);
|
|
5120
5321
|
}, { passive: true }), on(editable, "mouseout", (e) => {
|
|
@@ -5241,6 +5442,7 @@ var ImageTooltip = class {
|
|
|
5241
5442
|
const target = img.closest("figure.an-figure") || img;
|
|
5242
5443
|
target.style.float = value;
|
|
5243
5444
|
target.style.display = "";
|
|
5445
|
+
if (target !== img) target.style.width = "";
|
|
5244
5446
|
target.style.marginLeft = value === "right" ? "12px" : "";
|
|
5245
5447
|
target.style.marginRight = value === "left" ? "12px" : "";
|
|
5246
5448
|
this.context.invoke("editor.afterCommand");
|
|
@@ -5255,6 +5457,7 @@ var ImageTooltip = class {
|
|
|
5255
5457
|
const target = img.closest("figure.an-figure") || img;
|
|
5256
5458
|
target.style.float = "";
|
|
5257
5459
|
target.style.display = "block";
|
|
5460
|
+
if (target !== img) target.style.width = "fit-content";
|
|
5258
5461
|
target.style.marginLeft = "auto";
|
|
5259
5462
|
target.style.marginRight = "auto";
|
|
5260
5463
|
this.context.invoke("editor.afterCommand");
|
|
@@ -5339,6 +5542,7 @@ var ImageTooltip = class {
|
|
|
5339
5542
|
img.style.marginRight = "";
|
|
5340
5543
|
} else if (img.style.display === "block" && img.style.marginLeft === "auto") {
|
|
5341
5544
|
figure.style.display = "block";
|
|
5545
|
+
figure.style.width = "fit-content";
|
|
5342
5546
|
figure.style.marginLeft = "auto";
|
|
5343
5547
|
figure.style.marginRight = "auto";
|
|
5344
5548
|
img.style.display = "";
|
|
@@ -5393,6 +5597,7 @@ var VideoTooltip = class {
|
|
|
5393
5597
|
document.body.appendChild(this._el);
|
|
5394
5598
|
const editable = this.context.layoutInfo.editable;
|
|
5395
5599
|
this._disposers.push(on(editable, "mouseover", (e) => {
|
|
5600
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
5396
5601
|
const wrapper = e.target.closest(".an-video-wrapper");
|
|
5397
5602
|
if (wrapper && editable.contains(wrapper)) this._scheduleShow(wrapper);
|
|
5398
5603
|
}, { passive: true }), on(editable, "mouseout", (e) => {
|
|
@@ -5684,6 +5889,7 @@ var TableTooltip = class {
|
|
|
5684
5889
|
document.body.appendChild(this._sizePopover);
|
|
5685
5890
|
const editable = this.context.layoutInfo.editable;
|
|
5686
5891
|
this._disposers.push(on(editable, "mouseover", (e) => {
|
|
5892
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
5687
5893
|
const table = e.target.closest("table");
|
|
5688
5894
|
if (table && editable.contains(table)) {
|
|
5689
5895
|
const cell = e.target.closest("td, th");
|
|
@@ -5725,6 +5931,10 @@ var TableTooltip = class {
|
|
|
5725
5931
|
};
|
|
5726
5932
|
const onEditorMove = (e) => {
|
|
5727
5933
|
if (_resizing) return;
|
|
5934
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) {
|
|
5935
|
+
clearHover();
|
|
5936
|
+
return;
|
|
5937
|
+
}
|
|
5728
5938
|
if (_rafEditorMove !== null) return;
|
|
5729
5939
|
const target = e.target;
|
|
5730
5940
|
const clientX = e.clientX;
|
|
@@ -5752,6 +5962,7 @@ var TableTooltip = class {
|
|
|
5752
5962
|
});
|
|
5753
5963
|
};
|
|
5754
5964
|
const onEditorDown = (e) => {
|
|
5965
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
5755
5966
|
if (!_nearCell || !_nearEdge) return;
|
|
5756
5967
|
_resizing = true;
|
|
5757
5968
|
_edge = _nearEdge;
|
|
@@ -6201,6 +6412,7 @@ var CodeTooltip = class {
|
|
|
6201
6412
|
this._ensurePrism();
|
|
6202
6413
|
const editable = this.context.layoutInfo.editable;
|
|
6203
6414
|
this._disposers.push(on(editable, "mouseover", (e) => {
|
|
6415
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
6204
6416
|
const pre = e.target.closest("pre");
|
|
6205
6417
|
if (pre && editable.contains(pre)) this._scheduleShow(pre);
|
|
6206
6418
|
}), on(editable, "mouseout", (e) => {
|
|
@@ -9631,22 +9843,50 @@ var ICONS = {
|
|
|
9631
9843
|
copyFormat: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>`,
|
|
9632
9844
|
pasteFormat: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><rect x="8" y="2" width="8" height="4" rx="1"/><path d="m9 14 2 2 4-4"/></svg>`,
|
|
9633
9845
|
removeFormat: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 21-4.3-4.3c-1-1-1-2.5 0-3.4l9.6-9.6c1-1 2.5-1 3.4 0l5.6 5.6c1 1 1 2.5 0 3.4L13 21"/><path d="M22 21H7"/><path d="m5 11 9 9"/></svg>`,
|
|
9634
|
-
table: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" 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"/></svg
|
|
9846
|
+
table: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" 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"/></svg>`,
|
|
9847
|
+
textColor: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 20L12 4L20 20"/><line x1="7.5" y1="14" x2="16.5" y2="14"/></svg>`,
|
|
9848
|
+
highlightColor: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21v-4l9-9 4 4-9 9z"/><path d="M12 8l4 4"/><line x1="3" y1="21" x2="21" y2="21"/></svg>`,
|
|
9849
|
+
noColor: `<svg xmlns="http://www.w3.org/2000/svg" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="4" y1="4" x2="20" y2="20"/><line x1="20" y1="4" x2="4" y2="20"/></svg>`,
|
|
9850
|
+
back: `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>`
|
|
9635
9851
|
};
|
|
9852
|
+
var COLOR_PRESETS = [
|
|
9853
|
+
"#000000",
|
|
9854
|
+
"#434343",
|
|
9855
|
+
"#666666",
|
|
9856
|
+
"#999999",
|
|
9857
|
+
"#b7b7b7",
|
|
9858
|
+
"#cccccc",
|
|
9859
|
+
"#efefef",
|
|
9860
|
+
"#ffffff",
|
|
9861
|
+
"#ff0000",
|
|
9862
|
+
"#ff9900",
|
|
9863
|
+
"#ffff00",
|
|
9864
|
+
"#00ff00",
|
|
9865
|
+
"#00ffff",
|
|
9866
|
+
"#4a86e8",
|
|
9867
|
+
"#9900ff",
|
|
9868
|
+
"#ff00ff",
|
|
9869
|
+
"#f4cccc",
|
|
9870
|
+
"#fce5cd",
|
|
9871
|
+
"#fff2cc",
|
|
9872
|
+
"#d9ead3",
|
|
9873
|
+
"#d0e0e3",
|
|
9874
|
+
"#c9daf8",
|
|
9875
|
+
"#d9d2e9",
|
|
9876
|
+
"#ead1dc"
|
|
9877
|
+
];
|
|
9878
|
+
function makeColorSubItems(colorType) {
|
|
9879
|
+
const label = colorType === "foreColor" ? "Text Color" : "Highlight Color";
|
|
9880
|
+
return () => [{
|
|
9881
|
+
back: true,
|
|
9882
|
+
label,
|
|
9883
|
+
navigate: () => defaultItems
|
|
9884
|
+
}, {
|
|
9885
|
+
colorPalette: true,
|
|
9886
|
+
colorType
|
|
9887
|
+
}];
|
|
9888
|
+
}
|
|
9636
9889
|
var defaultItems = [
|
|
9637
|
-
{
|
|
9638
|
-
name: "undo",
|
|
9639
|
-
label: "Undo",
|
|
9640
|
-
icon: ICONS.undo,
|
|
9641
|
-
action: (ctx) => ctx.invoke("editor.undo")
|
|
9642
|
-
},
|
|
9643
|
-
{
|
|
9644
|
-
name: "redo",
|
|
9645
|
-
label: "Redo",
|
|
9646
|
-
icon: ICONS.redo,
|
|
9647
|
-
action: (ctx) => ctx.invoke("editor.redo")
|
|
9648
|
-
},
|
|
9649
|
-
{ separator: true },
|
|
9650
9890
|
{
|
|
9651
9891
|
name: "cut",
|
|
9652
9892
|
label: "Cut",
|
|
@@ -9707,6 +9947,21 @@ var defaultItems = [
|
|
|
9707
9947
|
action: (ctx) => ctx.invoke("editor.underline")
|
|
9708
9948
|
},
|
|
9709
9949
|
{ separator: true },
|
|
9950
|
+
{
|
|
9951
|
+
name: "textColor",
|
|
9952
|
+
label: "Text Color",
|
|
9953
|
+
icon: ICONS.textColor,
|
|
9954
|
+
colorStrip: "foreColor",
|
|
9955
|
+
navigate: makeColorSubItems("foreColor")
|
|
9956
|
+
},
|
|
9957
|
+
{
|
|
9958
|
+
name: "highlightColor",
|
|
9959
|
+
label: "Highlight Color",
|
|
9960
|
+
icon: ICONS.highlightColor,
|
|
9961
|
+
colorStrip: "hiliteColor",
|
|
9962
|
+
navigate: makeColorSubItems("hiliteColor")
|
|
9963
|
+
},
|
|
9964
|
+
{ separator: true },
|
|
9710
9965
|
{
|
|
9711
9966
|
name: "copyFormat",
|
|
9712
9967
|
label: "Copy Format",
|
|
@@ -9824,8 +10079,10 @@ var ContextMenu = class {
|
|
|
9824
10079
|
backBtn.appendChild(createElement("span", { class: "an-context-label" }, [it.label || "Back"]));
|
|
9825
10080
|
const off = on(backBtn, "click", (e) => {
|
|
9826
10081
|
e.stopPropagation();
|
|
10082
|
+
const curLeft = parseFloat(this.el.style.left);
|
|
10083
|
+
const curTop = parseFloat(this.el.style.top);
|
|
9827
10084
|
this._renderItems(it.navigate());
|
|
9828
|
-
this._reposition();
|
|
10085
|
+
this._reposition(curLeft, curTop);
|
|
9829
10086
|
});
|
|
9830
10087
|
this._menuDisposers.push(off);
|
|
9831
10088
|
this.el.appendChild(backBtn);
|
|
@@ -9837,7 +10094,19 @@ var ContextMenu = class {
|
|
|
9837
10094
|
class: "an-context-item an-context-submenu",
|
|
9838
10095
|
"data-name": it.name || ""
|
|
9839
10096
|
});
|
|
9840
|
-
if (it.icon) {
|
|
10097
|
+
if (it.icon) if (it.colorStrip) {
|
|
10098
|
+
const iconWrap = createElement("span", {
|
|
10099
|
+
class: "an-context-icon an-context-icon--color",
|
|
10100
|
+
"aria-hidden": "true"
|
|
10101
|
+
});
|
|
10102
|
+
const svgSpan = createElement("span", { class: "an-context-icon-svg" });
|
|
10103
|
+
svgSpan.innerHTML = it.icon;
|
|
10104
|
+
const strip = createElement("span", { class: "an-context-color-strip" });
|
|
10105
|
+
strip.style.background = this._getSelectionColor(it.colorStrip);
|
|
10106
|
+
iconWrap.appendChild(svgSpan);
|
|
10107
|
+
iconWrap.appendChild(strip);
|
|
10108
|
+
btn.appendChild(iconWrap);
|
|
10109
|
+
} else {
|
|
9841
10110
|
const iconSpan = createElement("span", {
|
|
9842
10111
|
class: "an-context-icon",
|
|
9843
10112
|
"aria-hidden": "true"
|
|
@@ -9854,13 +10123,63 @@ var ContextMenu = class {
|
|
|
9854
10123
|
btn.appendChild(chevron);
|
|
9855
10124
|
const off = on(btn, "click", (e) => {
|
|
9856
10125
|
e.stopPropagation();
|
|
10126
|
+
const curLeft = parseFloat(this.el.style.left);
|
|
10127
|
+
const curTop = parseFloat(this.el.style.top);
|
|
9857
10128
|
this._renderItems(it.navigate());
|
|
9858
|
-
this._reposition();
|
|
10129
|
+
this._reposition(curLeft, curTop);
|
|
9859
10130
|
});
|
|
9860
10131
|
this._menuDisposers.push(off);
|
|
9861
10132
|
this.el.appendChild(btn);
|
|
9862
10133
|
return;
|
|
9863
10134
|
}
|
|
10135
|
+
if (it.colorPalette) {
|
|
10136
|
+
const palette = createElement("div", { class: "an-context-color-palette" });
|
|
10137
|
+
COLOR_PRESETS.forEach((color) => {
|
|
10138
|
+
const sw = createElement("div", {
|
|
10139
|
+
class: "an-context-color-swatch",
|
|
10140
|
+
title: color,
|
|
10141
|
+
role: "button",
|
|
10142
|
+
"aria-label": color
|
|
10143
|
+
});
|
|
10144
|
+
sw.style.background = color;
|
|
10145
|
+
const offSw = on(sw, "click", (e) => {
|
|
10146
|
+
e.stopPropagation();
|
|
10147
|
+
this._applyColor(it.colorType, color);
|
|
10148
|
+
});
|
|
10149
|
+
this._menuDisposers.push(offSw);
|
|
10150
|
+
palette.appendChild(sw);
|
|
10151
|
+
});
|
|
10152
|
+
if (it.colorType === "hiliteColor") {
|
|
10153
|
+
const noColor = createElement("div", {
|
|
10154
|
+
class: "an-context-color-swatch an-context-color-none",
|
|
10155
|
+
title: "No highlight",
|
|
10156
|
+
role: "button",
|
|
10157
|
+
"aria-label": "No highlight"
|
|
10158
|
+
});
|
|
10159
|
+
noColor.innerHTML = ICONS.noColor;
|
|
10160
|
+
const offNo = on(noColor, "click", (e) => {
|
|
10161
|
+
e.stopPropagation();
|
|
10162
|
+
this._applyColor("hiliteColor", "transparent");
|
|
10163
|
+
});
|
|
10164
|
+
this._menuDisposers.push(offNo);
|
|
10165
|
+
palette.appendChild(noColor);
|
|
10166
|
+
}
|
|
10167
|
+
this.el.appendChild(palette);
|
|
10168
|
+
const customRow = createElement("div", { class: "an-context-color-custom" });
|
|
10169
|
+
const colorInput = createElement("input", {
|
|
10170
|
+
type: "color",
|
|
10171
|
+
value: it.colorType === "foreColor" ? "#000000" : "#ffff00",
|
|
10172
|
+
title: "Custom color",
|
|
10173
|
+
"aria-label": "Custom color"
|
|
10174
|
+
});
|
|
10175
|
+
const customLabel = createElement("span", {}, ["Custom…"]);
|
|
10176
|
+
const offCustom = on(colorInput, "change", () => this._applyColor(it.colorType, colorInput.value));
|
|
10177
|
+
this._menuDisposers.push(offCustom);
|
|
10178
|
+
customRow.appendChild(colorInput);
|
|
10179
|
+
customRow.appendChild(customLabel);
|
|
10180
|
+
this.el.appendChild(customRow);
|
|
10181
|
+
return;
|
|
10182
|
+
}
|
|
9864
10183
|
if (it.tableGrid) {
|
|
9865
10184
|
const GRID_ROWS = 8, GRID_COLS = 8;
|
|
9866
10185
|
const wrapper = createElement("div", { class: "an-context-table-wrap" });
|
|
@@ -9978,6 +10297,7 @@ var ContextMenu = class {
|
|
|
9978
10297
|
const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
|
|
9979
10298
|
if (!editable) return;
|
|
9980
10299
|
if (!editable.contains(event.target)) return;
|
|
10300
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
9981
10301
|
event.preventDefault();
|
|
9982
10302
|
this._lastX = event.clientX;
|
|
9983
10303
|
this._lastY = event.clientY;
|
|
@@ -10004,7 +10324,19 @@ var ContextMenu = class {
|
|
|
10004
10324
|
let left = rx;
|
|
10005
10325
|
let top = ry;
|
|
10006
10326
|
if (left + rect.width > window.innerWidth) left = window.innerWidth - rect.width - 8;
|
|
10327
|
+
if (left < 8) left = 8;
|
|
10007
10328
|
if (top + rect.height > window.innerHeight) top = window.innerHeight - rect.height - 8;
|
|
10329
|
+
if (top < 8) top = 8;
|
|
10330
|
+
if (this._savedRange) try {
|
|
10331
|
+
const sel = this._savedRange.getBoundingClientRect();
|
|
10332
|
+
if (sel.width > 0 || sel.height > 0) {
|
|
10333
|
+
if (top < sel.bottom && top + rect.height > sel.top && left < sel.right && left + rect.width > sel.left) {
|
|
10334
|
+
const belowTop = sel.bottom + 6;
|
|
10335
|
+
if (belowTop + rect.height <= window.innerHeight - 8) top = belowTop;
|
|
10336
|
+
else top = Math.max(8, sel.top - rect.height - 6);
|
|
10337
|
+
}
|
|
10338
|
+
}
|
|
10339
|
+
} catch (_) {}
|
|
10008
10340
|
this.el.style.left = `${left}px`;
|
|
10009
10341
|
this.el.style.top = `${top}px`;
|
|
10010
10342
|
}
|
|
@@ -10013,6 +10345,33 @@ var ContextMenu = class {
|
|
|
10013
10345
|
this.el.style.display = "none";
|
|
10014
10346
|
this.el.setAttribute("aria-hidden", "true");
|
|
10015
10347
|
}
|
|
10348
|
+
/** Read the current selection's text or highlight color for the strip.
|
|
10349
|
+
* @param {'foreColor'|'hiliteColor'} type
|
|
10350
|
+
* @returns {string} CSS color string
|
|
10351
|
+
*/
|
|
10352
|
+
_getSelectionColor(type) {
|
|
10353
|
+
const range = this._savedRange;
|
|
10354
|
+
if (!range) return type === "foreColor" ? "#000000" : "transparent";
|
|
10355
|
+
let node = range.startContainer;
|
|
10356
|
+
if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
|
|
10357
|
+
if (!node) return type === "foreColor" ? "#000000" : "transparent";
|
|
10358
|
+
const cs = window.getComputedStyle(node);
|
|
10359
|
+
if (type === "foreColor") return cs.color || "#000000";
|
|
10360
|
+
const bg = cs.backgroundColor;
|
|
10361
|
+
return !bg || bg === "rgba(0, 0, 0, 0)" || bg === "transparent" ? "transparent" : bg;
|
|
10362
|
+
}
|
|
10363
|
+
/** Restore selection, apply a color command, then hide the menu. */
|
|
10364
|
+
_applyColor(type, color) {
|
|
10365
|
+
const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
|
|
10366
|
+
if (!editable || !this._savedRange) return;
|
|
10367
|
+
editable.focus();
|
|
10368
|
+
const sel = window.getSelection();
|
|
10369
|
+
sel.removeAllRanges();
|
|
10370
|
+
sel.addRange(this._savedRange.cloneRange());
|
|
10371
|
+
document.execCommand(type, false, color);
|
|
10372
|
+
this.context.invoke("editor.afterCommand");
|
|
10373
|
+
this.hide();
|
|
10374
|
+
}
|
|
10016
10375
|
/** Returns true if a format has been copied — used to disable Paste Format. */
|
|
10017
10376
|
hasCopiedFormat() {
|
|
10018
10377
|
return !!this._copiedFormat;
|
|
@@ -10680,7 +11039,7 @@ function drawCropToCanvas(img, naturalRect, renderW, renderH) {
|
|
|
10680
11039
|
resolve(null);
|
|
10681
11040
|
}
|
|
10682
11041
|
};
|
|
10683
|
-
if (img.src.startsWith("data:") || img.src.startsWith("blob:") || img.src.startsWith(location.origin)) {
|
|
11042
|
+
if (img.src.startsWith("data:") || img.src.startsWith("blob:") || img.src.startsWith(window.location.origin)) {
|
|
10684
11043
|
tryDraw(img);
|
|
10685
11044
|
return;
|
|
10686
11045
|
}
|
|
@@ -11056,7 +11415,7 @@ var ImageCropOverlay = class {
|
|
|
11056
11415
|
height: natH
|
|
11057
11416
|
}, w, h);
|
|
11058
11417
|
if (!canvas) {
|
|
11059
|
-
alert("Cannot crop this image: the image server does not allow cross-origin access.\nUpload the image directly to use the crop tool.");
|
|
11418
|
+
window.alert("Cannot crop this image: the image server does not allow cross-origin access.\nUpload the image directly to use the crop tool.");
|
|
11060
11419
|
this._close(false);
|
|
11061
11420
|
return;
|
|
11062
11421
|
}
|
|
@@ -11417,9 +11776,15 @@ var Context = class {
|
|
|
11417
11776
|
if (disabled) {
|
|
11418
11777
|
editable.setAttribute("contenteditable", "false");
|
|
11419
11778
|
this.layoutInfo.container.classList.add("an-disabled");
|
|
11779
|
+
editable.querySelectorAll("ul.an-checklist input[type=\"checkbox\"]").forEach((cb) => {
|
|
11780
|
+
cb.setAttribute("disabled", "");
|
|
11781
|
+
});
|
|
11420
11782
|
} else {
|
|
11421
11783
|
editable.setAttribute("contenteditable", "true");
|
|
11422
11784
|
this.layoutInfo.container.classList.remove("an-disabled");
|
|
11785
|
+
editable.querySelectorAll("ul.an-checklist input[type=\"checkbox\"]").forEach((cb) => {
|
|
11786
|
+
cb.removeAttribute("disabled");
|
|
11787
|
+
});
|
|
11423
11788
|
}
|
|
11424
11789
|
}
|
|
11425
11790
|
/**
|