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.
Files changed (47) hide show
  1. package/README.md +4 -4
  2. package/dist/autumnnote.css +0 -2
  3. package/dist/autumnnote.es.js +348 -342
  4. package/dist/autumnnote.es.js.map +1 -1
  5. package/dist/autumnnote.umd.js +341 -336
  6. package/dist/autumnnote.umd.js.map +1 -1
  7. package/package.json +21 -3
  8. package/src/js/Context.js +16 -14
  9. package/src/js/core/dom.js +9 -9
  10. package/src/js/core/env.js +1 -1
  11. package/src/js/core/func.js +1 -1
  12. package/src/js/core/lists.js +1 -1
  13. package/src/js/core/markdown.js +18 -18
  14. package/src/js/core/range.js +6 -6
  15. package/src/js/editing/History.js +4 -4
  16. package/src/js/editing/Style.js +32 -32
  17. package/src/js/editing/Table.js +2 -2
  18. package/src/js/editing/Typing.js +15 -15
  19. package/src/js/module/AutoSaveRestore.js +2 -4
  20. package/src/js/module/BubbleToolbar.js +25 -25
  21. package/src/js/module/Buttons.js +4 -4
  22. package/src/js/module/Clipboard.js +12 -13
  23. package/src/js/module/CodeTooltip.js +14 -16
  24. package/src/js/module/Codeview.js +3 -5
  25. package/src/js/module/ContextMenu.js +27 -27
  26. package/src/js/module/Editor.js +17 -18
  27. package/src/js/module/EmojiDialog.js +5 -5
  28. package/src/js/module/FindReplace.js +8 -7
  29. package/src/js/module/IconDialog.js +13 -15
  30. package/src/js/module/ImageCropOverlay.js +7 -7
  31. package/src/js/module/ImageDialog.js +1 -1
  32. package/src/js/module/ImageResizer.js +4 -4
  33. package/src/js/module/ImageTooltip.js +14 -14
  34. package/src/js/module/LinkDialog.js +2 -2
  35. package/src/js/module/LinkTooltip.js +12 -12
  36. package/src/js/module/MarkdownShortcuts.js +11 -14
  37. package/src/js/module/Mention.js +8 -10
  38. package/src/js/module/Placeholder.js +1 -1
  39. package/src/js/module/ShortcutsDialog.js +2 -4
  40. package/src/js/module/Statusbar.js +3 -5
  41. package/src/js/module/TableTooltip.js +30 -32
  42. package/src/js/module/Toolbar.js +21 -21
  43. package/src/js/module/VideoDialog.js +8 -8
  44. package/src/js/module/VideoResizer.js +5 -7
  45. package/src/js/module/VideoTooltip.js +7 -7
  46. package/src/js/renderer.js +1 -1
  47. 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.parentNode.removeChild(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 = url.match(/(?:youtube\.com\/watch\?(?:.*&)?v=|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/);
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 = url.match(/youtu\.be\/([a-zA-Z0-9_-]{11})/);
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 = url.match(/youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})/);
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 = url.match(/vimeo\.com\/(\d+)/);
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.replace(/"/g, '%22');
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.replace(/"/g, '%22');
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(window, 'scroll', () => this._updateOverlayPosition(), { passive: true }),
50
- on(window, 'resize', onWindowResize),
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
- if (this._overlay && this._overlay.parentNode) {
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 && el.classList.contains('an-video-wrapper')) return /** @type {HTMLElement} */ (el);
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 && this._overlay.contains(e.target)) return;
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 && target.closest ? target.closest('.an-video-wrapper') : null;
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(window, 'scroll', () => this._hide(), { passive: true }),
66
- on(window, 'resize', () => this._hide(), { passive: true }),
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
- if (this._el && this._el.parentNode) this._el.parentNode.removeChild(this._el);
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 > window.innerHeight - margin) top = rect.top - tipH - margin;
214
- if (left + tipW > window.innerWidth - margin) left = window.innerWidth - tipW - margin;
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
- if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper);
271
+ wrapper.remove();
272
272
  this.context.invoke('editor.afterCommand');
273
273
  }
274
274
 
@@ -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 || (options.fontFamilies && options.fontFamilies[0]);
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