autumnnote 1.3.0 → 1.4.0
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 +66 -10
- package/dist/autumnnote.es.js +126 -4
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.umd.js +125 -3
- package/dist/autumnnote.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/js/Context.js +64 -0
- package/src/js/index.js +42 -2
- package/src/js/module/Buttons.js +37 -0
- package/src/js/module/Toolbar.js +33 -2
- package/types/index.d.ts +54 -1
package/dist/autumnnote.umd.js
CHANGED
|
@@ -803,6 +803,34 @@
|
|
|
803
803
|
isDisabled
|
|
804
804
|
};
|
|
805
805
|
}
|
|
806
|
+
/**
|
|
807
|
+
* Global registry for custom buttons registered via AutumnNote.registerButton()
|
|
808
|
+
* or via a plugin's `buttons` array. Toolbar resolves string names from here.
|
|
809
|
+
* @type {Map<string, object>}
|
|
810
|
+
*/
|
|
811
|
+
var _buttonRegistry = /* @__PURE__ */ new Map();
|
|
812
|
+
/**
|
|
813
|
+
* Registers a button definition in the global registry so it can be referenced
|
|
814
|
+
* by string name in toolbar configuration: `toolbar: [['myBtn', boldBtn]]`.
|
|
815
|
+
* @param {object} btnDef - Any ToolbarItemDef-compatible object with a `name` string.
|
|
816
|
+
*/
|
|
817
|
+
function registerButton(btnDef) {
|
|
818
|
+
if (!btnDef || typeof btnDef.name !== "string") {
|
|
819
|
+
console.warn("[AutumnNote] registerButton: btnDef must have a string `name` property.");
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
if (_buttonRegistry.has(btnDef.name)) console.warn(`[AutumnNote] registerButton: overwriting existing button "${btnDef.name}".`);
|
|
823
|
+
_buttonRegistry.set(btnDef.name, btnDef);
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* Looks up a button definition by name from the global registry.
|
|
827
|
+
* Returns undefined when not found.
|
|
828
|
+
* @param {string} name
|
|
829
|
+
* @returns {object|undefined}
|
|
830
|
+
*/
|
|
831
|
+
function getButton(name) {
|
|
832
|
+
return _buttonRegistry.get(name);
|
|
833
|
+
}
|
|
806
834
|
var boldBtn = btn("bold", "bold", "Bold (Ctrl+B)", () => bold(), () => document.queryCommandState("bold"));
|
|
807
835
|
var italicBtn = btn("italic", "italic", "Italic (Ctrl+I)", () => italic(), () => document.queryCommandState("italic"));
|
|
808
836
|
var underlineBtn = btn("underline", "underline", "Underline (Ctrl+U)", () => underline(), () => {
|
|
@@ -5502,6 +5530,8 @@
|
|
|
5502
5530
|
* Toolbar.js - Builds and manages the editor toolbar UI
|
|
5503
5531
|
* Inspired by Summernote's Toolbar module — rewritten without jQuery
|
|
5504
5532
|
*/
|
|
5533
|
+
/** Resolve a toolbar item: string → registry lookup, object → pass-through. */
|
|
5534
|
+
var _resolveBtn = (item) => typeof item === "string" ? getButton(item) : item;
|
|
5505
5535
|
var _faPageLevelReady = null;
|
|
5506
5536
|
var _S$1 = "stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"";
|
|
5507
5537
|
var _svgWrap = (paths) => `<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" ${_S$1} style="display:block">${paths}</svg>`;
|
|
@@ -5598,7 +5628,7 @@
|
|
|
5598
5628
|
this.el = createElement("div", { class: "an-toolbar" });
|
|
5599
5629
|
this._faReady = this._detectFontAwesome();
|
|
5600
5630
|
this._buildButtons();
|
|
5601
|
-
this._btnMap = new Map((this.options.toolbar || []).flat().map((b) => [b.name, b]));
|
|
5631
|
+
this._btnMap = new Map((this.options.toolbar || []).flat().map(_resolveBtn).filter(Boolean).map((b) => [b.name, b]));
|
|
5602
5632
|
return this;
|
|
5603
5633
|
}
|
|
5604
5634
|
destroy() {
|
|
@@ -5614,7 +5644,12 @@
|
|
|
5614
5644
|
const fragment = document.createDocumentFragment();
|
|
5615
5645
|
toolbar.forEach((group) => {
|
|
5616
5646
|
const groupEl = createElement("div", { class: "an-btn-group" });
|
|
5617
|
-
group.forEach((
|
|
5647
|
+
group.forEach((item) => {
|
|
5648
|
+
const btnDef = _resolveBtn(item);
|
|
5649
|
+
if (!btnDef) {
|
|
5650
|
+
console.warn(`[AutumnNote] Toolbar: button "${item}" not found in registry. Skipped.`);
|
|
5651
|
+
return;
|
|
5652
|
+
}
|
|
5618
5653
|
let el;
|
|
5619
5654
|
if (btnDef.type === "select") el = this._createSelect(btnDef);
|
|
5620
5655
|
else if (btnDef.type === "grid") el = this._createGridPicker(btnDef);
|
|
@@ -6034,6 +6069,24 @@
|
|
|
6034
6069
|
hide() {
|
|
6035
6070
|
if (this.el) this.el.style.display = "none";
|
|
6036
6071
|
}
|
|
6072
|
+
/**
|
|
6073
|
+
* Tears down and re-renders the toolbar in-place.
|
|
6074
|
+
* Call after registering new buttons post-create via context.use(plugin)
|
|
6075
|
+
* or AutumnNote.registerButton() to make them appear in the toolbar.
|
|
6076
|
+
*/
|
|
6077
|
+
rebuild() {
|
|
6078
|
+
if (this._refreshRaf) {
|
|
6079
|
+
cancelAnimationFrame(this._refreshRaf);
|
|
6080
|
+
this._refreshRaf = null;
|
|
6081
|
+
}
|
|
6082
|
+
this._disposers.forEach((d) => d());
|
|
6083
|
+
this._disposers = [];
|
|
6084
|
+
if (this.el) this.el.innerHTML = "";
|
|
6085
|
+
this._faReady = this._detectFontAwesome();
|
|
6086
|
+
this._buildButtons();
|
|
6087
|
+
this._btnMap = new Map((this.options.toolbar || []).flat().map(_resolveBtn).filter(Boolean).map((b) => [b.name, b]));
|
|
6088
|
+
this.refresh();
|
|
6089
|
+
}
|
|
6037
6090
|
};
|
|
6038
6091
|
//#endregion
|
|
6039
6092
|
//#region src/js/module/Statusbar.js
|
|
@@ -15481,6 +15534,8 @@
|
|
|
15481
15534
|
*/
|
|
15482
15535
|
/** Module registry shared across all Context instances (populated via AutumnNote.registerModule). */
|
|
15483
15536
|
var _customModules = /* @__PURE__ */ new Map();
|
|
15537
|
+
/** Global plugin registry (populated via AutumnNote.use()). Applied to every new Context. */
|
|
15538
|
+
var _globalPlugins = /* @__PURE__ */ new Map();
|
|
15484
15539
|
var Context = class {
|
|
15485
15540
|
/**
|
|
15486
15541
|
* @param {HTMLElement} targetEl - The element to replace with the editor
|
|
@@ -15497,6 +15552,8 @@
|
|
|
15497
15552
|
this._listeners = /* @__PURE__ */ new Map();
|
|
15498
15553
|
/** @type {Map<string, object>} */
|
|
15499
15554
|
this._modules = /* @__PURE__ */ new Map();
|
|
15555
|
+
/** @type {Map<string, { plugin: object, publicApi: * }>} */
|
|
15556
|
+
this._plugins = /* @__PURE__ */ new Map();
|
|
15500
15557
|
this._disposers = [];
|
|
15501
15558
|
this._alive = false;
|
|
15502
15559
|
}
|
|
@@ -15519,6 +15576,7 @@
|
|
|
15519
15576
|
if (this.options.focus) editable.focus();
|
|
15520
15577
|
this._alive = true;
|
|
15521
15578
|
this.invoke("toolbar.refresh");
|
|
15579
|
+
this._applyGlobalPlugins();
|
|
15522
15580
|
if (typeof this.options.onInit === "function") this.options.onInit(this);
|
|
15523
15581
|
return this;
|
|
15524
15582
|
}
|
|
@@ -15570,6 +15628,46 @@
|
|
|
15570
15628
|
this._modules.set(name, instance);
|
|
15571
15629
|
return this;
|
|
15572
15630
|
}
|
|
15631
|
+
/**
|
|
15632
|
+
* Installs a plugin on this editor instance.
|
|
15633
|
+
* If called after create(), buttons are registered immediately but the toolbar
|
|
15634
|
+
* must be rebuilt via ctx.invoke('toolbar.rebuild') to render new buttons.
|
|
15635
|
+
* @param {object} plugin - { name, version?, buttons?, install?, uninstall? }
|
|
15636
|
+
* @param {object} [options] - Forwarded to plugin.install(context, options)
|
|
15637
|
+
* @returns {this}
|
|
15638
|
+
*/
|
|
15639
|
+
use(plugin, options = {}) {
|
|
15640
|
+
if (Array.isArray(plugin.buttons)) plugin.buttons.forEach((b) => registerButton(b));
|
|
15641
|
+
this._installPlugin(plugin, options);
|
|
15642
|
+
return this;
|
|
15643
|
+
}
|
|
15644
|
+
/**
|
|
15645
|
+
* Returns the public API returned by plugin.install(), or null.
|
|
15646
|
+
* @param {string} name
|
|
15647
|
+
* @returns {*}
|
|
15648
|
+
*/
|
|
15649
|
+
getPlugin(name) {
|
|
15650
|
+
return this._plugins.get(name)?.publicApi ?? null;
|
|
15651
|
+
}
|
|
15652
|
+
_installPlugin(plugin, pluginOptions = {}) {
|
|
15653
|
+
const { name } = plugin;
|
|
15654
|
+
if (!name || typeof name !== "string") {
|
|
15655
|
+
console.warn("[AutumnNote] Plugin must have a string `name` property.");
|
|
15656
|
+
return;
|
|
15657
|
+
}
|
|
15658
|
+
if (this._plugins.has(name)) {
|
|
15659
|
+
console.warn(`[AutumnNote] Plugin "${name}" already installed on this instance. Skipping.`);
|
|
15660
|
+
return;
|
|
15661
|
+
}
|
|
15662
|
+
const publicApi = typeof plugin.install === "function" ? plugin.install(this, pluginOptions) ?? null : null;
|
|
15663
|
+
this._plugins.set(name, {
|
|
15664
|
+
plugin,
|
|
15665
|
+
publicApi
|
|
15666
|
+
});
|
|
15667
|
+
}
|
|
15668
|
+
_applyGlobalPlugins() {
|
|
15669
|
+
for (const { plugin, options } of _globalPlugins.values()) this._installPlugin(plugin, options);
|
|
15670
|
+
}
|
|
15573
15671
|
_bindEditorEvents(editable) {
|
|
15574
15672
|
const d0 = on(editable, "input", () => this._syncToTarget());
|
|
15575
15673
|
const d1 = on(editable, "focus", () => {
|
|
@@ -15820,6 +15918,10 @@
|
|
|
15820
15918
|
if (typeof module.destroy === "function") module.destroy();
|
|
15821
15919
|
});
|
|
15822
15920
|
this._modules.clear();
|
|
15921
|
+
for (const { plugin } of this._plugins.values()) if (typeof plugin.uninstall === "function") try {
|
|
15922
|
+
plugin.uninstall(this);
|
|
15923
|
+
} catch (_) {}
|
|
15924
|
+
this._plugins.clear();
|
|
15823
15925
|
this._disposers.forEach((d) => d());
|
|
15824
15926
|
this._disposers = [];
|
|
15825
15927
|
const container = this.layoutInfo.container;
|
|
@@ -15888,7 +15990,27 @@
|
|
|
15888
15990
|
registerModule(name, ModuleClass) {
|
|
15889
15991
|
_customModules.set(name, ModuleClass);
|
|
15890
15992
|
},
|
|
15891
|
-
|
|
15993
|
+
use(plugin, options = {}) {
|
|
15994
|
+
if (!plugin || typeof plugin.name !== "string") throw new TypeError("[AutumnNote] AutumnNote.use: plugin must have a string `name` property.");
|
|
15995
|
+
if (_globalPlugins.has(plugin.name)) {
|
|
15996
|
+
console.warn(`[AutumnNote] Plugin "${plugin.name}" already registered globally. Skipping.`);
|
|
15997
|
+
return this;
|
|
15998
|
+
}
|
|
15999
|
+
if (Array.isArray(plugin.buttons)) plugin.buttons.forEach((b) => registerButton(b));
|
|
16000
|
+
_globalPlugins.set(plugin.name, {
|
|
16001
|
+
plugin,
|
|
16002
|
+
options
|
|
16003
|
+
});
|
|
16004
|
+
return this;
|
|
16005
|
+
},
|
|
16006
|
+
hasPlugin(name) {
|
|
16007
|
+
return _globalPlugins.has(name);
|
|
16008
|
+
},
|
|
16009
|
+
registerButton(btnDef) {
|
|
16010
|
+
registerButton(btnDef);
|
|
16011
|
+
return this;
|
|
16012
|
+
},
|
|
16013
|
+
version: "1.4.0"
|
|
15892
16014
|
};
|
|
15893
16015
|
/**
|
|
15894
16016
|
* @param {string|Element|NodeList|Element[]} selector
|