autumnnote 1.0.7 → 1.0.8
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 +3 -3
- package/dist/autumnnote.css +40 -4
- package/dist/autumnnote.es.js +513 -107
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.umd.js +513 -107
- package/dist/autumnnote.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/js/editing/Style.js +195 -44
- package/src/js/editing/Typing.js +2 -2
- package/src/js/module/Editor.js +14 -3
- package/src/js/module/EmojiDialog.js +11 -0
- package/src/js/module/IconDialog.js +11 -0
- package/src/js/module/ImageDialog.js +9 -5
- package/src/js/module/Placeholder.js +6 -1
- package/src/js/module/TableTooltip.js +393 -86
- package/src/styles/autumnnote.scss +50 -5
package/dist/autumnnote.es.js
CHANGED
|
@@ -566,8 +566,24 @@ function underline() {
|
|
|
566
566
|
}
|
|
567
567
|
/**
|
|
568
568
|
* Strikethrough / removes strikethrough.
|
|
569
|
+
* Falls back to manual DOM manipulation inside nested formats where
|
|
570
|
+
* execCommand's state detection is unreliable (mirrors underline() logic).
|
|
569
571
|
*/
|
|
570
|
-
|
|
572
|
+
function strikethrough() {
|
|
573
|
+
const sel = window.getSelection();
|
|
574
|
+
if (!sel || !sel.rangeCount) return;
|
|
575
|
+
let sc = sel.getRangeAt(0).startContainer;
|
|
576
|
+
if (sc.nodeType === 3) sc = sc.parentElement;
|
|
577
|
+
const sEl = sc && sc.closest && (sc.closest("s") || sc.closest("strike"));
|
|
578
|
+
const nativeState = document.queryCommandState("strikeThrough");
|
|
579
|
+
if (sEl && !nativeState) {
|
|
580
|
+
const parent = sEl.parentNode;
|
|
581
|
+
while (sEl.firstChild) parent.insertBefore(sEl.firstChild, sEl);
|
|
582
|
+
parent.removeChild(sEl);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
execCommand("strikeThrough");
|
|
586
|
+
}
|
|
571
587
|
/**
|
|
572
588
|
* Superscript toggle.
|
|
573
589
|
*/
|
|
@@ -600,6 +616,22 @@ var fontName = (name) => execCommand("fontName", name);
|
|
|
600
616
|
function fontSize(size, editable = document) {
|
|
601
617
|
const sel = window.getSelection();
|
|
602
618
|
const wasCollapsed = !sel || !sel.rangeCount || sel.getRangeAt(0).collapsed;
|
|
619
|
+
if (wasCollapsed && sel && sel.rangeCount > 0) {
|
|
620
|
+
try {
|
|
621
|
+
const range = sel.getRangeAt(0);
|
|
622
|
+
const span = document.createElement("span");
|
|
623
|
+
span.style.fontSize = size;
|
|
624
|
+
const zwsNode = document.createTextNode("");
|
|
625
|
+
span.appendChild(zwsNode);
|
|
626
|
+
range.insertNode(span);
|
|
627
|
+
const nr = document.createRange();
|
|
628
|
+
nr.setStart(zwsNode, zwsNode.textContent.length);
|
|
629
|
+
nr.collapse(true);
|
|
630
|
+
sel.removeAllRanges();
|
|
631
|
+
sel.addRange(nr);
|
|
632
|
+
} catch (_) {}
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
603
635
|
execCommand("fontSize", "7");
|
|
604
636
|
const scope = editable instanceof HTMLElement ? editable : document;
|
|
605
637
|
const newSpans = [];
|
|
@@ -611,27 +643,17 @@ function fontSize(size, editable = document) {
|
|
|
611
643
|
el.parentNode.removeChild(el);
|
|
612
644
|
newSpans.push(span);
|
|
613
645
|
});
|
|
614
|
-
if (sel && newSpans.length > 0) {
|
|
646
|
+
if (!wasCollapsed && sel && newSpans.length > 0) {
|
|
615
647
|
const first = newSpans[0];
|
|
616
648
|
const last = newSpans[newSpans.length - 1];
|
|
617
649
|
try {
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
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
|
-
}
|
|
650
|
+
const nr = document.createRange();
|
|
651
|
+
const startNode = first.firstChild || first;
|
|
652
|
+
const endNode = last.lastChild || last;
|
|
653
|
+
nr.setStart(startNode, 0);
|
|
654
|
+
nr.setEnd(endNode, endNode.nodeType === Node.TEXT_NODE ? endNode.textContent.length : endNode.childNodes.length);
|
|
655
|
+
sel.removeAllRanges();
|
|
656
|
+
sel.addRange(nr);
|
|
635
657
|
} catch (_) {}
|
|
636
658
|
}
|
|
637
659
|
}
|
|
@@ -662,8 +684,57 @@ var justifyFull = () => execCommand("justifyFull");
|
|
|
662
684
|
var indent = () => execCommand("indent");
|
|
663
685
|
/**
|
|
664
686
|
* Outdents the list or block.
|
|
687
|
+
* G.5: When cursor is inside a checklist item, "outdent" means converting
|
|
688
|
+
* that item back to a regular <p> element rather than calling execCommand
|
|
689
|
+
* (which would destroy the ul > li checklist structure).
|
|
665
690
|
*/
|
|
666
|
-
|
|
691
|
+
function outdent() {
|
|
692
|
+
const sel = window.getSelection();
|
|
693
|
+
if (sel && sel.rangeCount) {
|
|
694
|
+
let container = sel.getRangeAt(0).commonAncestorContainer;
|
|
695
|
+
if (container.nodeType === 3) container = container.parentElement;
|
|
696
|
+
const checkLi = container && container.closest && container.closest(".an-checklist li");
|
|
697
|
+
if (checkLi) {
|
|
698
|
+
_checklistItemToP(checkLi);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
execCommand("outdent");
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* G.5 helper: splits a checklist at checkLi, converts it to a <p>,
|
|
706
|
+
* and keeps items before/after as separate checklists.
|
|
707
|
+
* @param {HTMLElement} checkLi
|
|
708
|
+
*/
|
|
709
|
+
function _checklistItemToP(checkLi) {
|
|
710
|
+
const checkUl = checkLi.closest(".an-checklist");
|
|
711
|
+
if (!checkUl) return;
|
|
712
|
+
const allLis = Array.from(checkUl.children);
|
|
713
|
+
const liIndex = allLis.indexOf(checkLi);
|
|
714
|
+
const afterLis = allLis.slice(liIndex + 1);
|
|
715
|
+
const p = document.createElement("p");
|
|
716
|
+
p.textContent = Array.from(checkLi.childNodes).filter((n) => !(n.nodeType === 1 && n.tagName === "INPUT")).map((n) => n.textContent).join("").replace(/\u200B/g, "").trim() || "\xA0";
|
|
717
|
+
if (afterLis.length > 0) {
|
|
718
|
+
const newUl = document.createElement("ul");
|
|
719
|
+
newUl.className = "an-checklist";
|
|
720
|
+
afterLis.forEach((li) => newUl.appendChild(li));
|
|
721
|
+
checkUl.parentNode.insertBefore(newUl, checkUl.nextSibling);
|
|
722
|
+
}
|
|
723
|
+
checkUl.parentNode.insertBefore(p, checkUl.nextSibling);
|
|
724
|
+
checkUl.removeChild(checkLi);
|
|
725
|
+
if (checkUl.children.length === 0) checkUl.parentNode.removeChild(checkUl);
|
|
726
|
+
try {
|
|
727
|
+
const nr = document.createRange();
|
|
728
|
+
const firstChild = p.firstChild;
|
|
729
|
+
nr.setStart(firstChild && firstChild.nodeType === 3 ? firstChild : p, 0);
|
|
730
|
+
nr.collapse(true);
|
|
731
|
+
const s = window.getSelection();
|
|
732
|
+
if (s) {
|
|
733
|
+
s.removeAllRanges();
|
|
734
|
+
s.addRange(nr);
|
|
735
|
+
}
|
|
736
|
+
} catch {}
|
|
737
|
+
}
|
|
667
738
|
/**
|
|
668
739
|
* Inserts an unordered list or converts selection.
|
|
669
740
|
*/
|
|
@@ -867,10 +938,60 @@ function toggleChecklist() {
|
|
|
867
938
|
sel.addRange(nr);
|
|
868
939
|
return;
|
|
869
940
|
}
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
941
|
+
if (!sel.toString().replace(/[\u00a0\u200B]/g, " ").trim()) return;
|
|
942
|
+
const BLOCK_TAGS_MULTI = new Set([
|
|
943
|
+
"P",
|
|
944
|
+
"DIV",
|
|
945
|
+
"H1",
|
|
946
|
+
"H2",
|
|
947
|
+
"H3",
|
|
948
|
+
"H4",
|
|
949
|
+
"H5",
|
|
950
|
+
"H6",
|
|
951
|
+
"BLOCKQUOTE",
|
|
952
|
+
"PRE",
|
|
953
|
+
"LI"
|
|
954
|
+
]);
|
|
955
|
+
const blocks = [];
|
|
956
|
+
const seenBlocks = /* @__PURE__ */ new Set();
|
|
957
|
+
const commonAncestor = range.commonAncestorContainer;
|
|
958
|
+
const iter = document.createNodeIterator(commonAncestor.nodeType === Node.TEXT_NODE ? commonAncestor.parentNode : commonAncestor, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, null);
|
|
959
|
+
let node;
|
|
960
|
+
while (node = iter.nextNode()) {
|
|
961
|
+
if (!range.intersectsNode(node)) continue;
|
|
962
|
+
let block = node.nodeType === Node.TEXT_NODE ? node.parentElement : node;
|
|
963
|
+
while (block && !BLOCK_TAGS_MULTI.has(block.tagName)) block = block.parentElement;
|
|
964
|
+
if (block && !seenBlocks.has(block)) {
|
|
965
|
+
seenBlocks.add(block);
|
|
966
|
+
blocks.push(block);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
if (blocks.length === 0) return;
|
|
970
|
+
const newUl = document.createElement("ul");
|
|
971
|
+
newUl.className = "an-checklist";
|
|
972
|
+
let lastTextNode = null;
|
|
973
|
+
blocks.forEach((block) => {
|
|
974
|
+
const li = document.createElement("li");
|
|
975
|
+
const cb = document.createElement("input");
|
|
976
|
+
cb.type = "checkbox";
|
|
977
|
+
cb.setAttribute("contenteditable", "false");
|
|
978
|
+
li.appendChild(cb);
|
|
979
|
+
const blockText = Array.from(block.childNodes).map((n) => n.textContent).join("").replace(/[\u00a0\u200B]/g, " ").trim();
|
|
980
|
+
const tn = document.createTextNode(blockText || "");
|
|
981
|
+
li.appendChild(tn);
|
|
982
|
+
newUl.appendChild(li);
|
|
983
|
+
lastTextNode = tn;
|
|
984
|
+
});
|
|
985
|
+
const firstBlock = blocks[0];
|
|
986
|
+
firstBlock.parentNode.insertBefore(newUl, firstBlock);
|
|
987
|
+
blocks.forEach((block) => block.parentNode && block.parentNode.removeChild(block));
|
|
988
|
+
if (lastTextNode) {
|
|
989
|
+
const nr = document.createRange();
|
|
990
|
+
nr.setStart(lastTextNode, lastTextNode.textContent.length);
|
|
991
|
+
nr.collapse(true);
|
|
992
|
+
sel.removeAllRanges();
|
|
993
|
+
sel.addRange(nr);
|
|
994
|
+
}
|
|
874
995
|
}
|
|
875
996
|
/**
|
|
876
997
|
* Returns true when the cursor is inside a checklist item.
|
|
@@ -1958,7 +2079,7 @@ function handleKeydown(event, editable, options = {}) {
|
|
|
1958
2079
|
const para = closestPara(range.sc, editable);
|
|
1959
2080
|
if (para && isLi(para)) {
|
|
1960
2081
|
event.preventDefault();
|
|
1961
|
-
if (event.shiftKey)
|
|
2082
|
+
if (event.shiftKey) outdent();
|
|
1962
2083
|
else execCommand("indent");
|
|
1963
2084
|
return true;
|
|
1964
2085
|
}
|
|
@@ -2379,7 +2500,12 @@ var Editor = class {
|
|
|
2379
2500
|
};
|
|
2380
2501
|
const isReadOnly = () => this.context.layoutInfo.container.classList.contains("an-disabled");
|
|
2381
2502
|
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())
|
|
2503
|
+
if (isReadOnly()) {
|
|
2504
|
+
e.preventDefault();
|
|
2505
|
+
return;
|
|
2506
|
+
}
|
|
2507
|
+
const target = e.target;
|
|
2508
|
+
if (target && (target.nodeName === "IFRAME" || target.closest && target.closest(".an-video-wrapper"))) e.preventDefault();
|
|
2383
2509
|
}), on(editable, "drop", (e) => {
|
|
2384
2510
|
if (isReadOnly()) e.preventDefault();
|
|
2385
2511
|
}));
|
|
@@ -2536,7 +2662,7 @@ var Editor = class {
|
|
|
2536
2662
|
* @param {string} html - HTML string (will be sanitised)
|
|
2537
2663
|
*/
|
|
2538
2664
|
setHTML(html) {
|
|
2539
|
-
this.context.layoutInfo.editable.innerHTML = sanitiseHTML(html);
|
|
2665
|
+
this.context.layoutInfo.editable.innerHTML = sanitiseHTML(html, { allowIframes: true });
|
|
2540
2666
|
if (this._history) this._history.reset();
|
|
2541
2667
|
this.afterCommand();
|
|
2542
2668
|
}
|
|
@@ -3911,7 +4037,7 @@ var Placeholder = class {
|
|
|
3911
4037
|
_update() {
|
|
3912
4038
|
const editable = this.context.layoutInfo.editable;
|
|
3913
4039
|
const isFocused = document.activeElement === editable;
|
|
3914
|
-
const isEmpty = !editable.textContent.trim() && !editable.querySelector("img, table, hr, .an-video-wrapper");
|
|
4040
|
+
const isEmpty = !(editable.textContent.replace(/\u200B/g, "").trim().length > 0) && !editable.querySelector("img, table, hr, .an-video-wrapper");
|
|
3915
4041
|
editable.classList.toggle("an-placeholder", isEmpty && !isFocused);
|
|
3916
4042
|
}
|
|
3917
4043
|
};
|
|
@@ -4346,7 +4472,7 @@ var ImageDialog = class {
|
|
|
4346
4472
|
const fileInput = createElement("input", {
|
|
4347
4473
|
type: "file",
|
|
4348
4474
|
class: "an-input",
|
|
4349
|
-
accept: "image
|
|
4475
|
+
accept: "image/jpeg,image/png,image/gif,image/webp,image/svg+xml,image/avif"
|
|
4350
4476
|
});
|
|
4351
4477
|
this._fileInput = fileInput;
|
|
4352
4478
|
const fileHint = createElement("p", { class: "an-dialog-hint" });
|
|
@@ -4393,14 +4519,15 @@ var ImageDialog = class {
|
|
|
4393
4519
|
_onFileChange() {
|
|
4394
4520
|
const file = this._fileInput && this._fileInput.files && this._fileInput.files[0];
|
|
4395
4521
|
if (!file || !file.type.startsWith("image/")) return;
|
|
4396
|
-
if ([
|
|
4397
|
-
"image/
|
|
4398
|
-
"image/
|
|
4399
|
-
"image/
|
|
4400
|
-
"image/
|
|
4401
|
-
"image/
|
|
4402
|
-
|
|
4403
|
-
|
|
4522
|
+
if (!new Set([
|
|
4523
|
+
"image/jpeg",
|
|
4524
|
+
"image/png",
|
|
4525
|
+
"image/gif",
|
|
4526
|
+
"image/webp",
|
|
4527
|
+
"image/svg+xml",
|
|
4528
|
+
"image/avif"
|
|
4529
|
+
]).has(file.type)) {
|
|
4530
|
+
const message = `Format "${file.type}" is not supported for display in web browsers. Please convert to JPEG, PNG, or WebP first.`;
|
|
4404
4531
|
if (this._fileHint) this._fileHint.textContent = message;
|
|
4405
4532
|
this.context.triggerEvent("imageError", {
|
|
4406
4533
|
file,
|
|
@@ -5854,6 +5981,47 @@ function getCellAfterVisualCol(row, visualIdx) {
|
|
|
5854
5981
|
}
|
|
5855
5982
|
return null;
|
|
5856
5983
|
}
|
|
5984
|
+
/**
|
|
5985
|
+
* Build a 2D grid map of the table, accounting for both rowspan and colspan.
|
|
5986
|
+
*
|
|
5987
|
+
* gridMap[r][c] = the DOM cell occupying visual grid position (r, c).
|
|
5988
|
+
* cellPos = WeakMap: cell → { r, c, rs, cs } (top-left grid origin + span).
|
|
5989
|
+
*
|
|
5990
|
+
* Uses HTMLTableElement.rows which is scoped to the table itself and never
|
|
5991
|
+
* includes rows from nested tables.
|
|
5992
|
+
*
|
|
5993
|
+
* @param {HTMLTableElement} table
|
|
5994
|
+
* @returns {{ gridMap: Object, cellPos: WeakMap }}
|
|
5995
|
+
*/
|
|
5996
|
+
function buildGridMap(table) {
|
|
5997
|
+
const rows = Array.from(table.rows);
|
|
5998
|
+
const gridMap = {};
|
|
5999
|
+
const cellPos = /* @__PURE__ */ new WeakMap();
|
|
6000
|
+
rows.forEach((row, r) => {
|
|
6001
|
+
if (!gridMap[r]) gridMap[r] = {};
|
|
6002
|
+
let c = 0;
|
|
6003
|
+
for (const cell of row.cells) {
|
|
6004
|
+
while (gridMap[r][c]) c++;
|
|
6005
|
+
const rs = cell.rowSpan || 1;
|
|
6006
|
+
const cs = cell.colSpan || 1;
|
|
6007
|
+
cellPos.set(cell, {
|
|
6008
|
+
r,
|
|
6009
|
+
c,
|
|
6010
|
+
rs,
|
|
6011
|
+
cs
|
|
6012
|
+
});
|
|
6013
|
+
for (let dr = 0; dr < rs; dr++) {
|
|
6014
|
+
if (!gridMap[r + dr]) gridMap[r + dr] = {};
|
|
6015
|
+
for (let dc = 0; dc < cs; dc++) gridMap[r + dr][c + dc] = cell;
|
|
6016
|
+
}
|
|
6017
|
+
c += cs;
|
|
6018
|
+
}
|
|
6019
|
+
});
|
|
6020
|
+
return {
|
|
6021
|
+
gridMap,
|
|
6022
|
+
cellPos
|
|
6023
|
+
};
|
|
6024
|
+
}
|
|
5857
6025
|
var ICONS$2 = {
|
|
5858
6026
|
rowAbove: `<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="12" x2="21" y2="12"/><path d="M12 3v7"/><path d="M9 7l3-4 3 4"/></svg>`,
|
|
5859
6027
|
rowBelow: `<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="12" x2="21" y2="12"/><path d="M12 12v7"/><path d="M9 17l3 4 3-4"/></svg>`,
|
|
@@ -5862,10 +6030,12 @@ var ICONS$2 = {
|
|
|
5862
6030
|
colRight: `<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="12" y1="3" x2="12" y2="21"/><path d="M12 12h9"/><path d="M17 8l4 4-4 4"/></svg>`,
|
|
5863
6031
|
deleteCol: `<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="12" y1="3" x2="12" y2="21"/><line x1="15" y1="6" x2="21" y2="12"/><line x1="21" y1="6" x2="15" y2="12"/></svg>`,
|
|
5864
6032
|
mergeCells: `<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="2" y="7" width="8" height="10" rx="1"/><rect x="14" y="7" width="8" height="10" rx="1"/><path d="M10 12h4"/><path d="M12 10l2 2-2 2"/></svg>`,
|
|
6033
|
+
unmergeCells: `<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="2" y="5" width="20" height="14" rx="1"/><line x1="12" y1="5" x2="12" y2="19" stroke-dasharray="2.5 2"/><line x1="2" y1="12" x2="22" y2="12" stroke-dasharray="2.5 2"/><path d="M9 9 L6 12 L9 15"/><path d="M15 9 L18 12 L15 15"/></svg>`,
|
|
5865
6034
|
colWidth: `<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="7" y1="4" x2="7" y2="20"/><line x1="17" y1="4" x2="17" y2="20"/><line x1="7" y1="12" x2="17" y2="12"/><path d="M10 9l-3 3 3 3"/><path d="M14 9l3 3-3 3"/></svg>`,
|
|
5866
6035
|
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>`,
|
|
5867
6036
|
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>`,
|
|
5868
|
-
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
|
|
6037
|
+
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>`,
|
|
6038
|
+
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>`
|
|
5869
6039
|
};
|
|
5870
6040
|
var TableTooltip = class {
|
|
5871
6041
|
/** @param {import('../Context.js').Context} context */
|
|
@@ -5881,6 +6051,12 @@ var TableTooltip = class {
|
|
|
5881
6051
|
this._sizeApply = null;
|
|
5882
6052
|
this._sizeTitleEl = null;
|
|
5883
6053
|
this._sizeInputEl = null;
|
|
6054
|
+
this._selectMode = false;
|
|
6055
|
+
this._selectedCells = [];
|
|
6056
|
+
this._selectStart = null;
|
|
6057
|
+
this._selectDragging = false;
|
|
6058
|
+
this._selectBtn = null;
|
|
6059
|
+
this._editable = null;
|
|
5884
6060
|
}
|
|
5885
6061
|
initialize() {
|
|
5886
6062
|
this._el = this._buildTooltip();
|
|
@@ -5888,6 +6064,29 @@ var TableTooltip = class {
|
|
|
5888
6064
|
this._sizePopover = this._buildSizePopover();
|
|
5889
6065
|
document.body.appendChild(this._sizePopover);
|
|
5890
6066
|
const editable = this.context.layoutInfo.editable;
|
|
6067
|
+
this._editable = editable;
|
|
6068
|
+
const onSelMousedown = (e) => {
|
|
6069
|
+
if (!this._selectMode) return;
|
|
6070
|
+
const cell = e.target.closest("td, th");
|
|
6071
|
+
if (!cell || !editable.contains(cell)) return;
|
|
6072
|
+
if (cell.style.cursor === "col-resize" || cell.style.cursor === "row-resize") return;
|
|
6073
|
+
e.preventDefault();
|
|
6074
|
+
this._activeTable = cell.closest("table");
|
|
6075
|
+
this._selectStart = cell;
|
|
6076
|
+
this._selectDragging = true;
|
|
6077
|
+
this._setSelection([cell]);
|
|
6078
|
+
};
|
|
6079
|
+
const onSelMousemove = (e) => {
|
|
6080
|
+
if (!this._selectMode || !this._selectDragging || !this._selectStart) return;
|
|
6081
|
+
const cell = e.target.closest("td, th");
|
|
6082
|
+
if (!cell || !editable.contains(cell)) return;
|
|
6083
|
+
if (cell.closest("table") !== this._activeTable) return;
|
|
6084
|
+
this._setSelection(this._getRectCells(this._selectStart, cell));
|
|
6085
|
+
};
|
|
6086
|
+
const onSelMouseup = () => {
|
|
6087
|
+
this._selectDragging = false;
|
|
6088
|
+
};
|
|
6089
|
+
this._disposers.push(on(editable, "mousedown", onSelMousedown), on(editable, "mousemove", onSelMousemove), on(document, "mouseup", onSelMouseup));
|
|
5891
6090
|
this._disposers.push(on(editable, "mouseover", (e) => {
|
|
5892
6091
|
if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
|
|
5893
6092
|
const table = e.target.closest("table");
|
|
@@ -5897,9 +6096,11 @@ var TableTooltip = class {
|
|
|
5897
6096
|
this._scheduleShow(table);
|
|
5898
6097
|
}
|
|
5899
6098
|
}, { passive: true }), on(editable, "mouseout", (e) => {
|
|
6099
|
+
if (this._selectMode) return;
|
|
5900
6100
|
const to = e.relatedTarget;
|
|
5901
6101
|
if (!to || !editable.contains(to) && !this._el.contains(to) && !(this._sizePopover && this._sizePopover.contains(to))) this._scheduleHide();
|
|
5902
6102
|
}, { passive: true }), on(document, "click", (e) => {
|
|
6103
|
+
if (this._selectMode && this._activeTable && this._activeTable.contains(e.target)) return;
|
|
5903
6104
|
if (this._activeTable && !this._activeTable.contains(e.target) && !this._el.contains(e.target) && !(this._sizePopover && this._sizePopover.contains(e.target))) this._hide();
|
|
5904
6105
|
}));
|
|
5905
6106
|
this._initResize();
|
|
@@ -5972,7 +6173,7 @@ var TableTooltip = class {
|
|
|
5972
6173
|
if (_edge === "col") {
|
|
5973
6174
|
_startW = _nearCell.offsetWidth;
|
|
5974
6175
|
_colIdx = getVisualColIndex(_nearCell);
|
|
5975
|
-
_colCells = _colIdx >= 0 ? Array.from(_table.querySelectorAll("tr")).map((r) => getCellAtVisualCol(r, _colIdx)).filter(Boolean) : [];
|
|
6176
|
+
_colCells = _colIdx >= 0 ? Array.from(_table.querySelectorAll("tr")).map((r) => getCellAtVisualCol(r, _colIdx)).filter(Boolean).filter((c) => (c.colSpan || 1) === 1) : [];
|
|
5976
6177
|
document.body.style.cursor = "col-resize";
|
|
5977
6178
|
} else {
|
|
5978
6179
|
_row = _nearCell.closest("tr");
|
|
@@ -6043,6 +6244,9 @@ var TableTooltip = class {
|
|
|
6043
6244
|
this._label.textContent = "Table";
|
|
6044
6245
|
el.appendChild(this._label);
|
|
6045
6246
|
el.appendChild(this._sep());
|
|
6247
|
+
this._selectBtn = this._makeBtn(ICONS$2.selectCells, "Select Cells", () => this._toggleSelectMode());
|
|
6248
|
+
el.appendChild(this._selectBtn);
|
|
6249
|
+
el.appendChild(this._sep());
|
|
6046
6250
|
el.appendChild(this._makeBtn(ICONS$2.rowAbove, "Add Row Above", () => this._addRow("above")));
|
|
6047
6251
|
el.appendChild(this._makeBtn(ICONS$2.rowBelow, "Add Row Below", () => this._addRow("below")));
|
|
6048
6252
|
el.appendChild(this._makeBtn(ICONS$2.deleteRow, "Delete Row", () => this._deleteRow()));
|
|
@@ -6052,6 +6256,7 @@ var TableTooltip = class {
|
|
|
6052
6256
|
el.appendChild(this._makeBtn(ICONS$2.deleteCol, "Delete Column", () => this._deleteColumn()));
|
|
6053
6257
|
el.appendChild(this._sep());
|
|
6054
6258
|
el.appendChild(this._makeBtn(ICONS$2.mergeCells, "Merge Cells", () => this._mergeCells()));
|
|
6259
|
+
el.appendChild(this._makeBtn(ICONS$2.unmergeCells, "Unmerge Cells", () => this._unmergeCells()));
|
|
6055
6260
|
el.appendChild(this._sep());
|
|
6056
6261
|
el.appendChild(this._makeBtn(ICONS$2.colWidth, "Column Width", () => this._openSizePopover("col")));
|
|
6057
6262
|
el.appendChild(this._makeBtn(ICONS$2.rowHeight, "Row Height", () => this._openSizePopover("row")));
|
|
@@ -6059,6 +6264,7 @@ var TableTooltip = class {
|
|
|
6059
6264
|
el.appendChild(this._sep());
|
|
6060
6265
|
el.appendChild(this._makeBtn(ICONS$2.deleteTable, "Delete Table", () => this._deleteTable(), true));
|
|
6061
6266
|
this._disposers.push(on(el, "mouseenter", () => this._clearTimers()), on(el, "mouseleave", () => {
|
|
6267
|
+
if (this._selectMode) return;
|
|
6062
6268
|
if (this._sizePopover && this._sizePopover.style.display !== "none") return;
|
|
6063
6269
|
this._scheduleHide();
|
|
6064
6270
|
}));
|
|
@@ -6114,6 +6320,12 @@ var TableTooltip = class {
|
|
|
6114
6320
|
this._el.style.display = "none";
|
|
6115
6321
|
this._activeTable = null;
|
|
6116
6322
|
this._activeCell = null;
|
|
6323
|
+
if (this._selectMode) {
|
|
6324
|
+
this._selectMode = false;
|
|
6325
|
+
if (this._selectBtn) this._selectBtn.classList.remove("an-link-tooltip-btn--active");
|
|
6326
|
+
if (this._editable) this._editable.classList.remove("an-table-select-mode");
|
|
6327
|
+
}
|
|
6328
|
+
this._clearSelection();
|
|
6117
6329
|
this._clearTimers();
|
|
6118
6330
|
this._hideSizePopover();
|
|
6119
6331
|
}
|
|
@@ -6147,14 +6359,111 @@ var TableTooltip = class {
|
|
|
6147
6359
|
}
|
|
6148
6360
|
return this._activeCell || this._activeTable && this._activeTable.querySelector("td, th");
|
|
6149
6361
|
}
|
|
6362
|
+
_toggleSelectMode() {
|
|
6363
|
+
this._selectMode = !this._selectMode;
|
|
6364
|
+
if (this._selectBtn) this._selectBtn.classList.toggle("an-link-tooltip-btn--active", this._selectMode);
|
|
6365
|
+
if (this._editable) this._editable.classList.toggle("an-table-select-mode", this._selectMode);
|
|
6366
|
+
if (!this._selectMode) this._clearSelection();
|
|
6367
|
+
}
|
|
6368
|
+
_clearSelection() {
|
|
6369
|
+
this._selectedCells.forEach((c) => c.classList.remove("an-cell-selected"));
|
|
6370
|
+
this._selectedCells = [];
|
|
6371
|
+
this._selectStart = null;
|
|
6372
|
+
}
|
|
6373
|
+
_setSelection(cells) {
|
|
6374
|
+
this._selectedCells.forEach((c) => {
|
|
6375
|
+
if (!cells.includes(c)) c.classList.remove("an-cell-selected");
|
|
6376
|
+
});
|
|
6377
|
+
this._selectedCells = cells;
|
|
6378
|
+
cells.forEach((c) => c.classList.add("an-cell-selected"));
|
|
6379
|
+
}
|
|
6380
|
+
/**
|
|
6381
|
+
* Returns all cells in the rectangular area between startCell and endCell,
|
|
6382
|
+
* correctly handling rowspan/colspan by using the grid map.
|
|
6383
|
+
* The rect is expanded iteratively until it is stable — this ensures any
|
|
6384
|
+
* merged cell that starts outside the initial rect but spans into it is
|
|
6385
|
+
* fully included.
|
|
6386
|
+
*/
|
|
6387
|
+
_getRectCells(startCell, endCell) {
|
|
6388
|
+
if (!startCell) return [];
|
|
6389
|
+
if (!endCell || startCell === endCell) return [startCell];
|
|
6390
|
+
const table = startCell.closest("table");
|
|
6391
|
+
if (!table || !table.contains(endCell)) return [startCell];
|
|
6392
|
+
const { gridMap, cellPos } = buildGridMap(table);
|
|
6393
|
+
const sp = cellPos.get(startCell);
|
|
6394
|
+
const ep = cellPos.get(endCell);
|
|
6395
|
+
if (!sp || !ep) return [startCell];
|
|
6396
|
+
let minR = Math.min(sp.r, ep.r);
|
|
6397
|
+
let maxR = Math.max(sp.r + sp.rs - 1, ep.r + ep.rs - 1);
|
|
6398
|
+
let minC = Math.min(sp.c, ep.c);
|
|
6399
|
+
let maxC = Math.max(sp.c + sp.cs - 1, ep.c + ep.cs - 1);
|
|
6400
|
+
let changed = true;
|
|
6401
|
+
while (changed) {
|
|
6402
|
+
changed = false;
|
|
6403
|
+
for (let r = minR; r <= maxR; r++) {
|
|
6404
|
+
const rowMap = gridMap[r];
|
|
6405
|
+
if (!rowMap) continue;
|
|
6406
|
+
for (let c = minC; c <= maxC; c++) {
|
|
6407
|
+
const cell = rowMap[c];
|
|
6408
|
+
if (!cell) continue;
|
|
6409
|
+
const pos = cellPos.get(cell);
|
|
6410
|
+
if (!pos) continue;
|
|
6411
|
+
if (pos.r < minR) {
|
|
6412
|
+
minR = pos.r;
|
|
6413
|
+
changed = true;
|
|
6414
|
+
}
|
|
6415
|
+
if (pos.r + pos.rs - 1 > maxR) {
|
|
6416
|
+
maxR = pos.r + pos.rs - 1;
|
|
6417
|
+
changed = true;
|
|
6418
|
+
}
|
|
6419
|
+
if (pos.c < minC) {
|
|
6420
|
+
minC = pos.c;
|
|
6421
|
+
changed = true;
|
|
6422
|
+
}
|
|
6423
|
+
if (pos.c + pos.cs - 1 > maxC) {
|
|
6424
|
+
maxC = pos.c + pos.cs - 1;
|
|
6425
|
+
changed = true;
|
|
6426
|
+
}
|
|
6427
|
+
}
|
|
6428
|
+
}
|
|
6429
|
+
}
|
|
6430
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6431
|
+
const result = [];
|
|
6432
|
+
for (let r = minR; r <= maxR; r++) {
|
|
6433
|
+
const rowMap = gridMap[r];
|
|
6434
|
+
if (!rowMap) continue;
|
|
6435
|
+
for (let c = minC; c <= maxC; c++) {
|
|
6436
|
+
const cell = rowMap[c];
|
|
6437
|
+
if (cell && !seen.has(cell)) {
|
|
6438
|
+
seen.add(cell);
|
|
6439
|
+
result.push(cell);
|
|
6440
|
+
}
|
|
6441
|
+
}
|
|
6442
|
+
}
|
|
6443
|
+
return result.length > 0 ? result : [startCell];
|
|
6444
|
+
}
|
|
6445
|
+
/**
|
|
6446
|
+
* Returns the active cell set: user-selected cells when available,
|
|
6447
|
+
* otherwise the single active/cursor cell.
|
|
6448
|
+
* @returns {HTMLTableCellElement[]}
|
|
6449
|
+
*/
|
|
6450
|
+
_getSelectedCells() {
|
|
6451
|
+
return this._selectedCells.length > 0 ? this._selectedCells : [this._getCell()].filter(Boolean);
|
|
6452
|
+
}
|
|
6150
6453
|
_addRow(position) {
|
|
6151
|
-
const
|
|
6152
|
-
if (!
|
|
6153
|
-
const
|
|
6154
|
-
if (!
|
|
6155
|
-
const
|
|
6454
|
+
const cells = this._getSelectedCells();
|
|
6455
|
+
if (!cells.length) return;
|
|
6456
|
+
const table = cells[0].closest("table");
|
|
6457
|
+
if (!table) return;
|
|
6458
|
+
const allRows = Array.from(table.querySelectorAll("tr"));
|
|
6459
|
+
const refRow = [...new Set(cells.map((c) => c.closest("tr")).filter(Boolean))].reduce((best, r) => {
|
|
6460
|
+
const bi = allRows.indexOf(best);
|
|
6461
|
+
const ri = allRows.indexOf(r);
|
|
6462
|
+
return position === "above" ? ri < bi ? r : best : ri > bi ? r : best;
|
|
6463
|
+
});
|
|
6464
|
+
const colCount = Array.from(refRow.cells).reduce((sum, c) => sum + (c.colSpan || 1), 0);
|
|
6156
6465
|
const newRow = document.createElement("tr");
|
|
6157
|
-
const refCells = Array.from(
|
|
6466
|
+
const refCells = Array.from(refRow.cells);
|
|
6158
6467
|
for (let i = 0; i < colCount; i++) {
|
|
6159
6468
|
const td = createElement("td", {}, ["\xA0"]);
|
|
6160
6469
|
const ref = refCells[i];
|
|
@@ -6162,19 +6471,20 @@ var TableTooltip = class {
|
|
|
6162
6471
|
if (ref && ref.style.minWidth) td.style.minWidth = ref.style.minWidth;
|
|
6163
6472
|
newRow.appendChild(td);
|
|
6164
6473
|
}
|
|
6165
|
-
if (position === "above")
|
|
6166
|
-
else
|
|
6474
|
+
if (position === "above") refRow.parentElement?.insertBefore(newRow, refRow);
|
|
6475
|
+
else refRow.insertAdjacentElement("afterend", newRow);
|
|
6167
6476
|
requestAnimationFrame(() => this._positionNear(this._activeTable));
|
|
6168
6477
|
this.context.invoke("editor.afterCommand");
|
|
6169
6478
|
}
|
|
6170
6479
|
_addColumn(position) {
|
|
6171
|
-
const
|
|
6172
|
-
if (!
|
|
6173
|
-
const table =
|
|
6480
|
+
const cells = this._getSelectedCells();
|
|
6481
|
+
if (!cells.length) return;
|
|
6482
|
+
const table = cells[0].closest("table");
|
|
6174
6483
|
if (!table) return;
|
|
6175
|
-
const
|
|
6484
|
+
const colIndices = cells.map((c) => getVisualColIndex(c));
|
|
6485
|
+
const targetColIdx = position === "left" ? Math.min(...colIndices) : Math.max(...colIndices);
|
|
6176
6486
|
const rows = Array.from(table.querySelectorAll("tr"));
|
|
6177
|
-
const refs = rows.map((r) => position === "left" ? getCellAtVisualCol(r,
|
|
6487
|
+
const refs = rows.map((r) => position === "left" ? getCellAtVisualCol(r, targetColIdx) : getCellAfterVisualCol(r, targetColIdx));
|
|
6178
6488
|
const isHeaders = rows.map((r) => r.closest("thead") !== null);
|
|
6179
6489
|
rows.forEach((r, i) => {
|
|
6180
6490
|
r.insertBefore(createElement(isHeaders[i] ? "th" : "td", {}, ["\xA0"]), refs[i]);
|
|
@@ -6183,68 +6493,93 @@ var TableTooltip = class {
|
|
|
6183
6493
|
this.context.invoke("editor.afterCommand");
|
|
6184
6494
|
}
|
|
6185
6495
|
_deleteRow() {
|
|
6186
|
-
const
|
|
6187
|
-
if (!
|
|
6188
|
-
const
|
|
6189
|
-
|
|
6190
|
-
if (!row || !table) return;
|
|
6496
|
+
const cells = this._getSelectedCells();
|
|
6497
|
+
if (!cells.length) return;
|
|
6498
|
+
const table = cells[0].closest("table");
|
|
6499
|
+
if (!table) return;
|
|
6191
6500
|
const tbody = table.querySelector("tbody");
|
|
6192
|
-
|
|
6501
|
+
const totalBodyRows = tbody ? tbody.querySelectorAll("tr").length : table.querySelectorAll("tr").length;
|
|
6502
|
+
const selectedRows = [...new Set(cells.map((c) => c.closest("tr")).filter(Boolean))];
|
|
6503
|
+
if (selectedRows.filter((r) => r.closest("tbody")).length >= totalBodyRows) return;
|
|
6193
6504
|
this._activeCell = null;
|
|
6194
|
-
|
|
6505
|
+
this._clearSelection();
|
|
6506
|
+
selectedRows.forEach((r) => r.parentElement?.removeChild(r));
|
|
6195
6507
|
requestAnimationFrame(() => this._positionNear(this._activeTable));
|
|
6196
6508
|
this.context.invoke("editor.afterCommand");
|
|
6197
6509
|
}
|
|
6198
6510
|
_deleteColumn() {
|
|
6199
|
-
const
|
|
6200
|
-
if (!
|
|
6201
|
-
const table =
|
|
6511
|
+
const cells = this._getSelectedCells();
|
|
6512
|
+
if (!cells.length) return;
|
|
6513
|
+
const table = cells[0].closest("table");
|
|
6202
6514
|
if (!table) return;
|
|
6203
|
-
const
|
|
6204
|
-
if (
|
|
6205
|
-
const
|
|
6206
|
-
|
|
6207
|
-
const
|
|
6208
|
-
|
|
6209
|
-
|
|
6515
|
+
const tableRows = Array.from(table.querySelectorAll("tr"));
|
|
6516
|
+
if (tableRows[0] && tableRows[0].cells.length <= 1) return;
|
|
6517
|
+
const colIndices = [...new Set(cells.map((c) => getVisualColIndex(c)))];
|
|
6518
|
+
if (colIndices.length >= (tableRows[0]?.cells.length ?? 1)) return;
|
|
6519
|
+
const cellsToDelete = [];
|
|
6520
|
+
colIndices.forEach((colIdx) => {
|
|
6521
|
+
tableRows.forEach((r) => {
|
|
6522
|
+
const c = getCellAtVisualCol(r, colIdx);
|
|
6523
|
+
if (c) cellsToDelete.push(c);
|
|
6524
|
+
});
|
|
6210
6525
|
});
|
|
6526
|
+
this._activeCell = null;
|
|
6527
|
+
this._clearSelection();
|
|
6528
|
+
cellsToDelete.forEach((c) => c.parentElement?.removeChild(c));
|
|
6211
6529
|
requestAnimationFrame(() => this._positionNear(this._activeTable));
|
|
6212
6530
|
this.context.invoke("editor.afterCommand");
|
|
6213
6531
|
}
|
|
6214
6532
|
_mergeCells() {
|
|
6215
6533
|
const cell = this._getCell();
|
|
6216
6534
|
if (!cell) return;
|
|
6217
|
-
const sel = window.getSelection();
|
|
6218
|
-
if (!sel || sel.rangeCount === 0) return;
|
|
6219
|
-
const range = sel.getRangeAt(0);
|
|
6220
6535
|
const table = cell.closest("table");
|
|
6221
6536
|
if (!table) return;
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
const rowSelected = Array.from(row.cells).filter((c) => selected.includes(c));
|
|
6234
|
-
if (rowSelected.length < 2) return;
|
|
6235
|
-
const first = rowSelected[0];
|
|
6236
|
-
first.colSpan = rowSelected.reduce((sum, c) => sum + (c.colSpan || 1), 0);
|
|
6237
|
-
first.innerHTML = rowSelected.map((c) => c.innerHTML).join("");
|
|
6238
|
-
rowSelected.slice(1).forEach((c) => row.removeChild(c));
|
|
6239
|
-
} else {
|
|
6240
|
-
if ([...new Set(selected.map((c) => getVisualColIndex(c)))].length !== 1) return;
|
|
6241
|
-
const first = selected[0];
|
|
6242
|
-
first.rowSpan = selected.reduce((sum, c) => sum + (c.rowSpan || 1), 0);
|
|
6243
|
-
first.innerHTML = selected.map((c) => c.innerHTML).join("");
|
|
6244
|
-
selected.slice(1).forEach((c) => {
|
|
6245
|
-
if (c.closest("tr")) c.closest("tr").removeChild(c);
|
|
6537
|
+
let selected = this._getSelectedCells().filter((c) => table.contains(c));
|
|
6538
|
+
if (selected.length < 2) {
|
|
6539
|
+
const sel = window.getSelection();
|
|
6540
|
+
if (!sel || sel.rangeCount === 0) return;
|
|
6541
|
+
const range = sel.getRangeAt(0);
|
|
6542
|
+
selected = Array.from(table.querySelectorAll("td, th")).filter((c) => {
|
|
6543
|
+
try {
|
|
6544
|
+
return range.intersectsNode(c);
|
|
6545
|
+
} catch {
|
|
6546
|
+
return false;
|
|
6547
|
+
}
|
|
6246
6548
|
});
|
|
6549
|
+
if (selected.length < 2) return;
|
|
6550
|
+
}
|
|
6551
|
+
const { gridMap, cellPos } = buildGridMap(table);
|
|
6552
|
+
let minR = Infinity, maxR = -Infinity, minC = Infinity, maxC = -Infinity;
|
|
6553
|
+
selected.forEach((c) => {
|
|
6554
|
+
const pos = cellPos.get(c);
|
|
6555
|
+
if (!pos) return;
|
|
6556
|
+
if (pos.r < minR) minR = pos.r;
|
|
6557
|
+
if (pos.r + pos.rs - 1 > maxR) maxR = pos.r + pos.rs - 1;
|
|
6558
|
+
if (pos.c < minC) minC = pos.c;
|
|
6559
|
+
if (pos.c + pos.cs - 1 > maxC) maxC = pos.c + pos.cs - 1;
|
|
6560
|
+
});
|
|
6561
|
+
if (minR === Infinity) return;
|
|
6562
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6563
|
+
const rectCells = [];
|
|
6564
|
+
for (let r = minR; r <= maxR; r++) {
|
|
6565
|
+
const rowMap = gridMap[r];
|
|
6566
|
+
if (!rowMap) continue;
|
|
6567
|
+
for (let c = minC; c <= maxC; c++) {
|
|
6568
|
+
const tc = rowMap[c];
|
|
6569
|
+
if (tc && !seen.has(tc)) {
|
|
6570
|
+
seen.add(tc);
|
|
6571
|
+
rectCells.push(tc);
|
|
6572
|
+
}
|
|
6573
|
+
}
|
|
6247
6574
|
}
|
|
6575
|
+
if (rectCells.length < 2) return;
|
|
6576
|
+
const first = rectCells[0];
|
|
6577
|
+
first.colSpan = maxC - minC + 1;
|
|
6578
|
+
first.rowSpan = maxR - minR + 1;
|
|
6579
|
+
first.style.verticalAlign = "middle";
|
|
6580
|
+
first.innerHTML = rectCells.map((c) => c.innerHTML).join("");
|
|
6581
|
+
rectCells.slice(1).forEach((c) => c.parentElement?.removeChild(c));
|
|
6582
|
+
this._clearSelection();
|
|
6248
6583
|
this.context.invoke("editor.afterCommand");
|
|
6249
6584
|
}
|
|
6250
6585
|
_deleteTable() {
|
|
@@ -6254,6 +6589,57 @@ var TableTooltip = class {
|
|
|
6254
6589
|
if (table.parentNode) table.parentNode.removeChild(table);
|
|
6255
6590
|
this.context.invoke("editor.afterCommand");
|
|
6256
6591
|
}
|
|
6592
|
+
_unmergeCells() {
|
|
6593
|
+
const cells = this._getSelectedCells();
|
|
6594
|
+
if (!cells.length) return;
|
|
6595
|
+
const table = cells[0].closest("table");
|
|
6596
|
+
if (!table) return;
|
|
6597
|
+
const mergedCells = cells.filter((c) => table.contains(c) && ((c.colSpan || 1) > 1 || (c.rowSpan || 1) > 1));
|
|
6598
|
+
if (!mergedCells.length) return;
|
|
6599
|
+
mergedCells.forEach((cell) => {
|
|
6600
|
+
if (table.contains(cell)) this._unmergeOne(cell, table);
|
|
6601
|
+
});
|
|
6602
|
+
this._clearSelection();
|
|
6603
|
+
requestAnimationFrame(() => this._positionNear(this._activeTable));
|
|
6604
|
+
this.context.invoke("editor.afterCommand");
|
|
6605
|
+
}
|
|
6606
|
+
/**
|
|
6607
|
+
* Split a single merged cell (colspan/rowspan > 1) back into individual cells.
|
|
6608
|
+
* New cells are empty ( ); the original cell retains its content.
|
|
6609
|
+
* @param {HTMLTableCellElement} cell
|
|
6610
|
+
* @param {HTMLTableElement} table
|
|
6611
|
+
*/
|
|
6612
|
+
_unmergeOne(cell, table) {
|
|
6613
|
+
const cs = cell.colSpan || 1;
|
|
6614
|
+
const rs = cell.rowSpan || 1;
|
|
6615
|
+
if (cs === 1 && rs === 1) return;
|
|
6616
|
+
const { cellPos } = buildGridMap(table);
|
|
6617
|
+
const pos = cellPos.get(cell);
|
|
6618
|
+
if (!pos) return;
|
|
6619
|
+
const { r, c } = pos;
|
|
6620
|
+
const tableRows = Array.from(table.rows);
|
|
6621
|
+
const tag = cell.tagName.toLowerCase();
|
|
6622
|
+
cell.rowSpan = 1;
|
|
6623
|
+
cell.colSpan = 1;
|
|
6624
|
+
cell.style.verticalAlign = "";
|
|
6625
|
+
if (cs > 1) {
|
|
6626
|
+
const insertRef = cell.nextElementSibling;
|
|
6627
|
+
for (let dc = 1; dc < cs; dc++) tableRows[r].insertBefore(createElement(tag, {}, ["\xA0"]), insertRef);
|
|
6628
|
+
}
|
|
6629
|
+
for (let dr = 1; dr < rs; dr++) {
|
|
6630
|
+
const targetRow = tableRows[r + dr];
|
|
6631
|
+
if (!targetRow) continue;
|
|
6632
|
+
let ref = null;
|
|
6633
|
+
for (const tc of targetRow.cells) {
|
|
6634
|
+
const tp = cellPos.get(tc);
|
|
6635
|
+
if (tp && tp.c > c) {
|
|
6636
|
+
ref = tc;
|
|
6637
|
+
break;
|
|
6638
|
+
}
|
|
6639
|
+
}
|
|
6640
|
+
for (let dc = 0; dc < cs; dc++) targetRow.insertBefore(createElement(tag, {}, ["\xA0"]), ref);
|
|
6641
|
+
}
|
|
6642
|
+
}
|
|
6257
6643
|
_buildSizePopover() {
|
|
6258
6644
|
const popover = createElement("div", { class: "an-size-popover" });
|
|
6259
6645
|
popover.style.display = "none";
|
|
@@ -6335,27 +6721,35 @@ var TableTooltip = class {
|
|
|
6335
6721
|
};
|
|
6336
6722
|
} else {
|
|
6337
6723
|
const isCol = type === "col";
|
|
6724
|
+
const activeCells = this._getSelectedCells().filter((c) => {
|
|
6725
|
+
const t = c.closest("table");
|
|
6726
|
+
return t && t === cell.closest("table");
|
|
6727
|
+
});
|
|
6338
6728
|
this._sizeTitleEl.textContent = isCol ? "Column Width (px)" : "Row Height (px)";
|
|
6339
6729
|
this._sizeInputEl.min = "1";
|
|
6340
6730
|
this._sizeInputEl.max = "2000";
|
|
6341
6731
|
this._sizeInputEl.value = isCol ? cell.offsetWidth || 120 : cell.closest("tr") ? cell.closest("tr").offsetHeight || 40 : 40;
|
|
6342
6732
|
this._sizeApply = (val) => {
|
|
6733
|
+
const table = cell.closest("table");
|
|
6734
|
+
if (!table) return;
|
|
6343
6735
|
if (isCol) {
|
|
6344
|
-
const
|
|
6345
|
-
const
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
c
|
|
6349
|
-
c.
|
|
6350
|
-
|
|
6736
|
+
const colIndices = [...new Set(activeCells.map((c) => getVisualColIndex(c)))];
|
|
6737
|
+
const tableRows = Array.from(table.querySelectorAll("tr"));
|
|
6738
|
+
colIndices.forEach((colIdx) => {
|
|
6739
|
+
tableRows.forEach((r) => {
|
|
6740
|
+
const c = getCellAtVisualCol(r, colIdx);
|
|
6741
|
+
if (c && (c.colSpan || 1) === 1) {
|
|
6742
|
+
c.style.width = `${val}px`;
|
|
6743
|
+
c.style.minWidth = `${val}px`;
|
|
6744
|
+
}
|
|
6745
|
+
});
|
|
6351
6746
|
});
|
|
6352
|
-
} else {
|
|
6353
|
-
const
|
|
6354
|
-
if (row) for (const c of row.cells) {
|
|
6747
|
+
} else [...new Set(activeCells.map((c) => c.closest("tr")).filter(Boolean))].forEach((row) => {
|
|
6748
|
+
for (const c of row.cells) {
|
|
6355
6749
|
c.style.height = `${val}px`;
|
|
6356
6750
|
c.style.minHeight = `${val}px`;
|
|
6357
6751
|
}
|
|
6358
|
-
}
|
|
6752
|
+
});
|
|
6359
6753
|
this.context.invoke("editor.afterCommand");
|
|
6360
6754
|
};
|
|
6361
6755
|
}
|
|
@@ -9210,7 +9604,13 @@ var EmojiDialog = class {
|
|
|
9210
9604
|
range.selectNodeContents(editable);
|
|
9211
9605
|
range.collapse(false);
|
|
9212
9606
|
}
|
|
9607
|
+
const _sc = range.startContainer;
|
|
9608
|
+
const _tdAnchor = (_sc.nodeType === 1 ? _sc : _sc.parentElement)?.closest?.("td, th");
|
|
9213
9609
|
range.deleteContents();
|
|
9610
|
+
if (_tdAnchor && _tdAnchor.isConnected && !_tdAnchor.contains(range.startContainer)) {
|
|
9611
|
+
range.setStart(_tdAnchor, 0);
|
|
9612
|
+
range.collapse(true);
|
|
9613
|
+
}
|
|
9214
9614
|
const textNode = document.createTextNode(char);
|
|
9215
9615
|
range.insertNode(textNode);
|
|
9216
9616
|
range.setStartAfter(textNode);
|
|
@@ -9779,7 +10179,13 @@ var IconDialog = class {
|
|
|
9779
10179
|
range.selectNodeContents(editable);
|
|
9780
10180
|
range.collapse(false);
|
|
9781
10181
|
}
|
|
10182
|
+
const _sc = range.startContainer;
|
|
10183
|
+
const _tdAnchor = (_sc.nodeType === 1 ? _sc : _sc.parentElement)?.closest?.("td, th");
|
|
9782
10184
|
range.deleteContents();
|
|
10185
|
+
if (_tdAnchor && _tdAnchor.isConnected && !_tdAnchor.contains(range.startContainer)) {
|
|
10186
|
+
range.setStart(_tdAnchor, 0);
|
|
10187
|
+
range.collapse(true);
|
|
10188
|
+
}
|
|
9783
10189
|
range.insertNode(iconEl);
|
|
9784
10190
|
let caretTextNode = iconEl.nextSibling;
|
|
9785
10191
|
if (!caretTextNode || caretTextNode.nodeType !== Node.TEXT_NODE) {
|