autumnnote 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/autumnnote.css +0 -2
- package/dist/autumnnote.es.js +348 -342
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.umd.js +341 -336
- package/dist/autumnnote.umd.js.map +1 -1
- package/package.json +21 -3
- package/src/js/Context.js +16 -14
- package/src/js/core/dom.js +9 -9
- package/src/js/core/env.js +1 -1
- package/src/js/core/func.js +1 -1
- package/src/js/core/lists.js +1 -1
- package/src/js/core/markdown.js +18 -18
- package/src/js/core/range.js +6 -6
- package/src/js/editing/History.js +4 -4
- package/src/js/editing/Style.js +32 -32
- package/src/js/editing/Table.js +2 -2
- package/src/js/editing/Typing.js +15 -15
- package/src/js/module/AutoSaveRestore.js +2 -4
- package/src/js/module/BubbleToolbar.js +25 -25
- package/src/js/module/Buttons.js +4 -4
- package/src/js/module/Clipboard.js +12 -13
- package/src/js/module/CodeTooltip.js +14 -16
- package/src/js/module/Codeview.js +3 -5
- package/src/js/module/ContextMenu.js +27 -27
- package/src/js/module/Editor.js +17 -18
- package/src/js/module/EmojiDialog.js +5 -5
- package/src/js/module/FindReplace.js +8 -7
- package/src/js/module/IconDialog.js +13 -15
- package/src/js/module/ImageCropOverlay.js +7 -7
- package/src/js/module/ImageDialog.js +1 -1
- package/src/js/module/ImageResizer.js +4 -4
- package/src/js/module/ImageTooltip.js +14 -14
- package/src/js/module/LinkDialog.js +2 -2
- package/src/js/module/LinkTooltip.js +12 -12
- package/src/js/module/MarkdownShortcuts.js +11 -14
- package/src/js/module/Mention.js +8 -10
- package/src/js/module/Placeholder.js +1 -1
- package/src/js/module/ShortcutsDialog.js +2 -4
- package/src/js/module/Statusbar.js +3 -5
- package/src/js/module/TableTooltip.js +30 -32
- package/src/js/module/Toolbar.js +21 -21
- package/src/js/module/VideoDialog.js +8 -8
- package/src/js/module/VideoResizer.js +5 -7
- package/src/js/module/VideoTooltip.js +7 -7
- package/src/js/renderer.js +1 -1
- package/src/styles/autumnnote.scss +0 -3
|
@@ -33,7 +33,7 @@ export class LinkDialog {
|
|
|
33
33
|
this._disposers.forEach((d) => d());
|
|
34
34
|
this._disposers = [];
|
|
35
35
|
if (this._dialog && this._dialog.parentNode) {
|
|
36
|
-
this._dialog.
|
|
36
|
+
this._dialog.remove();
|
|
37
37
|
}
|
|
38
38
|
this._dialog = null;
|
|
39
39
|
}
|
|
@@ -138,7 +138,7 @@ export class LinkDialog {
|
|
|
138
138
|
|
|
139
139
|
_prefill() {
|
|
140
140
|
// Try to find currently selected anchor
|
|
141
|
-
const sel =
|
|
141
|
+
const sel = globalThis.getSelection();
|
|
142
142
|
let anchor = null;
|
|
143
143
|
if (sel && sel.rangeCount > 0) {
|
|
144
144
|
let node = sel.getRangeAt(0).startContainer;
|
|
@@ -46,8 +46,8 @@ export class LinkTooltip {
|
|
|
46
46
|
}
|
|
47
47
|
}),
|
|
48
48
|
// Hide when the page scrolls or resizes — the tooltip position becomes stale
|
|
49
|
-
on(
|
|
50
|
-
on(
|
|
49
|
+
on(globalThis, 'scroll', () => this._hide(), { passive: true }),
|
|
50
|
+
on(globalThis, 'resize', () => this._hide(), { passive: true }),
|
|
51
51
|
);
|
|
52
52
|
|
|
53
53
|
return this;
|
|
@@ -57,7 +57,7 @@ export class LinkTooltip {
|
|
|
57
57
|
this._clearTimers();
|
|
58
58
|
this._disposers.forEach((d) => d());
|
|
59
59
|
this._disposers = [];
|
|
60
|
-
if (this._el && this._el.parentNode) this._el.
|
|
60
|
+
if (this._el && this._el.parentNode) this._el.remove();
|
|
61
61
|
this._el = null;
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -163,11 +163,11 @@ export class LinkTooltip {
|
|
|
163
163
|
let top = rect.bottom + margin;
|
|
164
164
|
let left = rect.left;
|
|
165
165
|
|
|
166
|
-
if (top + tipH >
|
|
166
|
+
if (top + tipH > globalThis.innerHeight - margin) {
|
|
167
167
|
top = rect.top - tipH - margin;
|
|
168
168
|
}
|
|
169
|
-
if (left + tipW >
|
|
170
|
-
left =
|
|
169
|
+
if (left + tipW > globalThis.innerWidth - margin) {
|
|
170
|
+
left = globalThis.innerWidth - tipW - margin;
|
|
171
171
|
}
|
|
172
172
|
if (left < margin) left = margin;
|
|
173
173
|
|
|
@@ -190,13 +190,13 @@ export class LinkTooltip {
|
|
|
190
190
|
// ---------------------------------------------------------------------------
|
|
191
191
|
|
|
192
192
|
_openLink() {
|
|
193
|
-
const url = this._activeAnchor
|
|
194
|
-
if (url)
|
|
193
|
+
const url = this._activeAnchor?.getAttribute('href');
|
|
194
|
+
if (url) globalThis.open(url, '_blank', 'noopener,noreferrer');
|
|
195
195
|
this._hide();
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
_copyLink() {
|
|
199
|
-
const url = this._activeAnchor
|
|
199
|
+
const url = this._activeAnchor?.getAttribute('href');
|
|
200
200
|
if (url) {
|
|
201
201
|
navigator.clipboard.writeText(url).catch(() => {
|
|
202
202
|
// Fallback for environments where clipboard API is unavailable
|
|
@@ -207,7 +207,7 @@ export class LinkTooltip {
|
|
|
207
207
|
document.body.appendChild(ta);
|
|
208
208
|
ta.select();
|
|
209
209
|
document.execCommand('copy');
|
|
210
|
-
|
|
210
|
+
ta.remove();
|
|
211
211
|
});
|
|
212
212
|
}
|
|
213
213
|
// Brief visual feedback
|
|
@@ -223,7 +223,7 @@ export class LinkTooltip {
|
|
|
223
223
|
this._hide();
|
|
224
224
|
|
|
225
225
|
// Place cursor inside the anchor, then open the link dialog (which pre-fills from selection)
|
|
226
|
-
const sel =
|
|
226
|
+
const sel = globalThis.getSelection();
|
|
227
227
|
const range = document.createRange();
|
|
228
228
|
range.selectNodeContents(anchor);
|
|
229
229
|
sel.removeAllRanges();
|
|
@@ -238,7 +238,7 @@ export class LinkTooltip {
|
|
|
238
238
|
this._hide();
|
|
239
239
|
|
|
240
240
|
// Select the anchor text, then remove the link
|
|
241
|
-
const sel =
|
|
241
|
+
const sel = globalThis.getSelection();
|
|
242
242
|
const range = document.createRange();
|
|
243
243
|
range.selectNode(anchor);
|
|
244
244
|
sel.removeAllRanges();
|
|
@@ -61,8 +61,8 @@ export class MarkdownShortcuts {
|
|
|
61
61
|
* @returns {{ text: string, range: Range, lineNode: Node } | null}
|
|
62
62
|
*/
|
|
63
63
|
_getLineContext() {
|
|
64
|
-
const sel =
|
|
65
|
-
if (!sel
|
|
64
|
+
const sel = globalThis.getSelection();
|
|
65
|
+
if (!sel?.rangeCount) return null;
|
|
66
66
|
const range = sel.getRangeAt(0);
|
|
67
67
|
if (!range.collapsed) return null;
|
|
68
68
|
|
|
@@ -87,7 +87,7 @@ export class MarkdownShortcuts {
|
|
|
87
87
|
|
|
88
88
|
_isBlock(node) {
|
|
89
89
|
if (node.nodeType !== Node.ELEMENT_NODE) return false;
|
|
90
|
-
const display =
|
|
90
|
+
const display = globalThis.getComputedStyle(node).display;
|
|
91
91
|
return display === 'block' || display === 'list-item' || display === 'table-cell';
|
|
92
92
|
}
|
|
93
93
|
|
|
@@ -106,7 +106,7 @@ export class MarkdownShortcuts {
|
|
|
106
106
|
];
|
|
107
107
|
|
|
108
108
|
for (const { re, handler } of blockPatterns) {
|
|
109
|
-
const m =
|
|
109
|
+
const m = re.exec(text);
|
|
110
110
|
if (m) {
|
|
111
111
|
handler(m);
|
|
112
112
|
return true;
|
|
@@ -137,8 +137,8 @@ export class MarkdownShortcuts {
|
|
|
137
137
|
// ---------------------------------------------------------------------------
|
|
138
138
|
|
|
139
139
|
_selectLineAndDelete() {
|
|
140
|
-
const sel =
|
|
141
|
-
if (!sel
|
|
140
|
+
const sel = globalThis.getSelection();
|
|
141
|
+
if (!sel?.rangeCount) return;
|
|
142
142
|
const range = sel.getRangeAt(0);
|
|
143
143
|
// Select from the start of the block to the cursor and delete
|
|
144
144
|
const startRange = document.createRange();
|
|
@@ -188,8 +188,8 @@ export class MarkdownShortcuts {
|
|
|
188
188
|
// ---------------------------------------------------------------------------
|
|
189
189
|
|
|
190
190
|
_onInput() {
|
|
191
|
-
const sel =
|
|
192
|
-
if (!sel
|
|
191
|
+
const sel = globalThis.getSelection();
|
|
192
|
+
if (!sel?.rangeCount) return;
|
|
193
193
|
const range = sel.getRangeAt(0);
|
|
194
194
|
if (!range.collapsed) return;
|
|
195
195
|
|
|
@@ -215,7 +215,7 @@ export class MarkdownShortcuts {
|
|
|
215
215
|
|
|
216
216
|
const upToCursor = text.slice(0, offset);
|
|
217
217
|
for (const { re, tag } of inlineRules) {
|
|
218
|
-
const m =
|
|
218
|
+
const m = re.exec(upToCursor);
|
|
219
219
|
if (!m) continue;
|
|
220
220
|
|
|
221
221
|
const matchStart = upToCursor.length - m[0].length;
|
|
@@ -233,11 +233,8 @@ export class MarkdownShortcuts {
|
|
|
233
233
|
const beforeNode = document.createTextNode(before);
|
|
234
234
|
const afterNode = document.createTextNode('' + after);
|
|
235
235
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
parent.insertBefore(el, node);
|
|
239
|
-
parent.insertBefore(afterNode, node);
|
|
240
|
-
parent.removeChild(node);
|
|
236
|
+
/** @type {ChildNode} */ (node).before(beforeNode, el, afterNode);
|
|
237
|
+
/** @type {ChildNode} */ (node).remove();
|
|
241
238
|
|
|
242
239
|
// Place cursor after the element (after the ZWS)
|
|
243
240
|
const newRange = document.createRange();
|
package/src/js/module/Mention.js
CHANGED
|
@@ -76,9 +76,7 @@ export class Mention {
|
|
|
76
76
|
|
|
77
77
|
destroy() {
|
|
78
78
|
clearTimeout(this._debounceTimer);
|
|
79
|
-
|
|
80
|
-
this._dropdown.parentNode.removeChild(this._dropdown);
|
|
81
|
-
}
|
|
79
|
+
this._dropdown?.remove();
|
|
82
80
|
this._dropdown = null;
|
|
83
81
|
this._disposers.forEach((d) => d());
|
|
84
82
|
this._disposers = [];
|
|
@@ -163,10 +161,10 @@ export class Mention {
|
|
|
163
161
|
let top = rect.bottom + 4;
|
|
164
162
|
let left = rect.left;
|
|
165
163
|
|
|
166
|
-
if (rect.bottom + ddh + 8 >
|
|
164
|
+
if (rect.bottom + ddh + 8 > globalThis.innerHeight) {
|
|
167
165
|
top = rect.top - ddh - 4;
|
|
168
166
|
}
|
|
169
|
-
left = Math.max(8, Math.min(left,
|
|
167
|
+
left = Math.max(8, Math.min(left, globalThis.innerWidth - ddw - 8));
|
|
170
168
|
|
|
171
169
|
dd.style.top = `${top}px`;
|
|
172
170
|
dd.style.left = `${left}px`;
|
|
@@ -196,7 +194,7 @@ export class Mention {
|
|
|
196
194
|
_captureCaretRect() {
|
|
197
195
|
// Prefer a range over the trigger character — it has non-zero width and
|
|
198
196
|
// getBoundingClientRect() reliably returns a valid rect.
|
|
199
|
-
if (this._triggerNode
|
|
197
|
+
if (this._triggerNode?.isConnected) {
|
|
200
198
|
try {
|
|
201
199
|
const r = document.createRange();
|
|
202
200
|
const end = Math.min(this._triggerOffset + 1, this._triggerNode.textContent.length);
|
|
@@ -211,7 +209,7 @@ export class Mention {
|
|
|
211
209
|
}
|
|
212
210
|
|
|
213
211
|
// Fallback: use getClientRects() on the current collapsed selection
|
|
214
|
-
const sel =
|
|
212
|
+
const sel = globalThis.getSelection();
|
|
215
213
|
if (!sel || !sel.rangeCount) return;
|
|
216
214
|
const rects = sel.getRangeAt(0).getClientRects();
|
|
217
215
|
if (rects.length > 0) {
|
|
@@ -224,7 +222,7 @@ export class Mention {
|
|
|
224
222
|
// ---------------------------------------------------------------------------
|
|
225
223
|
|
|
226
224
|
_getQueryAtCursor() {
|
|
227
|
-
const sel =
|
|
225
|
+
const sel = globalThis.getSelection();
|
|
228
226
|
if (!sel || !sel.rangeCount) return null;
|
|
229
227
|
const range = sel.getRangeAt(0);
|
|
230
228
|
if (!range.collapsed) return null;
|
|
@@ -305,7 +303,7 @@ export class Mention {
|
|
|
305
303
|
|
|
306
304
|
_onDocClick(e) {
|
|
307
305
|
if (!this._open) return;
|
|
308
|
-
if (this._dropdown
|
|
306
|
+
if (this._dropdown?.contains(e.target)) return;
|
|
309
307
|
this._hideDropdown();
|
|
310
308
|
}
|
|
311
309
|
|
|
@@ -325,7 +323,7 @@ export class Mention {
|
|
|
325
323
|
node.textContent = before + after;
|
|
326
324
|
|
|
327
325
|
// Move cursor to where the trigger was
|
|
328
|
-
const sel =
|
|
326
|
+
const sel = globalThis.getSelection();
|
|
329
327
|
const range = document.createRange();
|
|
330
328
|
range.setStart(node, this._triggerOffset);
|
|
331
329
|
range.collapse(true);
|
|
@@ -43,7 +43,7 @@ export class Placeholder {
|
|
|
43
43
|
// addition to regular whitespace before deciding if the editor is empty.
|
|
44
44
|
// Without this, a freshly-created checklist item or icon leaves a ZWS in
|
|
45
45
|
// the DOM that causes the placeholder to overlap real content (A-1).
|
|
46
|
-
const hasText = editable.textContent.
|
|
46
|
+
const hasText = editable.textContent.replaceAll('\u200B', '').trim().length > 0;
|
|
47
47
|
const isEmpty = !hasText &&
|
|
48
48
|
!editable.querySelector('img, table, hr, .an-video-wrapper');
|
|
49
49
|
editable.classList.toggle('an-placeholder', isEmpty && !isFocused);
|
|
@@ -69,9 +69,7 @@ export class ShortcutsDialog {
|
|
|
69
69
|
destroy() {
|
|
70
70
|
this._disposers.forEach((d) => d());
|
|
71
71
|
this._disposers = [];
|
|
72
|
-
|
|
73
|
-
this._dialog.parentNode.removeChild(this._dialog);
|
|
74
|
-
}
|
|
72
|
+
this._dialog?.remove();
|
|
75
73
|
this._dialog = null;
|
|
76
74
|
}
|
|
77
75
|
|
|
@@ -79,7 +77,7 @@ export class ShortcutsDialog {
|
|
|
79
77
|
if (this._dialog) {
|
|
80
78
|
this._dialog.style.display = 'flex';
|
|
81
79
|
this._removeTrap = trapFocus(this._dialog, () => this._close());
|
|
82
|
-
setTimeout(() => this._closeBtn
|
|
80
|
+
setTimeout(() => this._closeBtn?.focus(), 50);
|
|
83
81
|
}
|
|
84
82
|
}
|
|
85
83
|
|
|
@@ -109,9 +109,7 @@ export class Statusbar {
|
|
|
109
109
|
this._dragDisposers.forEach((d) => d());
|
|
110
110
|
this._dragDisposers = null;
|
|
111
111
|
}
|
|
112
|
-
|
|
113
|
-
this.el.parentNode.removeChild(this.el);
|
|
114
|
-
}
|
|
112
|
+
this.el?.remove();
|
|
115
113
|
this.el = null;
|
|
116
114
|
}
|
|
117
115
|
|
|
@@ -217,7 +215,7 @@ export class Statusbar {
|
|
|
217
215
|
// textContent is faster than innerText (no layout flush, no CSS visibility check)
|
|
218
216
|
const text = editable.textContent || '';
|
|
219
217
|
const words = _countWords(text);
|
|
220
|
-
const chars = text.
|
|
218
|
+
const chars = text.replaceAll('\n', '').length;
|
|
221
219
|
const maxWords = this.options.maxWords || 0;
|
|
222
220
|
const maxChars = this.options.maxChars || 0;
|
|
223
221
|
|
|
@@ -249,6 +247,6 @@ export class Statusbar {
|
|
|
249
247
|
*/
|
|
250
248
|
getCharCount() {
|
|
251
249
|
const editable = this.context.layoutInfo.editable;
|
|
252
|
-
return (
|
|
250
|
+
return (editable.innerText || '').replaceAll('\n', '').length;
|
|
253
251
|
}
|
|
254
252
|
}
|
|
@@ -212,26 +212,26 @@ export class TableTooltip {
|
|
|
212
212
|
if (!to || (
|
|
213
213
|
!editable.contains(to) &&
|
|
214
214
|
!this._el.contains(to) &&
|
|
215
|
-
!
|
|
215
|
+
!this._sizePopover?.contains(to)
|
|
216
216
|
)) {
|
|
217
217
|
this._scheduleHide();
|
|
218
218
|
}
|
|
219
219
|
}, { passive: true }),
|
|
220
220
|
on(document, 'click', (e) => {
|
|
221
221
|
const et = /** @type {Node} */ (e.target);
|
|
222
|
-
if (this._selectMode && this._activeTable
|
|
222
|
+
if (this._selectMode && this._activeTable?.contains(et)) return;
|
|
223
223
|
if (this._activeTable &&
|
|
224
224
|
!this._activeTable.contains(et) &&
|
|
225
225
|
!this._el.contains(et) &&
|
|
226
|
-
!
|
|
226
|
+
!this._sizePopover?.contains(et)) {
|
|
227
227
|
this._hide();
|
|
228
228
|
}
|
|
229
229
|
}),
|
|
230
230
|
// Sync shade strip whenever selection moves to a different cell
|
|
231
231
|
on(document, 'selectionchange', () => this._syncShadeStrip()),
|
|
232
232
|
// Hide when the page scrolls or resizes — the tooltip position becomes stale
|
|
233
|
-
on(
|
|
234
|
-
on(
|
|
233
|
+
on(globalThis, 'scroll', () => this._hide(), { passive: true }),
|
|
234
|
+
on(globalThis, 'resize', () => this._hide(), { passive: true }),
|
|
235
235
|
);
|
|
236
236
|
|
|
237
237
|
this._initResize();
|
|
@@ -386,14 +386,14 @@ export class TableTooltip {
|
|
|
386
386
|
this._clearTimers();
|
|
387
387
|
this._disposers.forEach((d) => d());
|
|
388
388
|
this._disposers = [];
|
|
389
|
-
if (this._el && this._el.parentNode) this._el.
|
|
389
|
+
if (this._el && this._el.parentNode) this._el.remove();
|
|
390
390
|
this._el = null;
|
|
391
391
|
if (this._sizePopover && this._sizePopover.parentNode) {
|
|
392
|
-
this._sizePopover.
|
|
392
|
+
this._sizePopover.remove();
|
|
393
393
|
}
|
|
394
394
|
this._sizePopover = null;
|
|
395
395
|
if (this._shadePopover && this._shadePopover.parentNode) {
|
|
396
|
-
this._shadePopover.
|
|
396
|
+
this._shadePopover.remove();
|
|
397
397
|
}
|
|
398
398
|
this._shadePopover = null;
|
|
399
399
|
}
|
|
@@ -553,7 +553,7 @@ export class TableTooltip {
|
|
|
553
553
|
_syncShadeStrip() {
|
|
554
554
|
if (!this._shadeColorStrip || !this._el || this._el.style.display === 'none') return;
|
|
555
555
|
const cell = this._getCell();
|
|
556
|
-
this._shadeColorStrip.style.background =
|
|
556
|
+
this._shadeColorStrip.style.background = cell?.style.backgroundColor || 'transparent';
|
|
557
557
|
}
|
|
558
558
|
|
|
559
559
|
_hide() {
|
|
@@ -590,7 +590,7 @@ export class TableTooltip {
|
|
|
590
590
|
let top = rect.top - tipH - margin;
|
|
591
591
|
|
|
592
592
|
if (top < margin) top = rect.bottom + margin;
|
|
593
|
-
if (left + tipW >
|
|
593
|
+
if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
|
|
594
594
|
if (left < margin) left = margin;
|
|
595
595
|
|
|
596
596
|
this._el.style.left = `${left}px`;
|
|
@@ -603,17 +603,17 @@ export class TableTooltip {
|
|
|
603
603
|
|
|
604
604
|
_getCell() {
|
|
605
605
|
// Prefer the cell under the current text cursor (most intuitive for operations)
|
|
606
|
-
const sel =
|
|
606
|
+
const sel = globalThis.getSelection();
|
|
607
607
|
if (sel && sel.rangeCount) {
|
|
608
608
|
let container = sel.getRangeAt(0).commonAncestorContainer;
|
|
609
609
|
if (container.nodeType === 3) container = container.parentElement;
|
|
610
|
-
const cellFromSel =
|
|
611
|
-
if (cellFromSel && this._activeTable
|
|
610
|
+
const cellFromSel = /** @type {Element} */ (container)?.closest('td, th');
|
|
611
|
+
if (cellFromSel && this._activeTable?.contains(cellFromSel)) {
|
|
612
612
|
return cellFromSel;
|
|
613
613
|
}
|
|
614
614
|
}
|
|
615
615
|
return this._activeCell
|
|
616
|
-
||
|
|
616
|
+
|| this._activeTable?.querySelector('td, th');
|
|
617
617
|
}
|
|
618
618
|
|
|
619
619
|
// ---------------------------------------------------------------------------
|
|
@@ -735,7 +735,7 @@ export class TableTooltip {
|
|
|
735
735
|
const bi = allRows.indexOf(best);
|
|
736
736
|
const ri = allRows.indexOf(r);
|
|
737
737
|
return position === 'above' ? (ri < bi ? r : best) : (ri > bi ? r : best);
|
|
738
|
-
});
|
|
738
|
+
}, selectedRows[0]);
|
|
739
739
|
const colCount = Array.from(refRow.cells).reduce((sum, c) => sum + (c.colSpan || 1), 0);
|
|
740
740
|
const newRow = document.createElement('tr');
|
|
741
741
|
const refCells = Array.from(refRow.cells);
|
|
@@ -786,7 +786,7 @@ export class TableTooltip {
|
|
|
786
786
|
if (bodyRowsToDelete.length >= totalBodyRows) return;
|
|
787
787
|
this._activeCell = null;
|
|
788
788
|
this._clearSelection();
|
|
789
|
-
selectedRows.forEach((r) => r.
|
|
789
|
+
selectedRows.forEach((r) => r.remove());
|
|
790
790
|
requestAnimationFrame(() => this._positionNear(this._activeTable));
|
|
791
791
|
this.context.invoke('editor.afterCommand');
|
|
792
792
|
}
|
|
@@ -810,7 +810,7 @@ export class TableTooltip {
|
|
|
810
810
|
});
|
|
811
811
|
this._activeCell = null;
|
|
812
812
|
this._clearSelection();
|
|
813
|
-
cellsToDelete.forEach((c) => c.
|
|
813
|
+
cellsToDelete.forEach((c) => c.remove());
|
|
814
814
|
requestAnimationFrame(() => this._positionNear(this._activeTable));
|
|
815
815
|
this.context.invoke('editor.afterCommand');
|
|
816
816
|
}
|
|
@@ -824,7 +824,7 @@ export class TableTooltip {
|
|
|
824
824
|
// Prefer user panel-selected cells; fall back to text-selection range
|
|
825
825
|
let selected = this._getSelectedCells().filter((c) => table.contains(c));
|
|
826
826
|
if (selected.length < 2) {
|
|
827
|
-
const sel =
|
|
827
|
+
const sel = globalThis.getSelection();
|
|
828
828
|
if (!sel || sel.rangeCount === 0) return;
|
|
829
829
|
const range = sel.getRangeAt(0);
|
|
830
830
|
const allCells = Array.from(table.querySelectorAll('td, th'));
|
|
@@ -866,7 +866,7 @@ export class TableTooltip {
|
|
|
866
866
|
first.rowSpan = maxR - minR + 1;
|
|
867
867
|
first.style.verticalAlign = 'middle';
|
|
868
868
|
first.innerHTML = rectCells.map((c) => c.innerHTML).join('');
|
|
869
|
-
rectCells.slice(1).forEach((c) => c.
|
|
869
|
+
rectCells.slice(1).forEach((c) => c.remove());
|
|
870
870
|
|
|
871
871
|
this._clearSelection();
|
|
872
872
|
this.context.invoke('editor.afterCommand');
|
|
@@ -876,7 +876,7 @@ export class TableTooltip {
|
|
|
876
876
|
const table = this._activeTable;
|
|
877
877
|
if (!table) return;
|
|
878
878
|
this._hide();
|
|
879
|
-
if (table.parentNode) table.
|
|
879
|
+
if (table.parentNode) table.remove();
|
|
880
880
|
this.context.invoke('editor.afterCommand');
|
|
881
881
|
}
|
|
882
882
|
|
|
@@ -981,7 +981,7 @@ export class TableTooltip {
|
|
|
981
981
|
this._sizeApply = null;
|
|
982
982
|
|
|
983
983
|
const d1 = on(applyBtn, 'click', () => {
|
|
984
|
-
const val = parseInt(this._sizeInputEl.value, 10);
|
|
984
|
+
const val = Number.parseInt(this._sizeInputEl.value, 10);
|
|
985
985
|
if (val > 0 && typeof this._sizeApply === 'function') this._sizeApply(val);
|
|
986
986
|
this._hideSizePopover();
|
|
987
987
|
});
|
|
@@ -1016,8 +1016,8 @@ export class TableTooltip {
|
|
|
1016
1016
|
if (!table) return;
|
|
1017
1017
|
const firstCell = table.querySelector('td, th');
|
|
1018
1018
|
const currentPx = firstCell
|
|
1019
|
-
? (parseInt(firstCell.style.borderWidth, 10) ||
|
|
1020
|
-
parseInt(
|
|
1019
|
+
? (Number.parseInt(firstCell.style.borderWidth, 10) ||
|
|
1020
|
+
Number.parseInt(globalThis.getComputedStyle(firstCell).borderWidth, 10) || 1)
|
|
1021
1021
|
: 1;
|
|
1022
1022
|
this._sizeTitleEl.textContent = this.context.locale.tooltips.table.tableBorderWidthPx;
|
|
1023
1023
|
this._sizeInputEl.min = '0';
|
|
@@ -1079,8 +1079,8 @@ export class TableTooltip {
|
|
|
1079
1079
|
const ph = this._sizePopover.offsetHeight || 110;
|
|
1080
1080
|
let left = tipRect.left;
|
|
1081
1081
|
let top = tipRect.bottom + 6;
|
|
1082
|
-
if (left + pw >
|
|
1083
|
-
if (top + ph >
|
|
1082
|
+
if (left + pw > globalThis.innerWidth - 8) left = globalThis.innerWidth - pw - 8;
|
|
1083
|
+
if (top + ph > globalThis.innerHeight - 8) top = tipRect.top - ph - 6;
|
|
1084
1084
|
this._sizePopover.style.left = `${left}px`;
|
|
1085
1085
|
this._sizePopover.style.top = `${top}px`;
|
|
1086
1086
|
if (this._sizeInputEl) { this._sizeInputEl.focus(); this._sizeInputEl.select(); }
|
|
@@ -1135,11 +1135,9 @@ export class TableTooltip {
|
|
|
1135
1135
|
customRow.appendChild(customLabel);
|
|
1136
1136
|
pop.appendChild(customRow);
|
|
1137
1137
|
|
|
1138
|
-
// Prevent mousedown from collapsing editor selection
|
|
1139
|
-
this._disposers.push(on(pop, 'mousedown', (e) => e.preventDefault()));
|
|
1140
|
-
|
|
1141
|
-
// Keep tooltip alive while hovering popover
|
|
1138
|
+
// Prevent mousedown from collapsing editor selection; keep tooltip alive while hovering
|
|
1142
1139
|
this._disposers.push(
|
|
1140
|
+
on(pop, 'mousedown', (e) => e.preventDefault()),
|
|
1143
1141
|
on(pop, 'mouseenter', () => this._clearTimers()),
|
|
1144
1142
|
on(pop, 'mouseleave', () => this._scheduleHide()),
|
|
1145
1143
|
);
|
|
@@ -1150,7 +1148,7 @@ export class TableTooltip {
|
|
|
1150
1148
|
if (this._shadePopover &&
|
|
1151
1149
|
this._shadePopover.style.display !== 'none' &&
|
|
1152
1150
|
!this._shadePopover.contains(et) &&
|
|
1153
|
-
!
|
|
1151
|
+
!this._el?.contains(et)) {
|
|
1154
1152
|
this._hideCellShadePopover();
|
|
1155
1153
|
}
|
|
1156
1154
|
}));
|
|
@@ -1172,8 +1170,8 @@ export class TableTooltip {
|
|
|
1172
1170
|
const tipRect = this._el.getBoundingClientRect();
|
|
1173
1171
|
let left = tipRect.left;
|
|
1174
1172
|
let top = tipRect.bottom + 6;
|
|
1175
|
-
if (left + pw >
|
|
1176
|
-
if (top + ph >
|
|
1173
|
+
if (left + pw > globalThis.innerWidth - 8) left = globalThis.innerWidth - pw - 8;
|
|
1174
|
+
if (top + ph > globalThis.innerHeight - 8) top = tipRect.top - ph - 6;
|
|
1177
1175
|
this._shadePopover.style.left = `${Math.max(8, left)}px`;
|
|
1178
1176
|
this._shadePopover.style.top = `${Math.max(8, top)}px`;
|
|
1179
1177
|
});
|
package/src/js/module/Toolbar.js
CHANGED
|
@@ -146,7 +146,7 @@ export class Toolbar {
|
|
|
146
146
|
this._disposers.forEach((d) => d());
|
|
147
147
|
this._disposers = [];
|
|
148
148
|
if (this.el && this.el.parentNode) {
|
|
149
|
-
this.el.
|
|
149
|
+
this.el.remove();
|
|
150
150
|
}
|
|
151
151
|
this.el = null;
|
|
152
152
|
}
|
|
@@ -244,8 +244,8 @@ export class Toolbar {
|
|
|
244
244
|
|
|
245
245
|
const setHighlight = (rows, cols) => {
|
|
246
246
|
cells.forEach((cell) => {
|
|
247
|
-
const r = +cell.
|
|
248
|
-
const c = +cell.
|
|
247
|
+
const r = +cell.dataset.row;
|
|
248
|
+
const c = +cell.dataset.col;
|
|
249
249
|
cell.classList.toggle('active', r <= rows && c <= cols);
|
|
250
250
|
});
|
|
251
251
|
label.textContent = (rows && cols) ? `${rows} × ${cols}` : (this.context.locale.toolbar.insertTableLabel || 'Insert Table');
|
|
@@ -264,8 +264,8 @@ export class Toolbar {
|
|
|
264
264
|
|
|
265
265
|
let left = rect.left;
|
|
266
266
|
let top = rect.bottom + 4;
|
|
267
|
-
if (left + pw >
|
|
268
|
-
if (top + ph >
|
|
267
|
+
if (left + pw > globalThis.innerWidth - 8) left = Math.max(8, globalThis.innerWidth - pw - 8);
|
|
268
|
+
if (top + ph > globalThis.innerHeight - 8) top = rect.top - ph - 4;
|
|
269
269
|
|
|
270
270
|
popup.style.left = `${left}px`;
|
|
271
271
|
popup.style.top = `${top}px`;
|
|
@@ -286,18 +286,18 @@ export class Toolbar {
|
|
|
286
286
|
});
|
|
287
287
|
|
|
288
288
|
const d2 = on(grid, 'mouseover', (e) => {
|
|
289
|
-
const cell = /** @type {Element} */ (e.target)?.closest('.an-table-cell');
|
|
289
|
+
const cell = /** @type {HTMLElement|null} */ (/** @type {Element} */ (e.target)?.closest('.an-table-cell'));
|
|
290
290
|
if (!cell) return;
|
|
291
|
-
setHighlight(+cell.
|
|
291
|
+
setHighlight(+cell.dataset.row, +cell.dataset.col);
|
|
292
292
|
});
|
|
293
293
|
|
|
294
294
|
const d3 = on(grid, 'mouseleave', () => setHighlight(0, 0));
|
|
295
295
|
|
|
296
296
|
const d4 = on(grid, 'click', (e) => {
|
|
297
|
-
const cell = /** @type {Element} */ (e.target)?.closest('.an-table-cell');
|
|
297
|
+
const cell = /** @type {HTMLElement|null} */ (/** @type {Element} */ (e.target)?.closest('.an-table-cell'));
|
|
298
298
|
if (!cell) return;
|
|
299
|
-
const rows = +cell.
|
|
300
|
-
const cols = +cell.
|
|
299
|
+
const rows = +cell.dataset.row;
|
|
300
|
+
const cols = +cell.dataset.col;
|
|
301
301
|
closePopup();
|
|
302
302
|
this.context.invoke('editor.focus');
|
|
303
303
|
def.action(this.context, rows, cols);
|
|
@@ -308,7 +308,7 @@ export class Toolbar {
|
|
|
308
308
|
// Append popup to body so position:fixed is truly viewport-relative,
|
|
309
309
|
// unaffected by any ancestor transform / filter (same pattern as color picker).
|
|
310
310
|
this._disposers.push(d1, d2, d3, d4, d5, () => {
|
|
311
|
-
if (popup.parentNode) popup.
|
|
311
|
+
if (popup.parentNode) popup.remove();
|
|
312
312
|
});
|
|
313
313
|
|
|
314
314
|
wrap.appendChild(btn);
|
|
@@ -398,14 +398,14 @@ export class Toolbar {
|
|
|
398
398
|
let savedRange = null;
|
|
399
399
|
|
|
400
400
|
const saveSelection = () => {
|
|
401
|
-
const sel =
|
|
401
|
+
const sel = globalThis.getSelection();
|
|
402
402
|
savedRange = (sel && sel.rangeCount) ? sel.getRangeAt(0).cloneRange() : null;
|
|
403
403
|
};
|
|
404
404
|
|
|
405
405
|
const restoreSelection = () => {
|
|
406
406
|
if (!savedRange) return;
|
|
407
407
|
try {
|
|
408
|
-
const sel =
|
|
408
|
+
const sel = globalThis.getSelection();
|
|
409
409
|
if (!sel) return;
|
|
410
410
|
sel.removeAllRanges();
|
|
411
411
|
sel.addRange(savedRange);
|
|
@@ -424,7 +424,7 @@ export class Toolbar {
|
|
|
424
424
|
const rect = arrowBtn.getBoundingClientRect();
|
|
425
425
|
const popupMinW = 184;
|
|
426
426
|
let left = rect.left;
|
|
427
|
-
if (left + popupMinW >
|
|
427
|
+
if (left + popupMinW > globalThis.innerWidth) left = rect.right - popupMinW;
|
|
428
428
|
popup.style.top = `${rect.bottom + 4}px`;
|
|
429
429
|
popup.style.left = `${Math.max(4, left)}px`;
|
|
430
430
|
popup.style.display = 'block';
|
|
@@ -491,13 +491,13 @@ export class Toolbar {
|
|
|
491
491
|
// popup doesn't drift away from the button it belongs to.
|
|
492
492
|
const onScrollResize = () => { if (isOpen) closePopup(); };
|
|
493
493
|
document.addEventListener('scroll', onScrollResize, { passive: true, capture: true });
|
|
494
|
-
|
|
494
|
+
globalThis.addEventListener('resize', onScrollResize, { passive: true });
|
|
495
495
|
|
|
496
496
|
this._disposers.push(d1, d2, d2b, d3, d3b, d4, d5, d6,
|
|
497
497
|
() => document.removeEventListener('scroll', onScrollResize, { capture: true }),
|
|
498
|
-
() =>
|
|
498
|
+
() => globalThis.removeEventListener('resize', onScrollResize),
|
|
499
499
|
// Remove popup from body on editor destroy
|
|
500
|
-
() => { if (popup.parentNode) popup.
|
|
500
|
+
() => { if (popup.parentNode) popup.remove(); },
|
|
501
501
|
);
|
|
502
502
|
|
|
503
503
|
// Register this popup's closer so other color pickers can close it
|
|
@@ -562,7 +562,7 @@ export class Toolbar {
|
|
|
562
562
|
/** @type {Range|null} */
|
|
563
563
|
let _savedRange = null;
|
|
564
564
|
const dMousedown = on(select, 'mousedown', () => {
|
|
565
|
-
const sel =
|
|
565
|
+
const sel = globalThis.getSelection();
|
|
566
566
|
_savedRange = (sel && sel.rangeCount) ? sel.getRangeAt(0).cloneRange() : null;
|
|
567
567
|
});
|
|
568
568
|
|
|
@@ -574,7 +574,7 @@ export class Toolbar {
|
|
|
574
574
|
// Restore selection saved on mousedown so the action targets the correct text.
|
|
575
575
|
if (_savedRange) {
|
|
576
576
|
try {
|
|
577
|
-
const sel =
|
|
577
|
+
const sel = globalThis.getSelection();
|
|
578
578
|
if (sel) { sel.removeAllRanges(); sel.addRange(_savedRange); }
|
|
579
579
|
} catch (_) { /* range may be stale if DOM changed */ }
|
|
580
580
|
}
|
|
@@ -684,7 +684,7 @@ export class Toolbar {
|
|
|
684
684
|
|
|
685
685
|
// Sync button active states
|
|
686
686
|
this.el.querySelectorAll('button[data-btn]').forEach((btn) => {
|
|
687
|
-
const def = btnMap.get(btn.
|
|
687
|
+
const def = btnMap.get(/** @type {HTMLElement} */ (btn).dataset.btn);
|
|
688
688
|
if (def && typeof def.isActive === 'function') {
|
|
689
689
|
btn.classList.toggle('active', !!def.isActive(this.context));
|
|
690
690
|
}
|
|
@@ -695,7 +695,7 @@ export class Toolbar {
|
|
|
695
695
|
|
|
696
696
|
// Sync select dropdowns (e.g. font family) with current cursor position
|
|
697
697
|
this.el.querySelectorAll('select[data-btn]').forEach((select) => {
|
|
698
|
-
const def = btnMap.get(select.
|
|
698
|
+
const def = btnMap.get(/** @type {HTMLElement} */ (select).dataset.btn);
|
|
699
699
|
if (!def || typeof def.getValue !== 'function') return;
|
|
700
700
|
// queryCommandValue returns the font name, possibly quoted — strip quotes
|
|
701
701
|
let raw = (def.getValue(this.context) || '').replace(/["']/g, '').trim();
|