autumnnote 1.6.5 → 1.6.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/dist/autumnnote.es.js +89 -75
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.umd.js +87 -73
- package/dist/autumnnote.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/js/Context.js +4 -4
- package/src/js/core/dom.js +3 -3
- package/src/js/core/markdown.js +2 -2
- package/src/js/core/range.js +1 -1
- package/src/js/editing/History.js +2 -2
- package/src/js/editing/Style.js +7 -5
- package/src/js/editing/Typing.js +2 -2
- package/src/js/index.js +1 -1
- package/src/js/module/AutoSaveRestore.js +3 -2
- package/src/js/module/BubbleToolbar.js +1 -1
- package/src/js/module/Clipboard.js +4 -4
- package/src/js/module/CodeTooltip.js +1 -1
- package/src/js/module/ContextMenu.js +14 -12
- package/src/js/module/Editor.js +6 -6
- package/src/js/module/EmojiDialog.js +1 -1
- package/src/js/module/FindReplace.js +6 -7
- package/src/js/module/IconDialog.js +1 -1
- package/src/js/module/ImageCropOverlay.js +1 -0
- package/src/js/module/ImageDialog.js +3 -3
- package/src/js/module/ImageResizer.js +2 -2
- package/src/js/module/ImageTooltip.js +5 -3
- package/src/js/module/LinkDialog.js +1 -1
- package/src/js/module/LinkTooltip.js +3 -3
- package/src/js/module/Mention.js +2 -2
- package/src/js/module/TableTooltip.js +50 -32
- package/src/js/module/Toolbar.js +13 -10
- package/src/js/module/VideoDialog.js +5 -2
- package/src/js/renderer.js +2 -2
|
@@ -190,10 +190,7 @@ export class TableTooltip {
|
|
|
190
190
|
on(editable, 'mousedown', onSelMousedown),
|
|
191
191
|
on(editable, 'mousemove', onSelMousemove),
|
|
192
192
|
on(document, 'mouseup', onSelMouseup),
|
|
193
|
-
|
|
194
|
-
// ────────────────────────────────────────────────────────────────────────
|
|
195
|
-
|
|
196
|
-
this._disposers.push(
|
|
193
|
+
// ──────────────────────────────────────────────────────────────────────
|
|
197
194
|
on(editable, 'mouseover', (e) => {
|
|
198
195
|
if (this.context.layoutInfo.container.classList.contains('an-disabled')) return;
|
|
199
196
|
const table = /** @type {Element} */ (e.target)?.closest('table');
|
|
@@ -309,22 +306,27 @@ export class TableTooltip {
|
|
|
309
306
|
_startY = e.clientY;
|
|
310
307
|
_table = _nearCell.closest('table');
|
|
311
308
|
if (_edge === 'col') {
|
|
312
|
-
|
|
313
|
-
_colIdx
|
|
314
|
-
// Cache
|
|
315
|
-
// F-1:
|
|
316
|
-
// distributes it equally across all spanned columns instead of resizing
|
|
317
|
-
// only the target column. Rows that have an individual cell at this
|
|
318
|
-
// visual column index are resized independently as expected.
|
|
309
|
+
// Right edge of a merged cell = last spanned column, not the start column
|
|
310
|
+
_colIdx = getVisualColIndex(_nearCell) + (_nearCell.colSpan || 1) - 1;
|
|
311
|
+
// Cache non-merged cells at that column — merged cells cannot be individually
|
|
312
|
+
// resized per column (F-1: colSpan > 1 distributes width across all spanned cols)
|
|
319
313
|
_colCells = _colIdx >= 0
|
|
320
314
|
? Array.from(_table.querySelectorAll('tr'))
|
|
321
315
|
.map(r => getCellAtVisualCol(r, _colIdx))
|
|
322
316
|
.filter(Boolean)
|
|
323
317
|
.filter(c => (c.colSpan || 1) === 1)
|
|
324
318
|
: [];
|
|
319
|
+
// Use the actual column width from a non-merged cell; fall back to per-column estimate
|
|
320
|
+
_startW = _colCells.length > 0
|
|
321
|
+
? _colCells[0].offsetWidth
|
|
322
|
+
: Math.max(30, Math.round(_nearCell.offsetWidth / (_nearCell.colSpan || 1)));
|
|
325
323
|
document.body.style.cursor = 'col-resize';
|
|
326
324
|
} else {
|
|
327
|
-
|
|
325
|
+
// Bottom edge of a merged cell = last spanned row, not the cell's own <tr>
|
|
326
|
+
const tr = _nearCell.closest('tr');
|
|
327
|
+
const rowStart = tr ? Array.from(_table.rows).indexOf(tr) : 0;
|
|
328
|
+
const lastRowIdx = rowStart + (_nearCell.rowSpan || 1) - 1;
|
|
329
|
+
_row = _table.rows[lastRowIdx] || tr;
|
|
328
330
|
_startH = _row ? _row.offsetHeight : 40;
|
|
329
331
|
document.body.style.cursor = 'row-resize';
|
|
330
332
|
}
|
|
@@ -386,7 +388,7 @@ export class TableTooltip {
|
|
|
386
388
|
this._clearTimers();
|
|
387
389
|
this._disposers.forEach((d) => d());
|
|
388
390
|
this._disposers = [];
|
|
389
|
-
if (this._el
|
|
391
|
+
if (this._el?.parentNode) this._el.remove();
|
|
390
392
|
this._el = null;
|
|
391
393
|
if (this._sizePopover?.parentNode) {
|
|
392
394
|
this._sizePopover.remove();
|
|
@@ -734,7 +736,8 @@ export class TableTooltip {
|
|
|
734
736
|
const refRow = selectedRows.reduce((best, r) => {
|
|
735
737
|
const bi = allRows.indexOf(best);
|
|
736
738
|
const ri = allRows.indexOf(r);
|
|
737
|
-
|
|
739
|
+
if (position === 'above') return ri < bi ? r : best;
|
|
740
|
+
return ri > bi ? r : best;
|
|
738
741
|
}, selectedRows[0]);
|
|
739
742
|
const colCount = Array.from(refRow.cells).reduce((sum, c) => sum + (c.colSpan || 1), 0);
|
|
740
743
|
const newRow = document.createElement('tr');
|
|
@@ -747,7 +750,7 @@ export class TableTooltip {
|
|
|
747
750
|
newRow.appendChild(td);
|
|
748
751
|
}
|
|
749
752
|
if (position === 'above') refRow.parentElement?.insertBefore(newRow, refRow);
|
|
750
|
-
else refRow.
|
|
753
|
+
else refRow.after(newRow);
|
|
751
754
|
requestAnimationFrame(() => this._positionNear(this._activeTable));
|
|
752
755
|
this.context.invoke('editor.afterCommand');
|
|
753
756
|
}
|
|
@@ -865,8 +868,21 @@ export class TableTooltip {
|
|
|
865
868
|
first.colSpan = maxC - minC + 1;
|
|
866
869
|
first.rowSpan = maxR - minR + 1;
|
|
867
870
|
first.style.verticalAlign = 'middle';
|
|
868
|
-
first.
|
|
869
|
-
|
|
871
|
+
first.style.height = '';
|
|
872
|
+
first.style.minHeight = '';
|
|
873
|
+
|
|
874
|
+
// Merge content: collect non-empty inner HTML, join with <br> separator
|
|
875
|
+
const parts = rectCells
|
|
876
|
+
.map((c) => c.innerHTML.replace(/^(<br\s*\/?>|\s)+$/i, '').trim())
|
|
877
|
+
.filter((h) => h !== '');
|
|
878
|
+
first.innerHTML = parts.length ? parts.join('<br>') : '<br>';
|
|
879
|
+
|
|
880
|
+
rectCells.slice(1).forEach((c) => {
|
|
881
|
+
const row = c.parentElement;
|
|
882
|
+
c.remove();
|
|
883
|
+
// Remove the parent <tr> if it is now completely empty
|
|
884
|
+
if (row && row.cells.length === 0) row.remove();
|
|
885
|
+
});
|
|
870
886
|
|
|
871
887
|
this._clearSelection();
|
|
872
888
|
this.context.invoke('editor.afterCommand');
|
|
@@ -939,7 +955,7 @@ export class TableTooltip {
|
|
|
939
955
|
let ref = null;
|
|
940
956
|
for (const tc of targetRow.cells) {
|
|
941
957
|
const tp = cellPos.get(tc);
|
|
942
|
-
if (tp
|
|
958
|
+
if (tp?.c > c) { ref = tc; break; }
|
|
943
959
|
}
|
|
944
960
|
for (let dc = 0; dc < cs; dc++) {
|
|
945
961
|
targetRow.insertBefore(createElement(tag, {}, ['\u00a0']), ref);
|
|
@@ -1043,9 +1059,12 @@ export class TableTooltip {
|
|
|
1043
1059
|
: this.context.locale.tooltips.table.rowHeightPx;
|
|
1044
1060
|
this._sizeInputEl.min = '1';
|
|
1045
1061
|
this._sizeInputEl.max = '2000';
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1062
|
+
if (isCol) {
|
|
1063
|
+
this._sizeInputEl.value = cell.offsetWidth || 120;
|
|
1064
|
+
} else {
|
|
1065
|
+
const refRow = cell.closest('tr');
|
|
1066
|
+
this._sizeInputEl.value = refRow ? (refRow.offsetHeight || 40) : 40;
|
|
1067
|
+
}
|
|
1049
1068
|
this._sizeApply = (val) => {
|
|
1050
1069
|
const table = cell.closest('table');
|
|
1051
1070
|
if (!table) return;
|
|
@@ -1140,19 +1159,18 @@ export class TableTooltip {
|
|
|
1140
1159
|
on(pop, 'mousedown', (e) => e.preventDefault()),
|
|
1141
1160
|
on(pop, 'mouseenter', () => this._clearTimers()),
|
|
1142
1161
|
on(pop, 'mouseleave', () => this._scheduleHide()),
|
|
1162
|
+
// Close on outside click
|
|
1163
|
+
on(document, 'click', (e) => {
|
|
1164
|
+
const et = /** @type {Node} */ (e.target);
|
|
1165
|
+
if (this._shadePopover &&
|
|
1166
|
+
this._shadePopover.style.display !== 'none' &&
|
|
1167
|
+
!this._shadePopover.contains(et) &&
|
|
1168
|
+
!this._el?.contains(et)) {
|
|
1169
|
+
this._hideCellShadePopover();
|
|
1170
|
+
}
|
|
1171
|
+
}),
|
|
1143
1172
|
);
|
|
1144
1173
|
|
|
1145
|
-
// Close on outside click
|
|
1146
|
-
this._disposers.push(on(document, 'click', (e) => {
|
|
1147
|
-
const et = /** @type {Node} */ (e.target);
|
|
1148
|
-
if (this._shadePopover &&
|
|
1149
|
-
this._shadePopover.style.display !== 'none' &&
|
|
1150
|
-
!this._shadePopover.contains(et) &&
|
|
1151
|
-
!this._el?.contains(et)) {
|
|
1152
|
-
this._hideCellShadePopover();
|
|
1153
|
-
}
|
|
1154
|
-
}));
|
|
1155
|
-
|
|
1156
1174
|
return pop;
|
|
1157
1175
|
}
|
|
1158
1176
|
|
package/src/js/module/Toolbar.js
CHANGED
|
@@ -145,7 +145,7 @@ export class Toolbar {
|
|
|
145
145
|
this._refreshRaf = null;
|
|
146
146
|
this._disposers.forEach((d) => d());
|
|
147
147
|
this._disposers = [];
|
|
148
|
-
if (this.el
|
|
148
|
+
if (this.el?.parentNode) {
|
|
149
149
|
this.el.remove();
|
|
150
150
|
}
|
|
151
151
|
this.el = null;
|
|
@@ -410,7 +410,7 @@ export class Toolbar {
|
|
|
410
410
|
sel.removeAllRanges();
|
|
411
411
|
sel.addRange(savedRange);
|
|
412
412
|
} catch (_) {
|
|
413
|
-
//
|
|
413
|
+
void _; // range may be stale if DOM changed while popup was open
|
|
414
414
|
}
|
|
415
415
|
};
|
|
416
416
|
|
|
@@ -541,11 +541,14 @@ export class Toolbar {
|
|
|
541
541
|
|
|
542
542
|
items.forEach((item) => {
|
|
543
543
|
const value = (typeof item === 'object') ? item.value : item;
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
544
|
+
let label;
|
|
545
|
+
if (typeof item !== 'object') {
|
|
546
|
+
label = item;
|
|
547
|
+
} else if (def.name === 'paragraphStyle') {
|
|
548
|
+
label = this.context.locale.toolbar.paragraphItems?.[item.value] || item.label;
|
|
549
|
+
} else {
|
|
550
|
+
label = item.label;
|
|
551
|
+
}
|
|
549
552
|
const isHeader = (typeof item === 'object') && !!item.disabled;
|
|
550
553
|
const attrs = { value };
|
|
551
554
|
if (isHeader) attrs.disabled = '';
|
|
@@ -576,7 +579,7 @@ export class Toolbar {
|
|
|
576
579
|
try {
|
|
577
580
|
const sel = globalThis.getSelection();
|
|
578
581
|
if (sel) { sel.removeAllRanges(); sel.addRange(_savedRange); }
|
|
579
|
-
} catch (_) { /* range may be stale if DOM changed */ }
|
|
582
|
+
} catch (_) { void _; /* range may be stale if DOM changed */ }
|
|
580
583
|
}
|
|
581
584
|
def.action(this.context, value);
|
|
582
585
|
this.context.invoke('editor.afterCommand');
|
|
@@ -700,13 +703,13 @@ export class Toolbar {
|
|
|
700
703
|
// Fallback: when no selection/font set, use the configured default font
|
|
701
704
|
if (!raw) {
|
|
702
705
|
raw = this.options.defaultFontFamily
|
|
703
|
-
||
|
|
706
|
+
|| this.options.fontFamilies?.[0]
|
|
704
707
|
|| '';
|
|
705
708
|
}
|
|
706
709
|
// Try to match against available options (case-insensitive)
|
|
707
710
|
const sel = /** @type {HTMLSelectElement} */ (select);
|
|
708
711
|
const matched = Array.from(sel.options).find(
|
|
709
|
-
(opt) => opt.value
|
|
712
|
+
(opt) => opt.value?.toLowerCase() === raw.toLowerCase()
|
|
710
713
|
);
|
|
711
714
|
sel.value = matched ? matched.value : '';
|
|
712
715
|
});
|
|
@@ -68,7 +68,10 @@ export class VideoDialog extends BaseDialog {
|
|
|
68
68
|
// Live URL hint
|
|
69
69
|
const d0 = on(urlInput, 'input', () => {
|
|
70
70
|
const info = this._parseVideoUrl(urlInput.value.trim());
|
|
71
|
-
|
|
71
|
+
let hint = '';
|
|
72
|
+
if (info) { hint = this.context.locale.videoDialog.detected(info.type); }
|
|
73
|
+
else if (urlInput.value) { hint = this.context.locale.videoDialog.unknownFormat; }
|
|
74
|
+
hintEl.textContent = hint;
|
|
72
75
|
});
|
|
73
76
|
const d4 = on(urlInput, 'keydown', (e) => { if (/** @type {KeyboardEvent} */ (e).key === 'Enter') { e.preventDefault(); this._onInsert(); } });
|
|
74
77
|
this._disposers.push(d0, d4);
|
|
@@ -167,7 +170,7 @@ export class VideoDialog extends BaseDialog {
|
|
|
167
170
|
);
|
|
168
171
|
}
|
|
169
172
|
|
|
170
|
-
if (info
|
|
173
|
+
if (info?.type === 'Direct video') {
|
|
171
174
|
const src = info.embedUrl.replaceAll('"', '%22');
|
|
172
175
|
return (
|
|
173
176
|
`<div class="an-video-wrapper" style="position:relative;display:block;width:${width}px;max-width:100%">` +
|
package/src/js/renderer.js
CHANGED
|
@@ -36,7 +36,7 @@ export function renderLayout(targetEl, options) {
|
|
|
36
36
|
// Restore auto-saved content when available; fall back to element content
|
|
37
37
|
let initialContent = '';
|
|
38
38
|
if (options.autoSave && options.autoSaveKey) {
|
|
39
|
-
try { initialContent = localStorage.getItem(options.autoSaveKey) || ''; } catch (_) {}
|
|
39
|
+
try { initialContent = localStorage.getItem(options.autoSaveKey) || ''; } catch (_) { void _; }
|
|
40
40
|
}
|
|
41
41
|
if (!initialContent) {
|
|
42
42
|
initialContent = targetEl.tagName === 'TEXTAREA'
|
|
@@ -111,7 +111,7 @@ export function renderLayout(targetEl, options) {
|
|
|
111
111
|
|
|
112
112
|
// Hide the original element; keep it in DOM for form submission
|
|
113
113
|
targetEl.style.display = 'none';
|
|
114
|
-
targetEl.
|
|
114
|
+
targetEl.after(container);
|
|
115
115
|
|
|
116
116
|
return { container, editable };
|
|
117
117
|
}
|