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.umd.js
CHANGED
|
@@ -325,14 +325,42 @@
|
|
|
325
325
|
* @param {HTMLElement} [editable] - scoping element to avoid touching nodes outside this editor
|
|
326
326
|
*/
|
|
327
327
|
function fontSize(size, editable = document) {
|
|
328
|
+
const sel = window.getSelection();
|
|
329
|
+
const wasCollapsed = !sel || !sel.rangeCount || sel.getRangeAt(0).collapsed;
|
|
328
330
|
execCommand("fontSize", "7");
|
|
329
|
-
editable
|
|
331
|
+
const scope = editable instanceof HTMLElement ? editable : document;
|
|
332
|
+
const newSpans = [];
|
|
333
|
+
scope.querySelectorAll("font[size=\"7\"]").forEach((el) => {
|
|
330
334
|
const span = document.createElement("span");
|
|
331
335
|
span.style.fontSize = size;
|
|
332
336
|
el.parentNode.insertBefore(span, el);
|
|
333
337
|
while (el.firstChild) span.appendChild(el.firstChild);
|
|
334
338
|
el.parentNode.removeChild(el);
|
|
339
|
+
newSpans.push(span);
|
|
335
340
|
});
|
|
341
|
+
if (sel && newSpans.length > 0) {
|
|
342
|
+
const first = newSpans[0];
|
|
343
|
+
const last = newSpans[newSpans.length - 1];
|
|
344
|
+
try {
|
|
345
|
+
if (wasCollapsed) {
|
|
346
|
+
if (!first.firstChild) first.appendChild(document.createTextNode(""));
|
|
347
|
+
const nr = document.createRange();
|
|
348
|
+
const anchor = first.firstChild;
|
|
349
|
+
nr.setStart(anchor, anchor.textContent.length);
|
|
350
|
+
nr.collapse(true);
|
|
351
|
+
sel.removeAllRanges();
|
|
352
|
+
sel.addRange(nr);
|
|
353
|
+
} else {
|
|
354
|
+
const nr = document.createRange();
|
|
355
|
+
const startNode = first.firstChild || first;
|
|
356
|
+
const endNode = last.lastChild || last;
|
|
357
|
+
nr.setStart(startNode, 0);
|
|
358
|
+
nr.setEnd(endNode, endNode.nodeType === Node.TEXT_NODE ? endNode.textContent.length : endNode.childNodes.length);
|
|
359
|
+
sel.removeAllRanges();
|
|
360
|
+
sel.addRange(nr);
|
|
361
|
+
}
|
|
362
|
+
} catch (_) {}
|
|
363
|
+
}
|
|
336
364
|
}
|
|
337
365
|
/**
|
|
338
366
|
* Wraps the selection in the given block tag (p, h1-h6, blockquote, pre).
|
|
@@ -437,9 +465,24 @@
|
|
|
437
465
|
const codeEl = container && container.closest ? container.closest("code") : null;
|
|
438
466
|
if (codeEl && !codeEl.closest("pre")) {
|
|
439
467
|
const parent = codeEl.parentNode;
|
|
468
|
+
const prevSibling = codeEl.previousSibling;
|
|
469
|
+
const movedChildren = Array.from(codeEl.childNodes);
|
|
440
470
|
while (codeEl.firstChild) parent.insertBefore(codeEl.firstChild, codeEl);
|
|
441
471
|
parent.removeChild(codeEl);
|
|
442
|
-
if (
|
|
472
|
+
if (parent && parent.normalize) parent.normalize();
|
|
473
|
+
if (movedChildren.length > 0) try {
|
|
474
|
+
const firstMoved = movedChildren[0];
|
|
475
|
+
const lastMoved = movedChildren[movedChildren.length - 1];
|
|
476
|
+
const nr = document.createRange();
|
|
477
|
+
const anchorNode = firstMoved.parentNode === parent ? firstMoved : prevSibling ? prevSibling.nextSibling : parent.firstChild;
|
|
478
|
+
if (anchorNode) {
|
|
479
|
+
nr.setStart(anchorNode, 0);
|
|
480
|
+
const endAnchor = lastMoved.parentNode === parent ? lastMoved : anchorNode;
|
|
481
|
+
nr.setEnd(endAnchor, endAnchor.nodeType === Node.TEXT_NODE ? endAnchor.textContent.length : endAnchor.childNodes.length);
|
|
482
|
+
sel.removeAllRanges();
|
|
483
|
+
sel.addRange(nr);
|
|
484
|
+
}
|
|
485
|
+
} catch (_) {}
|
|
443
486
|
} else {
|
|
444
487
|
if (range.collapsed) return;
|
|
445
488
|
try {
|
|
@@ -464,14 +507,17 @@
|
|
|
464
507
|
/**
|
|
465
508
|
* Returns true when the cursor / selection is inside an inline <code>
|
|
466
509
|
* (not nested in a <pre>).
|
|
510
|
+
* Uses startContainer for reliable cross-browser detection regardless of
|
|
511
|
+
* whether the selection is collapsed or a range (commonAncestorContainer
|
|
512
|
+
* can behave inconsistently for range selections on some browsers).
|
|
467
513
|
* @returns {boolean}
|
|
468
514
|
*/
|
|
469
515
|
function isInlineCode() {
|
|
470
516
|
const sel = window.getSelection();
|
|
471
517
|
if (!sel || !sel.rangeCount) return false;
|
|
472
|
-
let
|
|
473
|
-
if (
|
|
474
|
-
const code =
|
|
518
|
+
let sc = sel.getRangeAt(0).startContainer;
|
|
519
|
+
if (sc.nodeType === 3) sc = sc.parentElement;
|
|
520
|
+
const code = sc && sc.closest ? sc.closest("code") : null;
|
|
475
521
|
return !!(code && !code.closest("pre"));
|
|
476
522
|
}
|
|
477
523
|
/**
|
|
@@ -482,7 +528,8 @@
|
|
|
482
528
|
function toggleChecklist() {
|
|
483
529
|
const sel = window.getSelection();
|
|
484
530
|
if (!sel || !sel.rangeCount) return;
|
|
485
|
-
|
|
531
|
+
const range = sel.getRangeAt(0);
|
|
532
|
+
let container = range.commonAncestorContainer;
|
|
486
533
|
if (container.nodeType === 3) container = container.parentElement;
|
|
487
534
|
const ul = container.closest && container.closest(".an-checklist");
|
|
488
535
|
if (ul) {
|
|
@@ -508,6 +555,45 @@
|
|
|
508
555
|
return;
|
|
509
556
|
}
|
|
510
557
|
}
|
|
558
|
+
if (range.collapsed) {
|
|
559
|
+
const BLOCK_TAGS = new Set([
|
|
560
|
+
"P",
|
|
561
|
+
"DIV",
|
|
562
|
+
"H1",
|
|
563
|
+
"H2",
|
|
564
|
+
"H3",
|
|
565
|
+
"H4",
|
|
566
|
+
"H5",
|
|
567
|
+
"H6",
|
|
568
|
+
"BLOCKQUOTE",
|
|
569
|
+
"LI"
|
|
570
|
+
]);
|
|
571
|
+
let block = container;
|
|
572
|
+
while (block && block.parentNode && !BLOCK_TAGS.has(block.tagName)) block = block.parentNode;
|
|
573
|
+
const itemText = block && BLOCK_TAGS.has(block.tagName) ? Array.from(block.childNodes).map((n) => n.textContent).join("").replace(/\u00a0/g, " ") : "";
|
|
574
|
+
const ul = document.createElement("ul");
|
|
575
|
+
ul.className = "an-checklist";
|
|
576
|
+
const li = document.createElement("li");
|
|
577
|
+
const checkbox = document.createElement("input");
|
|
578
|
+
checkbox.type = "checkbox";
|
|
579
|
+
checkbox.contentEditable = "false";
|
|
580
|
+
li.appendChild(checkbox);
|
|
581
|
+
li.appendChild(document.createTextNode(itemText || ""));
|
|
582
|
+
ul.appendChild(li);
|
|
583
|
+
if (block && BLOCK_TAGS.has(block.tagName)) block.parentNode.replaceChild(ul, block);
|
|
584
|
+
else {
|
|
585
|
+
document.execCommand("insertHTML", false, ul.outerHTML);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
const textNode = li.lastChild;
|
|
589
|
+
const nr = document.createRange();
|
|
590
|
+
const offset = textNode.nodeType === Node.TEXT_NODE ? textNode.textContent.length : 0;
|
|
591
|
+
nr.setStart(textNode, offset);
|
|
592
|
+
nr.collapse(true);
|
|
593
|
+
sel.removeAllRanges();
|
|
594
|
+
sel.addRange(nr);
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
511
597
|
const lines = sel.toString().split(/\r?\n/).filter((l) => l.trim().length > 0);
|
|
512
598
|
if (lines.length === 0) return;
|
|
513
599
|
const items = lines.map((l) => `<li><input type="checkbox" contenteditable="false">${l || ""}</li>`).join("");
|
|
@@ -576,9 +662,9 @@
|
|
|
576
662
|
if (document.queryCommandState("underline")) return true;
|
|
577
663
|
const sel = window.getSelection();
|
|
578
664
|
if (!sel || !sel.rangeCount) return false;
|
|
579
|
-
let
|
|
580
|
-
if (
|
|
581
|
-
return !!(
|
|
665
|
+
let sc = sel.getRangeAt(0).startContainer;
|
|
666
|
+
if (sc.nodeType === 3) sc = sc.parentElement;
|
|
667
|
+
return !!(sc && sc.closest && sc.closest("u"));
|
|
582
668
|
});
|
|
583
669
|
var strikeBtn = btn("strikethrough", "strikethrough", "Strikethrough", () => strikethrough(), () => document.queryCommandState("strikeThrough"));
|
|
584
670
|
var superscriptBtn = btn("superscript", "superscript", "Superscript", () => superscript(), () => document.queryCommandState("superscript"));
|
|
@@ -972,7 +1058,6 @@
|
|
|
972
1058
|
"object",
|
|
973
1059
|
"embed",
|
|
974
1060
|
"form",
|
|
975
|
-
"input",
|
|
976
1061
|
"button"
|
|
977
1062
|
];
|
|
978
1063
|
/** Attributes whose values must be sanitised as URLs. */
|
|
@@ -996,7 +1081,8 @@
|
|
|
996
1081
|
* Uses DOMParser so the sanitisation follows normal browser parsing rules —
|
|
997
1082
|
* no regex shortcuts that can be bypassed by encoding tricks.
|
|
998
1083
|
*
|
|
999
|
-
* - Strips PROHIBITED_TAGS (script, style, iframe, object, embed, form,
|
|
1084
|
+
* - Strips PROHIBITED_TAGS (script, style, iframe, object, embed, form, button)
|
|
1085
|
+
* - Allows input[type="checkbox"] only inside ul.an-checklist li; removes all other <input>
|
|
1000
1086
|
* - Removes all on* event-handler attributes
|
|
1001
1087
|
* - Rejects javascript: and vbscript: URLs in URL attributes
|
|
1002
1088
|
* - Rejects data: URIs everywhere except img[src] (base64 uploads)
|
|
@@ -1035,6 +1121,16 @@
|
|
|
1035
1121
|
}
|
|
1036
1122
|
});
|
|
1037
1123
|
});
|
|
1124
|
+
doc.querySelectorAll("input").forEach((el) => {
|
|
1125
|
+
if (!(el.closest("ul.an-checklist") !== null && el.closest("li") !== null) || el.getAttribute("type") !== "checkbox") el.remove();
|
|
1126
|
+
else Array.from(el.attributes).forEach((attr) => {
|
|
1127
|
+
if (![
|
|
1128
|
+
"type",
|
|
1129
|
+
"checked",
|
|
1130
|
+
"contenteditable"
|
|
1131
|
+
].includes(attr.name)) el.removeAttribute(attr.name);
|
|
1132
|
+
});
|
|
1133
|
+
});
|
|
1038
1134
|
return doc.body.innerHTML;
|
|
1039
1135
|
}
|
|
1040
1136
|
/**
|
|
@@ -1115,7 +1211,12 @@
|
|
|
1115
1211
|
if (options.maxHeight) editable.style.maxHeight = `${options.maxHeight}px`;
|
|
1116
1212
|
container.appendChild(editable);
|
|
1117
1213
|
if (options.theme === "dark") container.classList.add("an-theme-dark");
|
|
1118
|
-
if (options.readOnly)
|
|
1214
|
+
if (options.readOnly) {
|
|
1215
|
+
container.classList.add("an-disabled");
|
|
1216
|
+
editable.querySelectorAll("ul.an-checklist input[type=\"checkbox\"]").forEach((cb) => {
|
|
1217
|
+
cb.setAttribute("disabled", "");
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1119
1220
|
if (options.direction === "rtl") {
|
|
1120
1221
|
editable.setAttribute("dir", "rtl");
|
|
1121
1222
|
container.classList.add("an-dir-rtl");
|
|
@@ -1994,7 +2095,37 @@
|
|
|
1994
2095
|
sel.removeAllRanges();
|
|
1995
2096
|
sel.addRange(nr);
|
|
1996
2097
|
};
|
|
1997
|
-
|
|
2098
|
+
const isReadOnly = () => this.context.layoutInfo.container.classList.contains("an-disabled");
|
|
2099
|
+
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) => {
|
|
2100
|
+
if (isReadOnly()) e.preventDefault();
|
|
2101
|
+
}), on(editable, "drop", (e) => {
|
|
2102
|
+
if (isReadOnly()) e.preventDefault();
|
|
2103
|
+
}));
|
|
2104
|
+
/** @type {string|null} 'superscript' | 'subscript' | null */
|
|
2105
|
+
let _compositionSupSub = null;
|
|
2106
|
+
const onCompositionStart = () => {
|
|
2107
|
+
const sel = window.getSelection();
|
|
2108
|
+
if (!sel || !sel.rangeCount) {
|
|
2109
|
+
_compositionSupSub = null;
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
2112
|
+
let node = sel.getRangeAt(0).startContainer;
|
|
2113
|
+
if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
|
|
2114
|
+
if (node && node.closest) if (node.closest("sup")) _compositionSupSub = "superscript";
|
|
2115
|
+
else if (node.closest("sub")) _compositionSupSub = "subscript";
|
|
2116
|
+
else _compositionSupSub = null;
|
|
2117
|
+
};
|
|
2118
|
+
const onCompositionEnd = () => {
|
|
2119
|
+
const tag = _compositionSupSub;
|
|
2120
|
+
_compositionSupSub = null;
|
|
2121
|
+
if (!tag) return;
|
|
2122
|
+
const sel = window.getSelection();
|
|
2123
|
+
if (!sel || !sel.rangeCount) return;
|
|
2124
|
+
let node = sel.getRangeAt(0).startContainer;
|
|
2125
|
+
if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
|
|
2126
|
+
if (!(node && node.closest && (tag === "superscript" ? node.closest("sup") : node.closest("sub")))) document.execCommand(tag);
|
|
2127
|
+
};
|
|
2128
|
+
this._disposers.push(on(editable, "compositionstart", onCompositionStart), on(editable, "compositionend", onCompositionEnd));
|
|
1998
2129
|
}
|
|
1999
2130
|
_onKeydown(event) {
|
|
2000
2131
|
const editable = this.context.layoutInfo.editable;
|
|
@@ -2080,6 +2211,7 @@
|
|
|
2080
2211
|
}
|
|
2081
2212
|
}
|
|
2082
2213
|
afterCommand() {
|
|
2214
|
+
this._cleanOrphanedFigures();
|
|
2083
2215
|
this.context.invoke("toolbar.refresh");
|
|
2084
2216
|
this.context.invoke("statusbar.update");
|
|
2085
2217
|
this._scheduleSnapshot();
|
|
@@ -2096,6 +2228,16 @@
|
|
|
2096
2228
|
this.context.triggerEvent("change", this.getHTML());
|
|
2097
2229
|
}, 400);
|
|
2098
2230
|
}
|
|
2231
|
+
/**
|
|
2232
|
+
* C4: Removes figure.an-figure elements that no longer contain an <img>.
|
|
2233
|
+
* This happens when a user selects only the image (not the whole figure)
|
|
2234
|
+
* and deletes or replaces it, leaving a dangling figcaption.
|
|
2235
|
+
*/
|
|
2236
|
+
_cleanOrphanedFigures() {
|
|
2237
|
+
this.context.layoutInfo.editable.querySelectorAll("figure.an-figure").forEach((fig) => {
|
|
2238
|
+
if (!fig.querySelector("img")) fig.parentNode.removeChild(fig);
|
|
2239
|
+
});
|
|
2240
|
+
}
|
|
2099
2241
|
focus() {
|
|
2100
2242
|
this.context.layoutInfo.editable.focus();
|
|
2101
2243
|
}
|
|
@@ -2827,15 +2969,28 @@
|
|
|
2827
2969
|
if (def.name === "fontFamily" && !isHeader) opt.style.fontFamily = value;
|
|
2828
2970
|
select.appendChild(opt);
|
|
2829
2971
|
});
|
|
2972
|
+
/** @type {Range|null} */
|
|
2973
|
+
let _savedRange = null;
|
|
2974
|
+
const dMousedown = on(select, "mousedown", () => {
|
|
2975
|
+
const sel = window.getSelection();
|
|
2976
|
+
_savedRange = sel && sel.rangeCount ? sel.getRangeAt(0).cloneRange() : null;
|
|
2977
|
+
});
|
|
2830
2978
|
const disposer = on(select, "change", (e) => {
|
|
2831
2979
|
const value = e.target.value;
|
|
2832
2980
|
const selectedOpt = e.target.options[e.target.selectedIndex];
|
|
2833
2981
|
if (!value || selectedOpt.disabled) return;
|
|
2834
2982
|
this.context.invoke("editor.focus");
|
|
2983
|
+
if (_savedRange) try {
|
|
2984
|
+
const sel = window.getSelection();
|
|
2985
|
+
if (sel) {
|
|
2986
|
+
sel.removeAllRanges();
|
|
2987
|
+
sel.addRange(_savedRange);
|
|
2988
|
+
}
|
|
2989
|
+
} catch (_) {}
|
|
2835
2990
|
def.action(this.context, value);
|
|
2836
2991
|
this.context.invoke("editor.afterCommand");
|
|
2837
2992
|
});
|
|
2838
|
-
this._disposers.push(disposer);
|
|
2993
|
+
this._disposers.push(dMousedown, disposer);
|
|
2839
2994
|
return select;
|
|
2840
2995
|
}
|
|
2841
2996
|
/**
|
|
@@ -3292,9 +3447,25 @@
|
|
|
3292
3447
|
this.options.onImageUpload(files);
|
|
3293
3448
|
return;
|
|
3294
3449
|
}
|
|
3450
|
+
const UNSUPPORTED = [
|
|
3451
|
+
"image/tiff",
|
|
3452
|
+
"image/x-tiff",
|
|
3453
|
+
"image/bmp",
|
|
3454
|
+
"image/x-bmp",
|
|
3455
|
+
"image/x-ms-bmp"
|
|
3456
|
+
];
|
|
3295
3457
|
const maxBytes = (this.options.maxImageSize || 5) * 1024 * 1024;
|
|
3296
3458
|
files.forEach((file) => {
|
|
3297
3459
|
if (!file || !file.type.startsWith("image/")) return;
|
|
3460
|
+
if (UNSUPPORTED.includes(file.type)) {
|
|
3461
|
+
const message = `Image format "${file.type}" is not supported for display in web browsers. Please convert to PNG, JPEG, or WebP first.`;
|
|
3462
|
+
this.context.triggerEvent("imageError", {
|
|
3463
|
+
file,
|
|
3464
|
+
message
|
|
3465
|
+
});
|
|
3466
|
+
console.warn("[AutumnNote]", message);
|
|
3467
|
+
return;
|
|
3468
|
+
}
|
|
3298
3469
|
if (file.size > maxBytes) {
|
|
3299
3470
|
const message = `Image "${file.name}" exceeds the ${this.options.maxImageSize || 5} MB size limit.`;
|
|
3300
3471
|
this.context.triggerEvent("imageError", {
|
|
@@ -3458,7 +3629,7 @@
|
|
|
3458
3629
|
_update() {
|
|
3459
3630
|
const editable = this.context.layoutInfo.editable;
|
|
3460
3631
|
const isFocused = document.activeElement === editable;
|
|
3461
|
-
const isEmpty = !editable.textContent.trim() && !editable.querySelector("img, table, hr");
|
|
3632
|
+
const isEmpty = !editable.textContent.trim() && !editable.querySelector("img, table, hr, .an-video-wrapper");
|
|
3462
3633
|
editable.classList.toggle("an-placeholder", isEmpty && !isFocused);
|
|
3463
3634
|
}
|
|
3464
3635
|
};
|
|
@@ -3896,9 +4067,11 @@
|
|
|
3896
4067
|
accept: "image/*"
|
|
3897
4068
|
});
|
|
3898
4069
|
this._fileInput = fileInput;
|
|
4070
|
+
const fileHint = createElement("p", { class: "an-dialog-hint" });
|
|
4071
|
+
this._fileHint = fileHint;
|
|
3899
4072
|
const d = on(fileInput, "change", () => this._onFileChange());
|
|
3900
4073
|
this._disposers.push(d);
|
|
3901
|
-
box.append(fileLabel, fileInput);
|
|
4074
|
+
box.append(fileLabel, fileInput, fileHint);
|
|
3902
4075
|
}
|
|
3903
4076
|
const btnRow = createElement("div", { class: "an-dialog-actions" });
|
|
3904
4077
|
const insertBtn = createElement("button", {
|
|
@@ -3938,9 +4111,27 @@
|
|
|
3938
4111
|
_onFileChange() {
|
|
3939
4112
|
const file = this._fileInput && this._fileInput.files && this._fileInput.files[0];
|
|
3940
4113
|
if (!file || !file.type.startsWith("image/")) return;
|
|
4114
|
+
if ([
|
|
4115
|
+
"image/tiff",
|
|
4116
|
+
"image/x-tiff",
|
|
4117
|
+
"image/bmp",
|
|
4118
|
+
"image/x-bmp",
|
|
4119
|
+
"image/x-ms-bmp"
|
|
4120
|
+
].includes(file.type)) {
|
|
4121
|
+
const message = `Format "${file.type}" is not supported for display in web browsers. Please convert to PNG, JPEG, or WebP first.`;
|
|
4122
|
+
if (this._fileHint) this._fileHint.textContent = message;
|
|
4123
|
+
this.context.triggerEvent("imageError", {
|
|
4124
|
+
file,
|
|
4125
|
+
message
|
|
4126
|
+
});
|
|
4127
|
+
this._fileInput.value = "";
|
|
4128
|
+
return;
|
|
4129
|
+
}
|
|
4130
|
+
if (this._fileHint) this._fileHint.textContent = "";
|
|
3941
4131
|
const maxSize = (this.options.maxImageSize || 5) * 1024 * 1024;
|
|
3942
4132
|
if (file.size > maxSize) {
|
|
3943
4133
|
const message = `Image file is too large. Maximum allowed size is ${this.options.maxImageSize || 5} MB.`;
|
|
4134
|
+
if (this._fileHint) this._fileHint.textContent = message;
|
|
3944
4135
|
console.warn("[AutumnNote] ImageDialog:", message);
|
|
3945
4136
|
this.context.triggerEvent("imageError", {
|
|
3946
4137
|
file,
|
|
@@ -4252,6 +4443,7 @@
|
|
|
4252
4443
|
_resizeDebounce = setTimeout(() => this._updateOverlayPosition(), 100);
|
|
4253
4444
|
};
|
|
4254
4445
|
this._disposers.push(on(editable, "click", (e) => this._onEditorClick(e)), on(editable, "contextmenu", (e) => {
|
|
4446
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
4255
4447
|
const img = e.target.closest("img");
|
|
4256
4448
|
if (img) this._select(img);
|
|
4257
4449
|
}), 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 }));
|
|
@@ -4302,6 +4494,7 @@
|
|
|
4302
4494
|
return overlay;
|
|
4303
4495
|
}
|
|
4304
4496
|
_onEditorClick(e) {
|
|
4497
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
4305
4498
|
const img = e.target.closest("img");
|
|
4306
4499
|
if (img) {
|
|
4307
4500
|
e.preventDefault();
|
|
@@ -4458,9 +4651,12 @@
|
|
|
4458
4651
|
_resizeDebounce = setTimeout(() => this._updateOverlayPosition(), 100);
|
|
4459
4652
|
};
|
|
4460
4653
|
this._disposers.push(on(editable, "click", (e) => this._onEditorClick(e)), on(editable, "contextmenu", (e) => {
|
|
4654
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
4461
4655
|
const wrapper = this._findWrapper(e.target);
|
|
4462
4656
|
if (wrapper) this._select(wrapper);
|
|
4463
|
-
}), 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 }))
|
|
4657
|
+
}), 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) => {
|
|
4658
|
+
if (e.target instanceof Element && e.target.closest(".an-video-wrapper")) e.preventDefault();
|
|
4659
|
+
}));
|
|
4464
4660
|
return this;
|
|
4465
4661
|
}
|
|
4466
4662
|
destroy() {
|
|
@@ -4519,6 +4715,7 @@
|
|
|
4519
4715
|
return overlay;
|
|
4520
4716
|
}
|
|
4521
4717
|
_onEditorClick(e) {
|
|
4718
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
4522
4719
|
const wrapper = this._findWrapper(e.target);
|
|
4523
4720
|
if (wrapper) {
|
|
4524
4721
|
e.preventDefault();
|
|
@@ -4717,9 +4914,12 @@
|
|
|
4717
4914
|
}, HIDE_DELAY$4);
|
|
4718
4915
|
}
|
|
4719
4916
|
_show(anchor) {
|
|
4917
|
+
const isReadOnly = this.context.layoutInfo.container.classList.contains("an-disabled");
|
|
4720
4918
|
const url = anchor.getAttribute("href") || "";
|
|
4721
4919
|
this._urlLabel.textContent = this._truncateUrl(url);
|
|
4722
4920
|
this._urlLabel.title = url;
|
|
4921
|
+
this._editBtn.style.display = isReadOnly ? "none" : "";
|
|
4922
|
+
this._unlinkBtn.style.display = isReadOnly ? "none" : "";
|
|
4723
4923
|
this._el.style.display = "flex";
|
|
4724
4924
|
this._positionNear(anchor);
|
|
4725
4925
|
}
|
|
@@ -4833,6 +5033,7 @@
|
|
|
4833
5033
|
document.body.appendChild(this._el);
|
|
4834
5034
|
const editable = this.context.layoutInfo.editable;
|
|
4835
5035
|
this._disposers.push(on(editable, "mouseover", (e) => {
|
|
5036
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
4836
5037
|
const img = e.target.closest("img");
|
|
4837
5038
|
if (img && editable.contains(img) && !img.closest("a[href]")) this._scheduleShow(img);
|
|
4838
5039
|
}, { passive: true }), on(editable, "mouseout", (e) => {
|
|
@@ -4959,6 +5160,7 @@
|
|
|
4959
5160
|
const target = img.closest("figure.an-figure") || img;
|
|
4960
5161
|
target.style.float = value;
|
|
4961
5162
|
target.style.display = "";
|
|
5163
|
+
if (target !== img) target.style.width = "";
|
|
4962
5164
|
target.style.marginLeft = value === "right" ? "12px" : "";
|
|
4963
5165
|
target.style.marginRight = value === "left" ? "12px" : "";
|
|
4964
5166
|
this.context.invoke("editor.afterCommand");
|
|
@@ -4973,6 +5175,7 @@
|
|
|
4973
5175
|
const target = img.closest("figure.an-figure") || img;
|
|
4974
5176
|
target.style.float = "";
|
|
4975
5177
|
target.style.display = "block";
|
|
5178
|
+
if (target !== img) target.style.width = "fit-content";
|
|
4976
5179
|
target.style.marginLeft = "auto";
|
|
4977
5180
|
target.style.marginRight = "auto";
|
|
4978
5181
|
this.context.invoke("editor.afterCommand");
|
|
@@ -5057,6 +5260,7 @@
|
|
|
5057
5260
|
img.style.marginRight = "";
|
|
5058
5261
|
} else if (img.style.display === "block" && img.style.marginLeft === "auto") {
|
|
5059
5262
|
figure.style.display = "block";
|
|
5263
|
+
figure.style.width = "fit-content";
|
|
5060
5264
|
figure.style.marginLeft = "auto";
|
|
5061
5265
|
figure.style.marginRight = "auto";
|
|
5062
5266
|
img.style.display = "";
|
|
@@ -5111,6 +5315,7 @@
|
|
|
5111
5315
|
document.body.appendChild(this._el);
|
|
5112
5316
|
const editable = this.context.layoutInfo.editable;
|
|
5113
5317
|
this._disposers.push(on(editable, "mouseover", (e) => {
|
|
5318
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
5114
5319
|
const wrapper = e.target.closest(".an-video-wrapper");
|
|
5115
5320
|
if (wrapper && editable.contains(wrapper)) this._scheduleShow(wrapper);
|
|
5116
5321
|
}, { passive: true }), on(editable, "mouseout", (e) => {
|
|
@@ -5402,6 +5607,7 @@
|
|
|
5402
5607
|
document.body.appendChild(this._sizePopover);
|
|
5403
5608
|
const editable = this.context.layoutInfo.editable;
|
|
5404
5609
|
this._disposers.push(on(editable, "mouseover", (e) => {
|
|
5610
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
5405
5611
|
const table = e.target.closest("table");
|
|
5406
5612
|
if (table && editable.contains(table)) {
|
|
5407
5613
|
const cell = e.target.closest("td, th");
|
|
@@ -5443,6 +5649,10 @@
|
|
|
5443
5649
|
};
|
|
5444
5650
|
const onEditorMove = (e) => {
|
|
5445
5651
|
if (_resizing) return;
|
|
5652
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) {
|
|
5653
|
+
clearHover();
|
|
5654
|
+
return;
|
|
5655
|
+
}
|
|
5446
5656
|
if (_rafEditorMove !== null) return;
|
|
5447
5657
|
const target = e.target;
|
|
5448
5658
|
const clientX = e.clientX;
|
|
@@ -5470,6 +5680,7 @@
|
|
|
5470
5680
|
});
|
|
5471
5681
|
};
|
|
5472
5682
|
const onEditorDown = (e) => {
|
|
5683
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
5473
5684
|
if (!_nearCell || !_nearEdge) return;
|
|
5474
5685
|
_resizing = true;
|
|
5475
5686
|
_edge = _nearEdge;
|
|
@@ -5919,6 +6130,7 @@
|
|
|
5919
6130
|
this._ensurePrism();
|
|
5920
6131
|
const editable = this.context.layoutInfo.editable;
|
|
5921
6132
|
this._disposers.push(on(editable, "mouseover", (e) => {
|
|
6133
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
5922
6134
|
const pre = e.target.closest("pre");
|
|
5923
6135
|
if (pre && editable.contains(pre)) this._scheduleShow(pre);
|
|
5924
6136
|
}), on(editable, "mouseout", (e) => {
|
|
@@ -9349,22 +9561,50 @@
|
|
|
9349
9561
|
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>`,
|
|
9350
9562
|
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>`,
|
|
9351
9563
|
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>`,
|
|
9352
|
-
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
|
|
9564
|
+
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>`,
|
|
9565
|
+
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>`,
|
|
9566
|
+
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>`,
|
|
9567
|
+
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>`,
|
|
9568
|
+
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>`
|
|
9353
9569
|
};
|
|
9570
|
+
var COLOR_PRESETS = [
|
|
9571
|
+
"#000000",
|
|
9572
|
+
"#434343",
|
|
9573
|
+
"#666666",
|
|
9574
|
+
"#999999",
|
|
9575
|
+
"#b7b7b7",
|
|
9576
|
+
"#cccccc",
|
|
9577
|
+
"#efefef",
|
|
9578
|
+
"#ffffff",
|
|
9579
|
+
"#ff0000",
|
|
9580
|
+
"#ff9900",
|
|
9581
|
+
"#ffff00",
|
|
9582
|
+
"#00ff00",
|
|
9583
|
+
"#00ffff",
|
|
9584
|
+
"#4a86e8",
|
|
9585
|
+
"#9900ff",
|
|
9586
|
+
"#ff00ff",
|
|
9587
|
+
"#f4cccc",
|
|
9588
|
+
"#fce5cd",
|
|
9589
|
+
"#fff2cc",
|
|
9590
|
+
"#d9ead3",
|
|
9591
|
+
"#d0e0e3",
|
|
9592
|
+
"#c9daf8",
|
|
9593
|
+
"#d9d2e9",
|
|
9594
|
+
"#ead1dc"
|
|
9595
|
+
];
|
|
9596
|
+
function makeColorSubItems(colorType) {
|
|
9597
|
+
const label = colorType === "foreColor" ? "Text Color" : "Highlight Color";
|
|
9598
|
+
return () => [{
|
|
9599
|
+
back: true,
|
|
9600
|
+
label,
|
|
9601
|
+
navigate: () => defaultItems
|
|
9602
|
+
}, {
|
|
9603
|
+
colorPalette: true,
|
|
9604
|
+
colorType
|
|
9605
|
+
}];
|
|
9606
|
+
}
|
|
9354
9607
|
var defaultItems = [
|
|
9355
|
-
{
|
|
9356
|
-
name: "undo",
|
|
9357
|
-
label: "Undo",
|
|
9358
|
-
icon: ICONS.undo,
|
|
9359
|
-
action: (ctx) => ctx.invoke("editor.undo")
|
|
9360
|
-
},
|
|
9361
|
-
{
|
|
9362
|
-
name: "redo",
|
|
9363
|
-
label: "Redo",
|
|
9364
|
-
icon: ICONS.redo,
|
|
9365
|
-
action: (ctx) => ctx.invoke("editor.redo")
|
|
9366
|
-
},
|
|
9367
|
-
{ separator: true },
|
|
9368
9608
|
{
|
|
9369
9609
|
name: "cut",
|
|
9370
9610
|
label: "Cut",
|
|
@@ -9425,6 +9665,21 @@
|
|
|
9425
9665
|
action: (ctx) => ctx.invoke("editor.underline")
|
|
9426
9666
|
},
|
|
9427
9667
|
{ separator: true },
|
|
9668
|
+
{
|
|
9669
|
+
name: "textColor",
|
|
9670
|
+
label: "Text Color",
|
|
9671
|
+
icon: ICONS.textColor,
|
|
9672
|
+
colorStrip: "foreColor",
|
|
9673
|
+
navigate: makeColorSubItems("foreColor")
|
|
9674
|
+
},
|
|
9675
|
+
{
|
|
9676
|
+
name: "highlightColor",
|
|
9677
|
+
label: "Highlight Color",
|
|
9678
|
+
icon: ICONS.highlightColor,
|
|
9679
|
+
colorStrip: "hiliteColor",
|
|
9680
|
+
navigate: makeColorSubItems("hiliteColor")
|
|
9681
|
+
},
|
|
9682
|
+
{ separator: true },
|
|
9428
9683
|
{
|
|
9429
9684
|
name: "copyFormat",
|
|
9430
9685
|
label: "Copy Format",
|
|
@@ -9542,8 +9797,10 @@
|
|
|
9542
9797
|
backBtn.appendChild(createElement("span", { class: "an-context-label" }, [it.label || "Back"]));
|
|
9543
9798
|
const off = on(backBtn, "click", (e) => {
|
|
9544
9799
|
e.stopPropagation();
|
|
9800
|
+
const curLeft = parseFloat(this.el.style.left);
|
|
9801
|
+
const curTop = parseFloat(this.el.style.top);
|
|
9545
9802
|
this._renderItems(it.navigate());
|
|
9546
|
-
this._reposition();
|
|
9803
|
+
this._reposition(curLeft, curTop);
|
|
9547
9804
|
});
|
|
9548
9805
|
this._menuDisposers.push(off);
|
|
9549
9806
|
this.el.appendChild(backBtn);
|
|
@@ -9555,7 +9812,19 @@
|
|
|
9555
9812
|
class: "an-context-item an-context-submenu",
|
|
9556
9813
|
"data-name": it.name || ""
|
|
9557
9814
|
});
|
|
9558
|
-
if (it.icon) {
|
|
9815
|
+
if (it.icon) if (it.colorStrip) {
|
|
9816
|
+
const iconWrap = createElement("span", {
|
|
9817
|
+
class: "an-context-icon an-context-icon--color",
|
|
9818
|
+
"aria-hidden": "true"
|
|
9819
|
+
});
|
|
9820
|
+
const svgSpan = createElement("span", { class: "an-context-icon-svg" });
|
|
9821
|
+
svgSpan.innerHTML = it.icon;
|
|
9822
|
+
const strip = createElement("span", { class: "an-context-color-strip" });
|
|
9823
|
+
strip.style.background = this._getSelectionColor(it.colorStrip);
|
|
9824
|
+
iconWrap.appendChild(svgSpan);
|
|
9825
|
+
iconWrap.appendChild(strip);
|
|
9826
|
+
btn.appendChild(iconWrap);
|
|
9827
|
+
} else {
|
|
9559
9828
|
const iconSpan = createElement("span", {
|
|
9560
9829
|
class: "an-context-icon",
|
|
9561
9830
|
"aria-hidden": "true"
|
|
@@ -9572,13 +9841,63 @@
|
|
|
9572
9841
|
btn.appendChild(chevron);
|
|
9573
9842
|
const off = on(btn, "click", (e) => {
|
|
9574
9843
|
e.stopPropagation();
|
|
9844
|
+
const curLeft = parseFloat(this.el.style.left);
|
|
9845
|
+
const curTop = parseFloat(this.el.style.top);
|
|
9575
9846
|
this._renderItems(it.navigate());
|
|
9576
|
-
this._reposition();
|
|
9847
|
+
this._reposition(curLeft, curTop);
|
|
9577
9848
|
});
|
|
9578
9849
|
this._menuDisposers.push(off);
|
|
9579
9850
|
this.el.appendChild(btn);
|
|
9580
9851
|
return;
|
|
9581
9852
|
}
|
|
9853
|
+
if (it.colorPalette) {
|
|
9854
|
+
const palette = createElement("div", { class: "an-context-color-palette" });
|
|
9855
|
+
COLOR_PRESETS.forEach((color) => {
|
|
9856
|
+
const sw = createElement("div", {
|
|
9857
|
+
class: "an-context-color-swatch",
|
|
9858
|
+
title: color,
|
|
9859
|
+
role: "button",
|
|
9860
|
+
"aria-label": color
|
|
9861
|
+
});
|
|
9862
|
+
sw.style.background = color;
|
|
9863
|
+
const offSw = on(sw, "click", (e) => {
|
|
9864
|
+
e.stopPropagation();
|
|
9865
|
+
this._applyColor(it.colorType, color);
|
|
9866
|
+
});
|
|
9867
|
+
this._menuDisposers.push(offSw);
|
|
9868
|
+
palette.appendChild(sw);
|
|
9869
|
+
});
|
|
9870
|
+
if (it.colorType === "hiliteColor") {
|
|
9871
|
+
const noColor = createElement("div", {
|
|
9872
|
+
class: "an-context-color-swatch an-context-color-none",
|
|
9873
|
+
title: "No highlight",
|
|
9874
|
+
role: "button",
|
|
9875
|
+
"aria-label": "No highlight"
|
|
9876
|
+
});
|
|
9877
|
+
noColor.innerHTML = ICONS.noColor;
|
|
9878
|
+
const offNo = on(noColor, "click", (e) => {
|
|
9879
|
+
e.stopPropagation();
|
|
9880
|
+
this._applyColor("hiliteColor", "transparent");
|
|
9881
|
+
});
|
|
9882
|
+
this._menuDisposers.push(offNo);
|
|
9883
|
+
palette.appendChild(noColor);
|
|
9884
|
+
}
|
|
9885
|
+
this.el.appendChild(palette);
|
|
9886
|
+
const customRow = createElement("div", { class: "an-context-color-custom" });
|
|
9887
|
+
const colorInput = createElement("input", {
|
|
9888
|
+
type: "color",
|
|
9889
|
+
value: it.colorType === "foreColor" ? "#000000" : "#ffff00",
|
|
9890
|
+
title: "Custom color",
|
|
9891
|
+
"aria-label": "Custom color"
|
|
9892
|
+
});
|
|
9893
|
+
const customLabel = createElement("span", {}, ["Custom…"]);
|
|
9894
|
+
const offCustom = on(colorInput, "change", () => this._applyColor(it.colorType, colorInput.value));
|
|
9895
|
+
this._menuDisposers.push(offCustom);
|
|
9896
|
+
customRow.appendChild(colorInput);
|
|
9897
|
+
customRow.appendChild(customLabel);
|
|
9898
|
+
this.el.appendChild(customRow);
|
|
9899
|
+
return;
|
|
9900
|
+
}
|
|
9582
9901
|
if (it.tableGrid) {
|
|
9583
9902
|
const GRID_ROWS = 8, GRID_COLS = 8;
|
|
9584
9903
|
const wrapper = createElement("div", { class: "an-context-table-wrap" });
|
|
@@ -9696,6 +10015,7 @@
|
|
|
9696
10015
|
const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
|
|
9697
10016
|
if (!editable) return;
|
|
9698
10017
|
if (!editable.contains(event.target)) return;
|
|
10018
|
+
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
9699
10019
|
event.preventDefault();
|
|
9700
10020
|
this._lastX = event.clientX;
|
|
9701
10021
|
this._lastY = event.clientY;
|
|
@@ -9722,7 +10042,19 @@
|
|
|
9722
10042
|
let left = rx;
|
|
9723
10043
|
let top = ry;
|
|
9724
10044
|
if (left + rect.width > window.innerWidth) left = window.innerWidth - rect.width - 8;
|
|
10045
|
+
if (left < 8) left = 8;
|
|
9725
10046
|
if (top + rect.height > window.innerHeight) top = window.innerHeight - rect.height - 8;
|
|
10047
|
+
if (top < 8) top = 8;
|
|
10048
|
+
if (this._savedRange) try {
|
|
10049
|
+
const sel = this._savedRange.getBoundingClientRect();
|
|
10050
|
+
if (sel.width > 0 || sel.height > 0) {
|
|
10051
|
+
if (top < sel.bottom && top + rect.height > sel.top && left < sel.right && left + rect.width > sel.left) {
|
|
10052
|
+
const belowTop = sel.bottom + 6;
|
|
10053
|
+
if (belowTop + rect.height <= window.innerHeight - 8) top = belowTop;
|
|
10054
|
+
else top = Math.max(8, sel.top - rect.height - 6);
|
|
10055
|
+
}
|
|
10056
|
+
}
|
|
10057
|
+
} catch (_) {}
|
|
9726
10058
|
this.el.style.left = `${left}px`;
|
|
9727
10059
|
this.el.style.top = `${top}px`;
|
|
9728
10060
|
}
|
|
@@ -9731,6 +10063,33 @@
|
|
|
9731
10063
|
this.el.style.display = "none";
|
|
9732
10064
|
this.el.setAttribute("aria-hidden", "true");
|
|
9733
10065
|
}
|
|
10066
|
+
/** Read the current selection's text or highlight color for the strip.
|
|
10067
|
+
* @param {'foreColor'|'hiliteColor'} type
|
|
10068
|
+
* @returns {string} CSS color string
|
|
10069
|
+
*/
|
|
10070
|
+
_getSelectionColor(type) {
|
|
10071
|
+
const range = this._savedRange;
|
|
10072
|
+
if (!range) return type === "foreColor" ? "#000000" : "transparent";
|
|
10073
|
+
let node = range.startContainer;
|
|
10074
|
+
if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
|
|
10075
|
+
if (!node) return type === "foreColor" ? "#000000" : "transparent";
|
|
10076
|
+
const cs = window.getComputedStyle(node);
|
|
10077
|
+
if (type === "foreColor") return cs.color || "#000000";
|
|
10078
|
+
const bg = cs.backgroundColor;
|
|
10079
|
+
return !bg || bg === "rgba(0, 0, 0, 0)" || bg === "transparent" ? "transparent" : bg;
|
|
10080
|
+
}
|
|
10081
|
+
/** Restore selection, apply a color command, then hide the menu. */
|
|
10082
|
+
_applyColor(type, color) {
|
|
10083
|
+
const editable = this.context.layoutInfo && this.context.layoutInfo.editable;
|
|
10084
|
+
if (!editable || !this._savedRange) return;
|
|
10085
|
+
editable.focus();
|
|
10086
|
+
const sel = window.getSelection();
|
|
10087
|
+
sel.removeAllRanges();
|
|
10088
|
+
sel.addRange(this._savedRange.cloneRange());
|
|
10089
|
+
document.execCommand(type, false, color);
|
|
10090
|
+
this.context.invoke("editor.afterCommand");
|
|
10091
|
+
this.hide();
|
|
10092
|
+
}
|
|
9734
10093
|
/** Returns true if a format has been copied — used to disable Paste Format. */
|
|
9735
10094
|
hasCopiedFormat() {
|
|
9736
10095
|
return !!this._copiedFormat;
|
|
@@ -10398,7 +10757,7 @@
|
|
|
10398
10757
|
resolve(null);
|
|
10399
10758
|
}
|
|
10400
10759
|
};
|
|
10401
|
-
if (img.src.startsWith("data:") || img.src.startsWith("blob:") || img.src.startsWith(location.origin)) {
|
|
10760
|
+
if (img.src.startsWith("data:") || img.src.startsWith("blob:") || img.src.startsWith(window.location.origin)) {
|
|
10402
10761
|
tryDraw(img);
|
|
10403
10762
|
return;
|
|
10404
10763
|
}
|
|
@@ -10774,7 +11133,7 @@
|
|
|
10774
11133
|
height: natH
|
|
10775
11134
|
}, w, h);
|
|
10776
11135
|
if (!canvas) {
|
|
10777
|
-
alert("Cannot crop this image: the image server does not allow cross-origin access.\nUpload the image directly to use the crop tool.");
|
|
11136
|
+
window.alert("Cannot crop this image: the image server does not allow cross-origin access.\nUpload the image directly to use the crop tool.");
|
|
10778
11137
|
this._close(false);
|
|
10779
11138
|
return;
|
|
10780
11139
|
}
|
|
@@ -11135,9 +11494,15 @@
|
|
|
11135
11494
|
if (disabled) {
|
|
11136
11495
|
editable.setAttribute("contenteditable", "false");
|
|
11137
11496
|
this.layoutInfo.container.classList.add("an-disabled");
|
|
11497
|
+
editable.querySelectorAll("ul.an-checklist input[type=\"checkbox\"]").forEach((cb) => {
|
|
11498
|
+
cb.setAttribute("disabled", "");
|
|
11499
|
+
});
|
|
11138
11500
|
} else {
|
|
11139
11501
|
editable.setAttribute("contenteditable", "true");
|
|
11140
11502
|
this.layoutInfo.container.classList.remove("an-disabled");
|
|
11503
|
+
editable.querySelectorAll("ul.an-checklist input[type=\"checkbox\"]").forEach((cb) => {
|
|
11504
|
+
cb.removeAttribute("disabled");
|
|
11505
|
+
});
|
|
11141
11506
|
}
|
|
11142
11507
|
}
|
|
11143
11508
|
/**
|