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
|
@@ -35,7 +35,7 @@ export class VideoDialog {
|
|
|
35
35
|
this._disposers.forEach((d) => d());
|
|
36
36
|
this._disposers = [];
|
|
37
37
|
if (this._dialog && this._dialog.parentNode) {
|
|
38
|
-
this._dialog.
|
|
38
|
+
this._dialog.remove();
|
|
39
39
|
}
|
|
40
40
|
this._dialog = null;
|
|
41
41
|
}
|
|
@@ -138,7 +138,7 @@ export class VideoDialog {
|
|
|
138
138
|
|
|
139
139
|
_onInsert() {
|
|
140
140
|
const rawUrl = this._urlInput.value.trim();
|
|
141
|
-
const width = Math.max(80, parseInt(this._widthInput.value, 10) || 560);
|
|
141
|
+
const width = Math.max(80, Number.parseInt(this._widthInput.value, 10) || 560);
|
|
142
142
|
|
|
143
143
|
if (!rawUrl) {
|
|
144
144
|
this._urlInput.focus();
|
|
@@ -190,19 +190,19 @@ export class VideoDialog {
|
|
|
190
190
|
} catch { return null; }
|
|
191
191
|
|
|
192
192
|
// YouTube watch: https://www.youtube.com/watch?v=ID
|
|
193
|
-
const ytWatch =
|
|
193
|
+
const ytWatch = /(?:youtube\.com\/watch\?(?:.*&)?v=|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/.exec(url);
|
|
194
194
|
if (ytWatch) return { type: 'YouTube', embedUrl: `https://www.youtube.com/embed/${ytWatch[1]}` };
|
|
195
195
|
|
|
196
196
|
// YouTube short: https://youtu.be/ID
|
|
197
|
-
const ytShort =
|
|
197
|
+
const ytShort = /youtu\.be\/([a-zA-Z0-9_-]{11})/.exec(url);
|
|
198
198
|
if (ytShort) return { type: 'YouTube', embedUrl: `https://www.youtube.com/embed/${ytShort[1]}` };
|
|
199
199
|
|
|
200
200
|
// YouTube Shorts: https://www.youtube.com/shorts/ID
|
|
201
|
-
const ytShorts =
|
|
201
|
+
const ytShorts = /youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/.exec(url);
|
|
202
202
|
if (ytShorts) return { type: 'YouTube Shorts', embedUrl: `https://www.youtube.com/embed/${ytShorts[1]}` };
|
|
203
203
|
|
|
204
204
|
// Vimeo: https://vimeo.com/ID
|
|
205
|
-
const vimeo =
|
|
205
|
+
const vimeo = /vimeo\.com\/(\d+)/.exec(url);
|
|
206
206
|
if (vimeo) return { type: 'Vimeo', embedUrl: `https://player.vimeo.com/video/${vimeo[1]}` };
|
|
207
207
|
|
|
208
208
|
// Direct video file
|
|
@@ -238,7 +238,7 @@ export class VideoDialog {
|
|
|
238
238
|
}
|
|
239
239
|
|
|
240
240
|
if (info && info.type === 'Direct video') {
|
|
241
|
-
const src = info.embedUrl.
|
|
241
|
+
const src = info.embedUrl.replaceAll('"', '%22');
|
|
242
242
|
return (
|
|
243
243
|
`<div class="an-video-wrapper" style="position:relative;display:block;width:${width}px;max-width:100%">` +
|
|
244
244
|
`<video src="${src}" width="${width}" height="${height}" controls ` +
|
|
@@ -258,7 +258,7 @@ export class VideoDialog {
|
|
|
258
258
|
})();
|
|
259
259
|
if (!safeSrc) return null;
|
|
260
260
|
|
|
261
|
-
const escapedSrc = safeSrc.
|
|
261
|
+
const escapedSrc = safeSrc.replaceAll('"', '%22');
|
|
262
262
|
return (
|
|
263
263
|
`<div class="an-video-wrapper" style="position:relative;display:block;width:${width}px;max-width:100%">` +
|
|
264
264
|
`<video src="${escapedSrc}" width="${width}" height="${height}" controls ` +
|
|
@@ -46,8 +46,8 @@ export class VideoResizer {
|
|
|
46
46
|
if (wrapper) this._select(wrapper);
|
|
47
47
|
}),
|
|
48
48
|
on(document, 'click', (e) => this._onDocClick(e)),
|
|
49
|
-
on(
|
|
50
|
-
on(
|
|
49
|
+
on(globalThis, 'scroll', () => this._updateOverlayPosition(), { passive: true }),
|
|
50
|
+
on(globalThis, 'resize', onWindowResize),
|
|
51
51
|
on(editable, 'scroll', () => this._updateOverlayPosition(), { passive: true }),
|
|
52
52
|
// D1: Prevent native browser drag of video wrappers. Without this, a user
|
|
53
53
|
// can hold-and-drag to produce a "copy" that lands outside .an-editable,
|
|
@@ -75,9 +75,7 @@ export class VideoResizer {
|
|
|
75
75
|
this._positionRaf = null;
|
|
76
76
|
}
|
|
77
77
|
this._deselect();
|
|
78
|
-
|
|
79
|
-
this._overlay.parentNode.removeChild(this._overlay);
|
|
80
|
-
}
|
|
78
|
+
this._overlay?.remove();
|
|
81
79
|
this._overlay = null;
|
|
82
80
|
}
|
|
83
81
|
|
|
@@ -111,7 +109,7 @@ export class VideoResizer {
|
|
|
111
109
|
_findWrapper(el) {
|
|
112
110
|
if (!el || !(el instanceof Element)) return null;
|
|
113
111
|
// Direct hit on wrapper
|
|
114
|
-
if (el.classList
|
|
112
|
+
if (el.classList?.contains('an-video-wrapper')) return /** @type {HTMLElement} */ (el);
|
|
115
113
|
// Child element (iframe, video, or nested)
|
|
116
114
|
const w = el.closest('.an-video-wrapper');
|
|
117
115
|
if (w) return /** @type {HTMLElement} */ (w);
|
|
@@ -152,7 +150,7 @@ export class VideoResizer {
|
|
|
152
150
|
_onDocClick(e) {
|
|
153
151
|
if (!this._activeWrapper) return;
|
|
154
152
|
if (this._activeWrapper.contains(e.target)) return;
|
|
155
|
-
if (this._overlay
|
|
153
|
+
if (this._overlay?.contains(e.target)) return;
|
|
156
154
|
if (e.target.closest('.an-contextmenu')) return;
|
|
157
155
|
this._deselect();
|
|
158
156
|
}
|
|
@@ -40,7 +40,7 @@ export class VideoTooltip {
|
|
|
40
40
|
if (this.context.layoutInfo.container.classList.contains('an-disabled')) return;
|
|
41
41
|
// The shield div sits on top of iframes — we detect hover via it or the wrapper
|
|
42
42
|
const target = /** @type {Element} */ (e.target);
|
|
43
|
-
const wrapper = target
|
|
43
|
+
const wrapper = target?.closest('.an-video-wrapper');
|
|
44
44
|
if (wrapper && editable.contains(wrapper)) {
|
|
45
45
|
this._scheduleShow(wrapper);
|
|
46
46
|
}
|
|
@@ -62,8 +62,8 @@ export class VideoTooltip {
|
|
|
62
62
|
}
|
|
63
63
|
}),
|
|
64
64
|
// Hide when the page scrolls or resizes — the tooltip position becomes stale
|
|
65
|
-
on(
|
|
66
|
-
on(
|
|
65
|
+
on(globalThis, 'scroll', () => this._hide(), { passive: true }),
|
|
66
|
+
on(globalThis, 'resize', () => this._hide(), { passive: true }),
|
|
67
67
|
);
|
|
68
68
|
|
|
69
69
|
return this;
|
|
@@ -74,7 +74,7 @@ export class VideoTooltip {
|
|
|
74
74
|
this._clearTimers();
|
|
75
75
|
this._disposers.forEach((d) => d());
|
|
76
76
|
this._disposers = [];
|
|
77
|
-
|
|
77
|
+
this._el?.remove();
|
|
78
78
|
this._el = null;
|
|
79
79
|
}
|
|
80
80
|
|
|
@@ -210,8 +210,8 @@ export class VideoTooltip {
|
|
|
210
210
|
let top = rect.bottom + margin;
|
|
211
211
|
let left = rect.left + (rect.width - tipW) / 2;
|
|
212
212
|
|
|
213
|
-
if (top + tipH >
|
|
214
|
-
if (left + tipW >
|
|
213
|
+
if (top + tipH > globalThis.innerHeight - margin) top = rect.top - tipH - margin;
|
|
214
|
+
if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
|
|
215
215
|
if (left < margin) left = margin;
|
|
216
216
|
|
|
217
217
|
this._el.style.top = `${top}px`;
|
|
@@ -268,7 +268,7 @@ export class VideoTooltip {
|
|
|
268
268
|
if (!wrapper) return;
|
|
269
269
|
this._hide();
|
|
270
270
|
this.context.invoke('videoResizer.deselect');
|
|
271
|
-
|
|
271
|
+
wrapper.remove();
|
|
272
272
|
this.context.invoke('editor.afterCommand');
|
|
273
273
|
}
|
|
274
274
|
|
package/src/js/renderer.js
CHANGED
|
@@ -46,7 +46,7 @@ export function renderLayout(targetEl, options) {
|
|
|
46
46
|
editable.innerHTML = sanitiseHTML(initialContent, { allowIframes: true });
|
|
47
47
|
|
|
48
48
|
// Apply default font family so the editable renders in the configured font
|
|
49
|
-
const defaultFont = options.defaultFontFamily ||
|
|
49
|
+
const defaultFont = options.defaultFontFamily || options.fontFamilies?.[0];
|
|
50
50
|
if (defaultFont) {
|
|
51
51
|
editable.style.fontFamily = defaultFont;
|
|
52
52
|
}
|
|
@@ -62,14 +62,12 @@
|
|
|
62
62
|
// Prevent images from being dragged out.
|
|
63
63
|
img {
|
|
64
64
|
-webkit-user-drag: none;
|
|
65
|
-
user-drag: none;
|
|
66
65
|
}
|
|
67
66
|
|
|
68
67
|
// Prevent video wrapper itself from being dragged, but keep pointer-events
|
|
69
68
|
// active so the video shield works and the iframe is visible/interactive.
|
|
70
69
|
.an-video-wrapper {
|
|
71
70
|
-webkit-user-drag: none;
|
|
72
|
-
user-drag: none;
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
// D-3: In read-only mode, disable the video shield so clicks reach the
|
|
@@ -1423,7 +1421,6 @@ $an-video-accent: #8b5cf6; // violet-500
|
|
|
1423
1421
|
// .an-video-selected is applied by VideoResizer for JS state tracking.
|
|
1424
1422
|
// Visual selection is handled entirely by the .an-video-resizer overlay,
|
|
1425
1423
|
// so no CSS outline is needed here (two visible frames would appear otherwise).
|
|
1426
|
-
.an-video-selected {}
|
|
1427
1424
|
|
|
1428
1425
|
// ---------------------------------------------------------------------------
|
|
1429
1426
|
// Icon dialog
|