autumnnote 1.6.1 → 1.6.3

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.
@@ -6978,15 +6978,13 @@
6978
6978
  }
6979
6979
  };
6980
6980
  //#endregion
6981
- //#region src/js/module/LinkDialog.js
6981
+ //#region src/js/module/BaseDialog.js
6982
6982
  /**
6983
- * LinkDialog.js - Dialog for inserting / editing hyperlinks
6984
- * Inspired by Summernote's LinkDialog rewritten without jQuery
6983
+ * Shared lifecycle and shell-building logic for all modal dialogs.
6984
+ * Subclasses implement _buildDialog() for their specific form fields.
6985
6985
  */
6986
- var LinkDialog = class {
6987
- /**
6988
- * @param {import('../Context.js').Context} context
6989
- */
6986
+ var BaseDialog = class {
6987
+ /** @param {import('../Context.js').Context} context */
6990
6988
  constructor(context) {
6991
6989
  this.context = context;
6992
6990
  this.options = context.options;
@@ -6994,6 +6992,9 @@
6994
6992
  this._dialog = null;
6995
6993
  this._disposers = [];
6996
6994
  this._savedRange = null;
6995
+ /** @type {HTMLElement|null} First focusable input; set by subclass in _buildDialog(). */
6996
+ this._firstInput = null;
6997
+ this._removeTrap = null;
6997
6998
  }
6998
6999
  initialize() {
6999
7000
  this._dialog = this._buildDialog();
@@ -7003,36 +7004,113 @@
7003
7004
  destroy() {
7004
7005
  this._disposers.forEach((d) => d());
7005
7006
  this._disposers = [];
7006
- if (this._dialog && this._dialog.parentNode) this._dialog.remove();
7007
+ if (this._dialog?.parentNode) this._dialog.remove();
7007
7008
  this._dialog = null;
7008
7009
  }
7009
- /**
7010
- * Opens the link dialog.
7011
- * Pre-fills with the currently selected link if present.
7012
- */
7013
- show() {
7010
+ /** Saves the current selection range before opening the dialog. */
7011
+ _saveRange() {
7014
7012
  withSavedRange((range) => {
7015
7013
  this._savedRange = range;
7016
7014
  });
7017
- this._prefill();
7018
- this._open();
7019
7015
  }
7020
- _buildDialog() {
7021
- const L = this.context.locale.linkDialog;
7016
+ _open() {
7017
+ if (this._dialog) {
7018
+ this._dialog.style.display = "flex";
7019
+ this._removeTrap = trapFocus(this._dialog, () => this._close());
7020
+ setTimeout(() => this._firstInput && this._firstInput.focus(), 50);
7021
+ }
7022
+ }
7023
+ _close() {
7024
+ if (this._dialog) this._dialog.style.display = "none";
7025
+ if (this._removeTrap) {
7026
+ this._removeTrap();
7027
+ this._removeTrap = null;
7028
+ }
7029
+ this._savedRange = null;
7030
+ }
7031
+ /**
7032
+ * Builds the overlay + box + header shell common to all dialogs.
7033
+ * Also wires up draggable and overlay-click-to-close.
7034
+ * @param {string} ariaLabel
7035
+ * @param {string} iconHtml Raw SVG string for the dialog icon
7036
+ * @param {string} titleText
7037
+ * @returns {{ overlay: HTMLElement, box: HTMLElement }}
7038
+ */
7039
+ _buildDialogShell(ariaLabel, iconHtml, titleText) {
7022
7040
  const overlay = createElement("div", {
7023
7041
  class: "an-dialog-overlay",
7024
7042
  role: "dialog",
7025
7043
  "aria-modal": "true",
7026
- "aria-label": L.ariaLabel
7044
+ "aria-label": ariaLabel
7027
7045
  });
7028
7046
  const box = createElement("div", { class: "an-dialog-box" });
7029
7047
  const header = createElement("div", { class: "an-dialog-header" });
7030
7048
  const iconEl = createElement("span", { class: "an-dialog-icon" });
7031
- iconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>`;
7032
- const title = createElement("h3", { class: "an-dialog-title" });
7033
- title.textContent = L.title;
7049
+ iconEl.innerHTML = iconHtml;
7050
+ const titleEl = createElement("h3", { class: "an-dialog-title" });
7051
+ titleEl.textContent = titleText;
7034
7052
  header.appendChild(iconEl);
7035
- header.appendChild(title);
7053
+ header.appendChild(titleEl);
7054
+ box.appendChild(header);
7055
+ overlay.appendChild(box);
7056
+ makeDraggable(header, box);
7057
+ const d = on(overlay, "click", (e) => {
7058
+ if (e.target === overlay) this._close();
7059
+ });
7060
+ this._disposers.push(d);
7061
+ return {
7062
+ overlay,
7063
+ box
7064
+ };
7065
+ }
7066
+ /**
7067
+ * Builds an action button row with a primary insert button and a cancel button.
7068
+ * Disposers are registered automatically.
7069
+ * @param {string} insertLabel
7070
+ * @param {string} cancelLabel
7071
+ * @param {() => void} onInsert
7072
+ * @returns {HTMLElement}
7073
+ */
7074
+ _buildButtonRow(insertLabel, cancelLabel, onInsert) {
7075
+ const btnRow = createElement("div", { class: "an-dialog-actions" });
7076
+ const insertBtn = createElement("button", {
7077
+ type: "button",
7078
+ class: "an-btn an-btn-primary"
7079
+ });
7080
+ insertBtn.textContent = insertLabel;
7081
+ const cancelBtn = createElement("button", {
7082
+ type: "button",
7083
+ class: "an-btn"
7084
+ });
7085
+ cancelBtn.textContent = cancelLabel;
7086
+ btnRow.appendChild(insertBtn);
7087
+ btnRow.appendChild(cancelBtn);
7088
+ const d1 = on(insertBtn, "click", onInsert);
7089
+ const d2 = on(cancelBtn, "click", () => this._close());
7090
+ this._disposers.push(d1, d2);
7091
+ return btnRow;
7092
+ }
7093
+ };
7094
+ //#endregion
7095
+ //#region src/js/module/LinkDialog.js
7096
+ /**
7097
+ * LinkDialog.js - Dialog for inserting / editing hyperlinks
7098
+ * Inspired by Summernote's LinkDialog — rewritten without jQuery
7099
+ */
7100
+ var ICON_SVG$3 = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>`;
7101
+ var LinkDialog = class extends BaseDialog {
7102
+ /**
7103
+ * Opens the link dialog.
7104
+ * Pre-fills with the currently selected link if present.
7105
+ */
7106
+ show() {
7107
+ this._saveRange();
7108
+ this._prefill();
7109
+ this._open();
7110
+ }
7111
+ _buildDialog() {
7112
+ const L = this.context.locale.linkDialog;
7113
+ const { overlay, box } = this._buildDialogShell(L.ariaLabel, ICON_SVG$3, L.title);
7036
7114
  const urlLabel = createElement("label", { class: "an-label" });
7037
7115
  urlLabel.textContent = L.url;
7038
7116
  const urlInput = createElement("input", {
@@ -7044,6 +7122,7 @@
7044
7122
  autocomplete: "off"
7045
7123
  });
7046
7124
  this._urlInput = urlInput;
7125
+ this._firstInput = urlInput;
7047
7126
  const textLabel = createElement("label", { class: "an-label" });
7048
7127
  textLabel.textContent = L.displayText;
7049
7128
  const textInput = createElement("input", {
@@ -7064,27 +7143,8 @@
7064
7143
  this._tabCheckbox = tabCheckbox;
7065
7144
  tabLabel.appendChild(tabCheckbox);
7066
7145
  tabLabel.appendChild(document.createTextNode(" " + L.openInNewTab));
7067
- const btnRow = createElement("div", { class: "an-dialog-actions" });
7068
- const insertBtn = createElement("button", {
7069
- type: "button",
7070
- class: "an-btn an-btn-primary"
7071
- });
7072
- insertBtn.textContent = L.insertBtn;
7073
- const cancelBtn = createElement("button", {
7074
- type: "button",
7075
- class: "an-btn"
7076
- });
7077
- cancelBtn.textContent = L.cancelBtn;
7078
- btnRow.appendChild(insertBtn);
7079
- btnRow.appendChild(cancelBtn);
7080
- box.append(header, urlLabel, urlInput, textLabel, textInput, tabLabel, btnRow);
7081
- overlay.appendChild(box);
7082
- makeDraggable(header, box);
7083
- const d1 = on(insertBtn, "click", () => this._onInsert());
7084
- const d2 = on(cancelBtn, "click", () => this._close());
7085
- const d3 = on(overlay, "click", (e) => {
7086
- if (e.target === overlay) this._close();
7087
- });
7146
+ const btnRow = this._buildButtonRow(L.insertBtn, L.cancelBtn, () => this._onInsert());
7147
+ box.append(urlLabel, urlInput, textLabel, textInput, tabLabel, btnRow);
7088
7148
  const d4 = on(urlInput, "keydown", (e) => {
7089
7149
  if (e.key === "Enter") {
7090
7150
  e.preventDefault();
@@ -7097,7 +7157,7 @@
7097
7157
  this._onInsert();
7098
7158
  }
7099
7159
  });
7100
- this._disposers.push(d1, d2, d3, d4, d5);
7160
+ this._disposers.push(d4, d5);
7101
7161
  return overlay;
7102
7162
  }
7103
7163
  _prefill() {
@@ -7146,21 +7206,6 @@
7146
7206
  this.context.invoke("editor.insertLink", url, text, newTab);
7147
7207
  this._close();
7148
7208
  }
7149
- _open() {
7150
- if (this._dialog) {
7151
- this._dialog.style.display = "flex";
7152
- this._removeTrap = trapFocus(this._dialog, () => this._close());
7153
- setTimeout(() => this._urlInput && this._urlInput.focus(), 50);
7154
- }
7155
- }
7156
- _close() {
7157
- if (this._dialog) this._dialog.style.display = "none";
7158
- if (this._removeTrap) {
7159
- this._removeTrap();
7160
- this._removeTrap = null;
7161
- }
7162
- this._savedRange = null;
7163
- }
7164
7209
  };
7165
7210
  //#endregion
7166
7211
  //#region src/js/module/ImageDialog.js
@@ -7168,33 +7213,10 @@
7168
7213
  * ImageDialog.js - Dialog for inserting images (by URL or file upload)
7169
7214
  * Inspired by Summernote's ImageDialog — rewritten without jQuery
7170
7215
  */
7171
- var ImageDialog = class {
7172
- /**
7173
- * @param {import('../Context.js').Context} context
7174
- */
7175
- constructor(context) {
7176
- this.context = context;
7177
- this.options = context.options;
7178
- /** @type {HTMLElement|null} */
7179
- this._dialog = null;
7180
- this._disposers = [];
7181
- this._savedRange = null;
7182
- }
7183
- initialize() {
7184
- this._dialog = this._buildDialog();
7185
- document.body.appendChild(this._dialog);
7186
- return this;
7187
- }
7188
- destroy() {
7189
- this._disposers.forEach((d) => d());
7190
- this._disposers = [];
7191
- if (this._dialog && this._dialog.parentNode) this._dialog.remove();
7192
- this._dialog = null;
7193
- }
7216
+ var ICON_SVG$2 = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" 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="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>`;
7217
+ var ImageDialog = class extends BaseDialog {
7194
7218
  show() {
7195
- withSavedRange((range) => {
7196
- this._savedRange = range;
7197
- });
7219
+ this._saveRange();
7198
7220
  this._urlInput.value = "";
7199
7221
  this._altInput.value = "";
7200
7222
  if (this._fileInput) this._fileInput.value = "";
@@ -7202,20 +7224,7 @@
7202
7224
  }
7203
7225
  _buildDialog() {
7204
7226
  const L = this.context.locale.imageDialog;
7205
- const overlay = createElement("div", {
7206
- class: "an-dialog-overlay",
7207
- role: "dialog",
7208
- "aria-modal": "true",
7209
- "aria-label": L.ariaLabel
7210
- });
7211
- const box = createElement("div", { class: "an-dialog-box" });
7212
- const header = createElement("div", { class: "an-dialog-header" });
7213
- const iconEl = createElement("span", { class: "an-dialog-icon" });
7214
- iconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" 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="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>`;
7215
- const title = createElement("h3", { class: "an-dialog-title" });
7216
- title.textContent = L.title;
7217
- header.appendChild(iconEl);
7218
- header.appendChild(title);
7227
+ const { overlay, box } = this._buildDialogShell(L.ariaLabel, ICON_SVG$2, L.title);
7219
7228
  const urlLabel = createElement("label", { class: "an-label" });
7220
7229
  urlLabel.textContent = L.imageUrl;
7221
7230
  const urlInput = createElement("input", {
@@ -7225,6 +7234,7 @@
7225
7234
  autocomplete: "off"
7226
7235
  });
7227
7236
  this._urlInput = urlInput;
7237
+ this._firstInput = urlInput;
7228
7238
  const altLabel = createElement("label", { class: "an-label" });
7229
7239
  altLabel.textContent = L.altText;
7230
7240
  const altInput = createElement("input", {
@@ -7234,7 +7244,7 @@
7234
7244
  autocomplete: "off"
7235
7245
  });
7236
7246
  this._altInput = altInput;
7237
- box.append(header, urlLabel, urlInput, altLabel, altInput);
7247
+ box.append(urlLabel, urlInput, altLabel, altInput);
7238
7248
  const alignLabel = createElement("label", { class: "an-label" });
7239
7249
  alignLabel.textContent = L.alignment;
7240
7250
  const alignRow = createElement("div", { class: "an-align-row" });
@@ -7288,27 +7298,8 @@
7288
7298
  this._disposers.push(d);
7289
7299
  box.append(fileLabel, fileInput, fileHint);
7290
7300
  }
7291
- const btnRow = createElement("div", { class: "an-dialog-actions" });
7292
- const insertBtn = createElement("button", {
7293
- type: "button",
7294
- class: "an-btn an-btn-primary"
7295
- });
7296
- insertBtn.textContent = L.insertBtn;
7297
- const cancelBtn = createElement("button", {
7298
- type: "button",
7299
- class: "an-btn"
7300
- });
7301
- cancelBtn.textContent = L.cancelBtn;
7302
- btnRow.appendChild(insertBtn);
7303
- btnRow.appendChild(cancelBtn);
7301
+ const btnRow = this._buildButtonRow(L.insertBtn, L.cancelBtn, () => this._onInsert());
7304
7302
  box.append(btnRow);
7305
- overlay.appendChild(box);
7306
- makeDraggable(header, box);
7307
- const d1 = on(insertBtn, "click", () => this._onInsert());
7308
- const d2 = on(cancelBtn, "click", () => this._close());
7309
- const d3 = on(overlay, "click", (e) => {
7310
- if (e.target === overlay) this._close();
7311
- });
7312
7303
  const d4 = on(urlInput, "keydown", (e) => {
7313
7304
  if (e.key === "Enter") {
7314
7305
  e.preventDefault();
@@ -7321,7 +7312,7 @@
7321
7312
  this._onInsert();
7322
7313
  }
7323
7314
  });
7324
- this._disposers.push(d1, d2, d3, d4, d5);
7315
+ this._disposers.push(d4, d5);
7325
7316
  return overlay;
7326
7317
  }
7327
7318
  _onFileChange() {
@@ -7376,21 +7367,6 @@
7376
7367
  this.context.invoke("editor.insertImage", src, alt, align);
7377
7368
  this._close();
7378
7369
  }
7379
- _open() {
7380
- if (this._dialog) {
7381
- this._dialog.style.display = "flex";
7382
- this._removeTrap = trapFocus(this._dialog, () => this._close());
7383
- setTimeout(() => this._urlInput && this._urlInput.focus(), 50);
7384
- }
7385
- }
7386
- _close() {
7387
- if (this._dialog) this._dialog.style.display = "none";
7388
- if (this._removeTrap) {
7389
- this._removeTrap();
7390
- this._removeTrap = null;
7391
- }
7392
- this._savedRange = null;
7393
- }
7394
7370
  };
7395
7371
  //#endregion
7396
7372
  //#region src/js/module/VideoDialog.js
@@ -7402,31 +7378,10 @@
7402
7378
  * • Vimeo URLs → <iframe> embed
7403
7379
  * • Direct video URLs → <video> element (.mp4 / .webm / .ogg)
7404
7380
  */
7405
- var VideoDialog = class {
7406
- /** @param {import('../Context.js').Context} context */
7407
- constructor(context) {
7408
- this.context = context;
7409
- this.options = context.options;
7410
- /** @type {HTMLElement|null} */
7411
- this._dialog = null;
7412
- this._disposers = [];
7413
- this._savedRange = null;
7414
- }
7415
- initialize() {
7416
- this._dialog = this._buildDialog();
7417
- document.body.appendChild(this._dialog);
7418
- return this;
7419
- }
7420
- destroy() {
7421
- this._disposers.forEach((d) => d());
7422
- this._disposers = [];
7423
- if (this._dialog && this._dialog.parentNode) this._dialog.remove();
7424
- this._dialog = null;
7425
- }
7381
+ var ICON_SVG$1 = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>`;
7382
+ var VideoDialog = class extends BaseDialog {
7426
7383
  show() {
7427
- withSavedRange((range) => {
7428
- this._savedRange = range;
7429
- });
7384
+ this._saveRange();
7430
7385
  this._urlInput.value = "";
7431
7386
  this._widthInput.value = "560";
7432
7387
  this._hintEl.textContent = "";
@@ -7434,20 +7389,7 @@
7434
7389
  }
7435
7390
  _buildDialog() {
7436
7391
  const L = this.context.locale.videoDialog;
7437
- const overlay = createElement("div", {
7438
- class: "an-dialog-overlay",
7439
- role: "dialog",
7440
- "aria-modal": "true",
7441
- "aria-label": L.ariaLabel
7442
- });
7443
- const box = createElement("div", { class: "an-dialog-box" });
7444
- const header = createElement("div", { class: "an-dialog-header" });
7445
- const iconEl = createElement("span", { class: "an-dialog-icon" });
7446
- iconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>`;
7447
- const title = createElement("h3", { class: "an-dialog-title" });
7448
- title.textContent = L.title;
7449
- header.appendChild(iconEl);
7450
- header.appendChild(title);
7392
+ const { overlay, box } = this._buildDialogShell(L.ariaLabel, ICON_SVG$1, L.title);
7451
7393
  const urlLabel = createElement("label", { class: "an-label" });
7452
7394
  urlLabel.textContent = L.videoUrl;
7453
7395
  const urlInput = createElement("input", {
@@ -7457,6 +7399,7 @@
7457
7399
  autocomplete: "off"
7458
7400
  });
7459
7401
  this._urlInput = urlInput;
7402
+ this._firstInput = urlInput;
7460
7403
  const hintEl = createElement("p", { class: "an-dialog-hint" });
7461
7404
  this._hintEl = hintEl;
7462
7405
  const widthLabel = createElement("label", { class: "an-label" });
@@ -7470,38 +7413,19 @@
7470
7413
  value: "560"
7471
7414
  });
7472
7415
  this._widthInput = widthInput;
7473
- const btnRow = createElement("div", { class: "an-dialog-actions" });
7474
- const insertBtn = createElement("button", {
7475
- type: "button",
7476
- class: "an-btn an-btn-primary"
7477
- });
7478
- insertBtn.textContent = L.insertBtn;
7479
- const cancelBtn = createElement("button", {
7480
- type: "button",
7481
- class: "an-btn"
7482
- });
7483
- cancelBtn.textContent = L.cancelBtn;
7484
- btnRow.appendChild(insertBtn);
7485
- btnRow.appendChild(cancelBtn);
7486
- box.append(header, urlLabel, urlInput, hintEl, widthLabel, widthInput, btnRow);
7487
- overlay.appendChild(box);
7488
- makeDraggable(header, box);
7416
+ const btnRow = this._buildButtonRow(L.insertBtn, L.cancelBtn, () => this._onInsert());
7417
+ box.append(urlLabel, urlInput, hintEl, widthLabel, widthInput, btnRow);
7489
7418
  const d0 = on(urlInput, "input", () => {
7490
7419
  const info = this._parseVideoUrl(urlInput.value.trim());
7491
7420
  hintEl.textContent = info ? this.context.locale.videoDialog.detected(info.type) : urlInput.value ? this.context.locale.videoDialog.unknownFormat : "";
7492
7421
  });
7493
- const d1 = on(insertBtn, "click", () => this._onInsert());
7494
- const d2 = on(cancelBtn, "click", () => this._close());
7495
- const d3 = on(overlay, "click", (e) => {
7496
- if (e.target === overlay) this._close();
7497
- });
7498
7422
  const d4 = on(urlInput, "keydown", (e) => {
7499
7423
  if (e.key === "Enter") {
7500
7424
  e.preventDefault();
7501
7425
  this._onInsert();
7502
7426
  }
7503
7427
  });
7504
- this._disposers.push(d0, d1, d2, d3, d4);
7428
+ this._disposers.push(d0, d4);
7505
7429
  return overlay;
7506
7430
  }
7507
7431
  _onInsert() {
@@ -7521,21 +7445,6 @@
7521
7445
  this.context.invoke("editor.insertVideo", html);
7522
7446
  this._close();
7523
7447
  }
7524
- _open() {
7525
- if (this._dialog) {
7526
- this._dialog.style.display = "flex";
7527
- this._removeTrap = trapFocus(this._dialog, () => this._close());
7528
- setTimeout(() => this._urlInput && this._urlInput.focus(), 50);
7529
- }
7530
- }
7531
- _close() {
7532
- if (this._dialog) this._dialog.style.display = "none";
7533
- if (this._removeTrap) {
7534
- this._removeTrap();
7535
- this._removeTrap = null;
7536
- }
7537
- this._savedRange = null;
7538
- }
7539
7448
  /**
7540
7449
  * Parses a video URL and returns { type, embedUrl } or null.
7541
7450
  * @param {string} url
@@ -12443,35 +12352,17 @@
12443
12352
  "symbols"
12444
12353
  ]
12445
12354
  ];
12446
- var EmojiDialog = class {
12447
- /**
12448
- * @param {import('../Context.js').Context} context
12449
- */
12450
- constructor(context) {
12451
- this.context = context;
12452
- /** @type {HTMLElement|null} */
12453
- this._dialog = null;
12454
- this._disposers = [];
12455
- this._savedRange = null;
12456
- this._activeCat = "all";
12457
- }
12355
+ var EmojiDialog = class extends BaseDialog {
12356
+ _activeCat = "all";
12458
12357
  initialize() {
12459
12358
  return this;
12460
12359
  }
12461
- destroy() {
12462
- this._disposers.forEach((d) => d());
12463
- this._disposers = [];
12464
- if (this._dialog && this._dialog.parentNode) this._dialog.remove();
12465
- this._dialog = null;
12466
- }
12467
12360
  show() {
12468
12361
  if (!this._dialog) {
12469
12362
  this._dialog = this._buildDialog();
12470
12363
  document.body.appendChild(this._dialog);
12471
12364
  }
12472
- withSavedRange((range) => {
12473
- this._savedRange = range;
12474
- });
12365
+ this._saveRange();
12475
12366
  this._activeCat = "all";
12476
12367
  this._searchInput.value = "";
12477
12368
  this._updateCatTabs();
@@ -12540,6 +12431,7 @@
12540
12431
  grid.appendChild(cell);
12541
12432
  });
12542
12433
  this._grid = grid;
12434
+ this._firstInput = searchInput;
12543
12435
  const btnRow = createElement("div", { class: "an-dialog-actions" });
12544
12436
  const cancelBtn = createElement("button", {
12545
12437
  type: "button",
@@ -12629,21 +12521,6 @@
12629
12521
  editable.focus();
12630
12522
  this.context.invoke("editor.afterCommand");
12631
12523
  }
12632
- _open() {
12633
- if (this._dialog) {
12634
- this._dialog.style.display = "flex";
12635
- this._removeTrap = trapFocus(this._dialog, () => this._close());
12636
- setTimeout(() => this._searchInput?.focus(), 50);
12637
- }
12638
- }
12639
- _close() {
12640
- if (this._dialog) this._dialog.style.display = "none";
12641
- if (this._removeTrap) {
12642
- this._removeTrap();
12643
- this._removeTrap = null;
12644
- }
12645
- this._savedRange = null;
12646
- }
12647
12524
  };
12648
12525
  //#endregion
12649
12526
  //#region src/js/module/IconDialog.js
@@ -12901,19 +12778,9 @@
12901
12778
  ["gift", "objects"],
12902
12779
  ["puzzle-piece", "objects"]
12903
12780
  ];
12904
- var IconDialog = class {
12905
- /**
12906
- * @param {import('../Context.js').Context} context
12907
- */
12908
- constructor(context) {
12909
- this.context = context;
12910
- /** @type {HTMLElement|null} */
12911
- this._dialog = null;
12912
- this._disposers = [];
12913
- this._savedRange = null;
12914
- this._selectedIcon = null;
12915
- this._activeCat = "all";
12916
- }
12781
+ var IconDialog = class extends BaseDialog {
12782
+ _selectedIcon = null;
12783
+ _activeCat = "all";
12917
12784
  initialize() {
12918
12785
  this._ensureFontAwesome();
12919
12786
  return this;
@@ -12937,20 +12804,12 @@
12937
12804
  link.referrerPolicy = "no-referrer";
12938
12805
  document.head.appendChild(link);
12939
12806
  }
12940
- destroy() {
12941
- this._disposers.forEach((d) => d());
12942
- this._disposers = [];
12943
- this._dialog?.remove();
12944
- this._dialog = null;
12945
- }
12946
12807
  show() {
12947
12808
  if (!this._dialog) {
12948
12809
  this._dialog = this._buildDialog();
12949
12810
  document.body.appendChild(this._dialog);
12950
12811
  }
12951
- withSavedRange((range) => {
12952
- this._savedRange = range;
12953
- });
12812
+ this._saveRange();
12954
12813
  this._selectedIcon = null;
12955
12814
  this._activeCat = "all";
12956
12815
  this._searchInput.value = "";
@@ -12991,6 +12850,7 @@
12991
12850
  autocomplete: "off"
12992
12851
  });
12993
12852
  this._searchInput = searchInput;
12853
+ this._firstInput = searchInput;
12994
12854
  const catBar = createElement("div", { class: "an-icon-cats" });
12995
12855
  const allTab = createElement("button", {
12996
12856
  type: "button",
@@ -13229,21 +13089,9 @@
13229
13089
  }
13230
13090
  this.context.invoke("editor.afterCommand");
13231
13091
  }
13232
- _open() {
13233
- if (this._dialog) {
13234
- this._dialog.style.display = "flex";
13235
- this._removeTrap = trapFocus(this._dialog, () => this._close());
13236
- setTimeout(() => this._searchInput?.focus(), 50);
13237
- }
13238
- }
13239
13092
  _close() {
13240
- if (this._dialog) this._dialog.style.display = "none";
13241
- if (this._removeTrap) {
13242
- this._removeTrap();
13243
- this._removeTrap = null;
13244
- }
13245
- this._savedRange = null;
13246
13093
  this._selectedIcon = null;
13094
+ super._close();
13247
13095
  }
13248
13096
  };
13249
13097
  //#endregion
@@ -13984,59 +13832,25 @@
13984
13832
  }]
13985
13833
  }
13986
13834
  ];
13987
- var ShortcutsDialog = class {
13988
- /** @param {import('../Context.js').Context} context */
13989
- constructor(context) {
13990
- this.context = context;
13991
- this._dialog = null;
13992
- this._closeBtn = null;
13993
- this._disposers = [];
13994
- }
13995
- initialize() {
13996
- this._dialog = this._buildDialog();
13997
- document.body.appendChild(this._dialog);
13998
- return this;
13999
- }
14000
- destroy() {
14001
- this._disposers.forEach((d) => d());
14002
- this._disposers = [];
14003
- this._dialog?.remove();
14004
- this._dialog = null;
14005
- }
13835
+ var ICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="7" width="20" height="14" rx="2"/><path d="M6 11h.01M10 11h.01M14 11h.01M18 11h.01M6 15h.01M18 15h.01M10 15h4"/><path d="M7 3l5 4 5-4"/></svg>`;
13836
+ var ShortcutsDialog = class extends BaseDialog {
14006
13837
  show() {
14007
- if (this._dialog) {
14008
- this._dialog.style.display = "flex";
14009
- this._removeTrap = trapFocus(this._dialog, () => this._close());
14010
- setTimeout(() => this._closeBtn?.focus(), 50);
14011
- }
14012
- }
14013
- _close() {
14014
- if (this._dialog) this._dialog.style.display = "none";
14015
- if (this._removeTrap) {
14016
- this._removeTrap();
14017
- this._removeTrap = null;
14018
- }
13838
+ this._open();
14019
13839
  }
14020
13840
  _buildDialog() {
14021
- const overlay = createElement("div", {
14022
- class: "an-dialog-overlay",
14023
- role: "dialog",
14024
- "aria-modal": "true",
14025
- "aria-label": this.context.locale.shortcutsDialog.ariaLabel
14026
- });
14027
- const box = createElement("div", { class: "an-dialog-box an-shortcuts-box" });
14028
- const titleRow = createElement("div", { class: "an-icon-title-row" });
14029
- const title = createElement("h3", { class: "an-dialog-title" });
14030
- title.textContent = this.context.locale.shortcutsDialog.title;
13841
+ const L = this.context.locale.shortcutsDialog;
13842
+ const { overlay, box } = this._buildDialogShell(L.ariaLabel, ICON_SVG, L.title);
13843
+ box.classList.add("an-shortcuts-box");
14031
13844
  const closeBtn = createElement("button", {
14032
13845
  type: "button",
14033
13846
  class: "an-icon-close",
14034
- "aria-label": this.context.locale.shortcutsDialog.close
13847
+ "aria-label": L.close,
13848
+ style: "margin-left:auto"
14035
13849
  });
14036
13850
  closeBtn.textContent = "×";
14037
13851
  this._closeBtn = closeBtn;
14038
- titleRow.append(title, closeBtn);
14039
- box.appendChild(titleRow);
13852
+ this._firstInput = closeBtn;
13853
+ box.querySelector(".an-dialog-header").appendChild(closeBtn);
14040
13854
  (this.context.locale.shortcutsDialog.shortcuts || SHORTCUTS).forEach(({ category, items }) => {
14041
13855
  const catEl = createElement("div", { class: "an-shortcuts-cat" });
14042
13856
  catEl.textContent = category;
@@ -14053,12 +13867,8 @@
14053
13867
  });
14054
13868
  box.appendChild(table);
14055
13869
  });
14056
- overlay.appendChild(box);
14057
13870
  const d1 = on(closeBtn, "click", () => this._close());
14058
- const d2 = on(overlay, "click", (e) => {
14059
- if (e.target === overlay) this._close();
14060
- });
14061
- this._disposers.push(d1, d2);
13871
+ this._disposers.push(d1);
14062
13872
  return overlay;
14063
13873
  }
14064
13874
  };
@@ -14072,12 +13882,10 @@
14072
13882
  * for highlighting. Supports case-sensitive search, Prev/Next navigation and
14073
13883
  * single / replace-all replacement.
14074
13884
  */
14075
- var FindReplace = class {
13885
+ var FindReplace = class extends BaseDialog {
14076
13886
  /** @param {import('../Context.js').Context} context */
14077
13887
  constructor(context) {
14078
- this.context = context;
14079
- /** @type {HTMLElement|null} */
14080
- this._dialog = null;
13888
+ super(context);
14081
13889
  /** @type {HTMLInputElement|null} */
14082
13890
  this._findInput = null;
14083
13891
  /** @type {HTMLInputElement|null} */
@@ -14098,23 +13906,13 @@
14098
13906
  this._queryRegex = null;
14099
13907
  this._lastQuery = null;
14100
13908
  this._lastCaseSensitive = null;
14101
- this._disposers = [];
14102
- this._removeTrap = null;
14103
13909
  this._focusTimer = null;
14104
13910
  }
14105
- initialize() {
14106
- this._dialog = this._buildDialog();
14107
- document.body.appendChild(this._dialog);
14108
- return this;
14109
- }
14110
13911
  destroy() {
14111
13912
  clearTimeout(this._focusTimer);
14112
13913
  this._focusTimer = null;
14113
13914
  this._clearHighlights();
14114
- this._disposers.forEach((d) => d());
14115
- this._disposers = [];
14116
- if (this._dialog && this._dialog.parentNode) this._dialog.remove();
14117
- this._dialog = null;
13915
+ super.destroy();
14118
13916
  }
14119
13917
  /**
14120
13918
  * Opens the dialog in 'find' or 'replace' mode.
@@ -16029,7 +15827,7 @@
16029
15827
  register("markdownShortcuts", MarkdownShortcuts);
16030
15828
  register("bubbleToolbar", BubbleToolbar);
16031
15829
  register("mention", Mention);
16032
- for (const [name, ModuleClass] of _customModules) register(name, ModuleClass);
15830
+ if (_customModules.size > 0) for (const [name, ModuleClass] of _customModules) register(name, ModuleClass);
16033
15831
  }
16034
15832
  /**
16035
15833
  * Registers and initialises a custom module on this instance.
@@ -16082,6 +15880,7 @@
16082
15880
  });
16083
15881
  }
16084
15882
  _applyGlobalPlugins() {
15883
+ if (_globalPlugins.size === 0) return;
16085
15884
  for (const { plugin, options } of _globalPlugins.values()) this._installPlugin(plugin, options);
16086
15885
  }
16087
15886
  _bindEditorEvents(editable) {
@@ -16478,7 +16277,7 @@
16478
16277
  return this;
16479
16278
  },
16480
16279
  /** Library version */
16481
- version: "1.5.0"
16280
+ version: "1.6.3"
16482
16281
  };
16483
16282
  /**
16484
16283
  * @param {string|Element|NodeList|Element[]} selector