@editora/core 1.0.1 → 1.0.2
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 +9 -0
- package/dist/A11yCheckerPlugin.native-CZKpi3uF.mjs +475 -0
- package/dist/A11yCheckerPlugin.native-CZKpi3uF.mjs.map +1 -0
- package/dist/AnchorPlugin.native-7es9PVZ9.mjs +340 -0
- package/dist/AnchorPlugin.native-7es9PVZ9.mjs.map +1 -0
- package/dist/BackgroundColorPlugin.native-Dip5uqTg.mjs +449 -0
- package/dist/BackgroundColorPlugin.native-Dip5uqTg.mjs.map +1 -0
- package/dist/BlockquotePlugin.native-JFmOLsxN.mjs +48 -0
- package/dist/BlockquotePlugin.native-JFmOLsxN.mjs.map +1 -0
- package/dist/BoldPlugin.native-BAzzoqU5.mjs +45 -0
- package/dist/BoldPlugin.native-BAzzoqU5.mjs.map +1 -0
- package/dist/CapitalizationPlugin.native-DOMsh5R7.mjs +79 -0
- package/dist/CapitalizationPlugin.native-DOMsh5R7.mjs.map +1 -0
- package/dist/ChecklistPlugin.native-Dccs3nLe.mjs +153 -0
- package/dist/ChecklistPlugin.native-Dccs3nLe.mjs.map +1 -0
- package/dist/ClearFormattingPlugin.native-BZPDHswo.mjs +27 -0
- package/dist/ClearFormattingPlugin.native-BZPDHswo.mjs.map +1 -0
- package/dist/CodePlugin.native-DD9xFIid.mjs +1679 -0
- package/dist/CodePlugin.native-DD9xFIid.mjs.map +1 -0
- package/dist/CodeSamplePlugin.native-DMbEdO9j.mjs +326 -0
- package/dist/CodeSamplePlugin.native-DMbEdO9j.mjs.map +1 -0
- package/dist/CommentsPlugin.native-2zQV8Ia4.mjs +473 -0
- package/dist/CommentsPlugin.native-2zQV8Ia4.mjs.map +1 -0
- package/dist/DirectionPlugin.native-Be7wCzkI.mjs +59 -0
- package/dist/DirectionPlugin.native-Be7wCzkI.mjs.map +1 -0
- package/dist/DocumentManagerPlugin.native-BvZL5CSG.mjs +116 -0
- package/dist/DocumentManagerPlugin.native-BvZL5CSG.mjs.map +1 -0
- package/dist/EmbedIframePlugin.native-ifr9KLdN.mjs +461 -0
- package/dist/EmbedIframePlugin.native-ifr9KLdN.mjs.map +1 -0
- package/dist/EmojisPlugin.native-D6mJSnSR.mjs +1033 -0
- package/dist/EmojisPlugin.native-D6mJSnSR.mjs.map +1 -0
- package/dist/FontFamilyPlugin.native-BzS_9qbM.mjs +106 -0
- package/dist/FontFamilyPlugin.native-BzS_9qbM.mjs.map +1 -0
- package/dist/FontSizePlugin.native-DkLMLPue.mjs +186 -0
- package/dist/FontSizePlugin.native-DkLMLPue.mjs.map +1 -0
- package/dist/FootnotePlugin.native-BciVc9W6.mjs +128 -0
- package/dist/FootnotePlugin.native-BciVc9W6.mjs.map +1 -0
- package/dist/FullscreenPlugin.native-ChXyxeNw.mjs +77 -0
- package/dist/FullscreenPlugin.native-ChXyxeNw.mjs.map +1 -0
- package/dist/HeadingPlugin.native-DrLYwQnQ.mjs +64 -0
- package/dist/HeadingPlugin.native-DrLYwQnQ.mjs.map +1 -0
- package/dist/HistoryPlugin.native-DoDRifCf.mjs +89 -0
- package/dist/HistoryPlugin.native-DoDRifCf.mjs.map +1 -0
- package/dist/IndentPlugin.native-CbFugPoi.mjs +133 -0
- package/dist/IndentPlugin.native-CbFugPoi.mjs.map +1 -0
- package/dist/ItalicPlugin.native-CQjjDyUL.mjs +43 -0
- package/dist/ItalicPlugin.native-CQjjDyUL.mjs.map +1 -0
- package/dist/LineHeightPlugin.native-CWQT2FIa.mjs +73 -0
- package/dist/LineHeightPlugin.native-CWQT2FIa.mjs.map +1 -0
- package/dist/LinkPlugin.native-BdAOV-iu.mjs +206 -0
- package/dist/LinkPlugin.native-BdAOV-iu.mjs.map +1 -0
- package/dist/ListPlugin.native-CLFU5AUQ.mjs +59 -0
- package/dist/ListPlugin.native-CLFU5AUQ.mjs.map +1 -0
- package/dist/MathPlugin.native-DE_ii-LA.mjs +182 -0
- package/dist/MathPlugin.native-DE_ii-LA.mjs.map +1 -0
- package/dist/MediaManagerPlugin.native-DaYFDzNM.mjs +533 -0
- package/dist/MediaManagerPlugin.native-DaYFDzNM.mjs.map +1 -0
- package/dist/MergeTagPlugin.native-CrxyThyn.mjs +178 -0
- package/dist/MergeTagPlugin.native-CrxyThyn.mjs.map +1 -0
- package/dist/PageBreakPlugin.native-DDjcDyRW.mjs +172 -0
- package/dist/PageBreakPlugin.native-DDjcDyRW.mjs.map +1 -0
- package/dist/PreviewPlugin.native-DBvfpmIv.mjs +322 -0
- package/dist/PreviewPlugin.native-DBvfpmIv.mjs.map +1 -0
- package/dist/PrintPlugin.native-BUpm52VJ.mjs +311 -0
- package/dist/PrintPlugin.native-BUpm52VJ.mjs.map +1 -0
- package/dist/SpecialCharactersPlugin.native-x7a2SWXc.mjs +731 -0
- package/dist/SpecialCharactersPlugin.native-x7a2SWXc.mjs.map +1 -0
- package/dist/SpellCheckPlugin.native-B7yTh0iE.mjs +465 -0
- package/dist/SpellCheckPlugin.native-B7yTh0iE.mjs.map +1 -0
- package/dist/StrikethroughPlugin.native-ChaZLaXw.mjs +43 -0
- package/dist/StrikethroughPlugin.native-ChaZLaXw.mjs.map +1 -0
- package/dist/TablePlugin.native-EEWXn1-s.mjs +491 -0
- package/dist/TablePlugin.native-EEWXn1-s.mjs.map +1 -0
- package/dist/TemplatePlugin.native-BlSn1c9h.mjs +564 -0
- package/dist/TemplatePlugin.native-BlSn1c9h.mjs.map +1 -0
- package/dist/TextAlignmentPlugin.native-CQIs1m7R.mjs +97 -0
- package/dist/TextAlignmentPlugin.native-CQIs1m7R.mjs.map +1 -0
- package/dist/TextColorPlugin.native-D6SmTglm.mjs +432 -0
- package/dist/TextColorPlugin.native-D6SmTglm.mjs.map +1 -0
- package/dist/UnderlinePlugin.native-QpIcK4L2.mjs +35 -0
- package/dist/UnderlinePlugin.native-QpIcK4L2.mjs.map +1 -0
- package/dist/documentManager-irzj9n3V.mjs +37627 -0
- package/dist/documentManager-irzj9n3V.mjs.map +1 -0
- package/dist/editorContainerHelpers-C7kdWnS0.mjs +27 -0
- package/dist/editorContainerHelpers-C7kdWnS0.mjs.map +1 -0
- package/dist/editora.min.js +14 -12
- package/dist/editora.min.js.map +1 -1
- package/dist/editora.umd.js +14 -12
- package/dist/editora.umd.js.map +1 -1
- package/dist/index-BF5RBhL9.js +4 -0
- package/dist/index-BF5RBhL9.js.map +1 -0
- package/dist/{index-BS4zT-KN.mjs → index-BPsf460l.mjs} +286 -162
- package/dist/index-BPsf460l.mjs.map +1 -0
- package/dist/index.cjs.js +3 -3
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es-CuicffkQ.mjs +6665 -0
- package/dist/index.es-CuicffkQ.mjs.map +1 -0
- package/dist/index.esm.js +117 -112
- package/dist/index.esm.js.map +1 -1
- package/dist/plugin-loader.js +55 -0
- package/dist/plugin-loader.js.map +1 -0
- package/dist/purify.es-CKpwg8Tk.mjs +471 -0
- package/dist/purify.es-CKpwg8Tk.mjs.map +1 -0
- package/dist/webcomponent-core.js +1243 -0
- package/dist/webcomponent-core.js.map +1 -0
- package/dist/webcomponent-core.min.css +1 -0
- package/dist/webcomponent-core.min.js +597 -0
- package/dist/webcomponent-core.min.js.map +1 -0
- package/dist/webcomponent.cjs.js +1 -1
- package/dist/webcomponent.esm.js +3 -3
- package/dist/webcomponent.js +1286 -0
- package/dist/webcomponent.js.map +1 -0
- package/dist/webcomponent.min.css +1 -0
- package/dist/webcomponent.min.js +337 -334
- package/dist/webcomponent.min.js.map +1 -1
- package/package.json +16 -4
- package/dist/index-BK2lHfHK.js +0 -2
- package/dist/index-BK2lHfHK.js.map +0 -1
- package/dist/index-BS4zT-KN.mjs.map +0 -1
- package/dist/webcomponent.umd.js +0 -4073
- package/dist/webcomponent.umd.js.map +0 -1
|
@@ -0,0 +1,1243 @@
|
|
|
1
|
+
class w {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.loadedPlugins = /* @__PURE__ */ new Map(), this.pluginRegistry = /* @__PURE__ */ new Map();
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Register a plugin factory (sync or async)
|
|
7
|
+
*/
|
|
8
|
+
register(t, e) {
|
|
9
|
+
this.pluginRegistry.set(t, e);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Load a plugin by name (async)
|
|
13
|
+
*/
|
|
14
|
+
async load(t, e) {
|
|
15
|
+
if (this.loadedPlugins.has(t))
|
|
16
|
+
return this.loadedPlugins.get(t);
|
|
17
|
+
const o = this.pluginRegistry.get(t);
|
|
18
|
+
if (!o)
|
|
19
|
+
return console.warn(`Plugin not found: ${t}`), null;
|
|
20
|
+
const i = await o();
|
|
21
|
+
return e && this.applyPluginConfig(i, e), this.loadedPlugins.set(t, i), i;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Load multiple plugins
|
|
25
|
+
*/
|
|
26
|
+
async loadMultiple(t, e) {
|
|
27
|
+
return (await Promise.all(
|
|
28
|
+
t.map((i) => this.load(i, e))
|
|
29
|
+
)).filter((i) => i !== null);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parse plugin string "lists link image media"
|
|
33
|
+
*/
|
|
34
|
+
async parsePluginString(t, e) {
|
|
35
|
+
const o = t.split(/\s+/).filter(Boolean);
|
|
36
|
+
return this.loadMultiple(o, e);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Apply configuration to plugin
|
|
40
|
+
*/
|
|
41
|
+
applyPluginConfig(t, e) {
|
|
42
|
+
t.__pluginConfig = e;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Unload a plugin
|
|
46
|
+
*/
|
|
47
|
+
unload(t) {
|
|
48
|
+
this.loadedPlugins.delete(t);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Clear all loaded plugins
|
|
52
|
+
*/
|
|
53
|
+
clear() {
|
|
54
|
+
this.loadedPlugins.clear();
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get all loaded plugins
|
|
58
|
+
*/
|
|
59
|
+
getLoadedPlugins() {
|
|
60
|
+
return Array.from(this.loadedPlugins.values());
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get all registered plugin names (available for loading)
|
|
64
|
+
*/
|
|
65
|
+
getRegisteredPluginNames() {
|
|
66
|
+
return Array.from(this.pluginRegistry.keys());
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Check if plugin is loaded
|
|
70
|
+
*/
|
|
71
|
+
isLoaded(t) {
|
|
72
|
+
return this.loadedPlugins.has(t);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
class f {
|
|
76
|
+
constructor(t, e, o) {
|
|
77
|
+
this.doc = t, this.selection = e, this.schema = o;
|
|
78
|
+
}
|
|
79
|
+
static create(t, e) {
|
|
80
|
+
const o = e || t.node("doc", {}, [t.node("paragraph")]);
|
|
81
|
+
return new f(o, { anchor: 0, head: 0 }, t);
|
|
82
|
+
}
|
|
83
|
+
apply(t, e) {
|
|
84
|
+
return new f(t, e || this.selection, this.schema);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
class E {
|
|
88
|
+
constructor(t, e) {
|
|
89
|
+
this.nodes = new Map(Object.entries(t)), this.marks = new Map(Object.entries(e));
|
|
90
|
+
}
|
|
91
|
+
node(t, e, o) {
|
|
92
|
+
return { type: t, attrs: e, content: o };
|
|
93
|
+
}
|
|
94
|
+
text(t, e) {
|
|
95
|
+
return { type: "text", text: t, marks: e };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
class C {
|
|
99
|
+
constructor() {
|
|
100
|
+
this.plugins = [], this.pluginConfigs = /* @__PURE__ */ new Map();
|
|
101
|
+
}
|
|
102
|
+
register(t, e) {
|
|
103
|
+
if (this.plugins.push(t), e && this.pluginConfigs.set(t.name, e), t.initialize) {
|
|
104
|
+
const o = this.pluginConfigs.get(t.name) || t.config;
|
|
105
|
+
t.initialize(o);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
unregister(t) {
|
|
109
|
+
const e = this.plugins.findIndex((o) => o.name === t);
|
|
110
|
+
if (e > -1) {
|
|
111
|
+
const o = this.plugins[e];
|
|
112
|
+
o.destroy && o.destroy(), this.plugins.splice(e, 1), this.pluginConfigs.delete(t);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
getPlugin(t) {
|
|
116
|
+
return this.plugins.find((e) => e.name === t);
|
|
117
|
+
}
|
|
118
|
+
getPluginConfig(t) {
|
|
119
|
+
return this.pluginConfigs.get(t);
|
|
120
|
+
}
|
|
121
|
+
buildSchema() {
|
|
122
|
+
const t = {}, e = {};
|
|
123
|
+
return this.plugins.forEach((o) => {
|
|
124
|
+
o.nodes && Object.assign(t, o.nodes), o.marks && Object.assign(e, o.marks);
|
|
125
|
+
}), new E(t, e);
|
|
126
|
+
}
|
|
127
|
+
getCommands() {
|
|
128
|
+
const t = {};
|
|
129
|
+
return this.plugins.forEach((e) => {
|
|
130
|
+
e.commands && Object.assign(t, e.commands);
|
|
131
|
+
}), t;
|
|
132
|
+
}
|
|
133
|
+
getToolbarItems() {
|
|
134
|
+
return this.plugins.flatMap((t) => t.toolbar || []);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Execute plugin command with mode awareness
|
|
138
|
+
*/
|
|
139
|
+
async executePluginCommand(t, e, ...o) {
|
|
140
|
+
const i = this.getPlugin(t);
|
|
141
|
+
if (!i)
|
|
142
|
+
throw new Error(`Plugin not found: ${t}`);
|
|
143
|
+
const n = this.getPluginConfig(t) || i.config || {}, a = n.mode || "local";
|
|
144
|
+
try {
|
|
145
|
+
switch (a) {
|
|
146
|
+
case "local":
|
|
147
|
+
return i.executeLocal ? i.executeLocal(e, ...o) : null;
|
|
148
|
+
case "api":
|
|
149
|
+
if (!i.executeAPI)
|
|
150
|
+
throw new Error(`Plugin ${t} does not support API mode`);
|
|
151
|
+
return await i.executeAPI(e, ...o);
|
|
152
|
+
case "hybrid":
|
|
153
|
+
if (i.executeHybrid)
|
|
154
|
+
return await i.executeHybrid(e, ...o);
|
|
155
|
+
try {
|
|
156
|
+
if (i.executeAPI)
|
|
157
|
+
return await i.executeAPI(e, ...o);
|
|
158
|
+
} catch (r) {
|
|
159
|
+
if (console.warn(`API execution failed for ${t}, falling back to local`, r), i.executeLocal && n.fallbackToLocal !== !1)
|
|
160
|
+
return i.executeLocal(e, ...o);
|
|
161
|
+
throw r;
|
|
162
|
+
}
|
|
163
|
+
break;
|
|
164
|
+
default:
|
|
165
|
+
throw new Error(`Unknown plugin mode: ${a}`);
|
|
166
|
+
}
|
|
167
|
+
} catch (r) {
|
|
168
|
+
throw console.error(`Error executing command ${e} on plugin ${t}:`, r), r;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Destroy all plugins
|
|
173
|
+
*/
|
|
174
|
+
async destroyAll() {
|
|
175
|
+
const t = this.plugins.filter((e) => e.destroy).map((e) => e.destroy());
|
|
176
|
+
await Promise.all(t), this.plugins = [], this.pluginConfigs.clear();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
class k {
|
|
180
|
+
constructor(t = {}) {
|
|
181
|
+
this.commands = /* @__PURE__ */ new Map(), Object.entries(t).forEach(([e, o]) => {
|
|
182
|
+
this.register(e, o);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Register a command
|
|
187
|
+
*/
|
|
188
|
+
register(t, e) {
|
|
189
|
+
this.commands.has(t) && console.warn(`Command ${t} is being overwritten`), this.commands.set(t, e);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Unregister a command
|
|
193
|
+
*/
|
|
194
|
+
unregister(t) {
|
|
195
|
+
this.commands.delete(t);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Get a command handler
|
|
199
|
+
*/
|
|
200
|
+
get(t) {
|
|
201
|
+
return this.commands.get(t);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Check if command exists
|
|
205
|
+
*/
|
|
206
|
+
has(t) {
|
|
207
|
+
return this.commands.has(t);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Get all command names
|
|
211
|
+
*/
|
|
212
|
+
getCommandNames() {
|
|
213
|
+
return Array.from(this.commands.keys());
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Clear all commands
|
|
217
|
+
*/
|
|
218
|
+
clear() {
|
|
219
|
+
this.commands.clear();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
class v {
|
|
223
|
+
constructor(t = {}) {
|
|
224
|
+
this.listeners = /* @__PURE__ */ new Map(), this.isReadonly = !1, this.isDestroyed = !1, this.isReadonly = t.readonly || !1, this.pluginManager = new C(), t.plugins && Array.isArray(t.plugins) && t.plugins.forEach((o) => this.pluginManager.register(o));
|
|
225
|
+
const e = this.pluginManager.buildSchema();
|
|
226
|
+
this.state = f.create(e), this.commandRegistry = new k(this.pluginManager.getCommands());
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Execute a command
|
|
230
|
+
*/
|
|
231
|
+
execCommand(t, e) {
|
|
232
|
+
if (this.isReadonly)
|
|
233
|
+
return console.warn("Cannot execute commands in readonly mode"), !1;
|
|
234
|
+
if (this.isDestroyed)
|
|
235
|
+
return console.warn("Cannot execute commands on destroyed editor"), !1;
|
|
236
|
+
const o = this.commandRegistry.get(t);
|
|
237
|
+
if (!o)
|
|
238
|
+
return console.warn(`Command not found: ${t}`), !1;
|
|
239
|
+
let i;
|
|
240
|
+
return e !== void 0 ? i = o(this.state, e) : i = o(this.state), i ? (this.setState(i), this.emit("change", this.state), !0) : !1;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Update editor state
|
|
244
|
+
*/
|
|
245
|
+
setState(t) {
|
|
246
|
+
this.isDestroyed || (this.state = t, this.emit("stateChange", t));
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Get current state
|
|
250
|
+
*/
|
|
251
|
+
getState() {
|
|
252
|
+
return this.state;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Set readonly mode
|
|
256
|
+
*/
|
|
257
|
+
setReadonly(t) {
|
|
258
|
+
this.isReadonly = t, this.emit("readonlyChange", t);
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Check if readonly
|
|
262
|
+
*/
|
|
263
|
+
isReadOnly() {
|
|
264
|
+
return this.isReadonly;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Event emitter
|
|
268
|
+
*/
|
|
269
|
+
on(t, e) {
|
|
270
|
+
return this.listeners.has(t) || this.listeners.set(t, []), this.listeners.get(t).push(e), () => {
|
|
271
|
+
const o = this.listeners.get(t);
|
|
272
|
+
if (o) {
|
|
273
|
+
const i = o.indexOf(e);
|
|
274
|
+
i > -1 && o.splice(i, 1);
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Emit event
|
|
280
|
+
*/
|
|
281
|
+
emit(t, ...e) {
|
|
282
|
+
const o = this.listeners.get(t);
|
|
283
|
+
o && o.forEach((i) => {
|
|
284
|
+
try {
|
|
285
|
+
i(...e);
|
|
286
|
+
} catch (n) {
|
|
287
|
+
console.error(`Error in ${t} handler:`, n);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Destroy editor instance
|
|
293
|
+
*/
|
|
294
|
+
destroy() {
|
|
295
|
+
this.isDestroyed || (this.isDestroyed = !0, this.listeners.clear(), this.emit("destroy"));
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Check if destroyed
|
|
299
|
+
*/
|
|
300
|
+
isEditorDestroyed() {
|
|
301
|
+
return this.isDestroyed;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
class L {
|
|
305
|
+
// PluginLoader instance to get all registered plugins
|
|
306
|
+
constructor(t, e, o) {
|
|
307
|
+
this.config = t, this.plugins = e, this.pluginLoader = o;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Set command handler for toolbar buttons
|
|
311
|
+
*/
|
|
312
|
+
setCommandHandler(t) {
|
|
313
|
+
this.commandHandler = t;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Parse toolbar string into button groups
|
|
317
|
+
*/
|
|
318
|
+
parseToolbarString(t) {
|
|
319
|
+
const e = [], o = t.split("|").map((r) => r.trim()), i = this.getAvailableToolbarItems(), n = /* @__PURE__ */ new Map();
|
|
320
|
+
i.forEach((r) => {
|
|
321
|
+
r.command && n.set(r.command, r), r.type === "group" && r.label && n.set(r.label, r);
|
|
322
|
+
});
|
|
323
|
+
const a = {
|
|
324
|
+
bold: "toggleBold",
|
|
325
|
+
italic: "toggleItalic",
|
|
326
|
+
underline: "toggleUnderline",
|
|
327
|
+
strikethrough: "toggleStrikethrough",
|
|
328
|
+
bullist: "toggleBulletList",
|
|
329
|
+
numlist: "toggleOrderedList",
|
|
330
|
+
checklist: "toggleChecklist",
|
|
331
|
+
link: "openLinkDialog",
|
|
332
|
+
image: "openImageDialog",
|
|
333
|
+
table: "insertTable",
|
|
334
|
+
anchor: "insertAnchor",
|
|
335
|
+
code: "toggleSourceView",
|
|
336
|
+
blockquote: "toggleBlockquote",
|
|
337
|
+
undo: "undo",
|
|
338
|
+
redo: "redo",
|
|
339
|
+
textColor: "openTextColorPicker",
|
|
340
|
+
backgroundColor: "openBackgroundColorPicker",
|
|
341
|
+
fontSize: "fontSize",
|
|
342
|
+
fontFamily: "setFontFamily",
|
|
343
|
+
lineHeight: "setLineHeight",
|
|
344
|
+
heading: "setBlockType",
|
|
345
|
+
paragraph: "setParagraph",
|
|
346
|
+
textAlignment: "setTextAlignment",
|
|
347
|
+
direction: "setDirectionLTR",
|
|
348
|
+
indent: "increaseIndent",
|
|
349
|
+
outdent: "decreaseIndent",
|
|
350
|
+
capitalization: "setCapitalization",
|
|
351
|
+
math: "insertMath",
|
|
352
|
+
specialCharacters: "insertSpecialCharacter",
|
|
353
|
+
emojis: "openEmojiDialog",
|
|
354
|
+
embedIframe: "openEmbedIframeDialog",
|
|
355
|
+
fullscreen: "toggleFullscreen",
|
|
356
|
+
preview: "togglePreview",
|
|
357
|
+
print: "print",
|
|
358
|
+
a11yChecker: "toggleA11yChecker",
|
|
359
|
+
spellCheck: "toggleSpellCheck",
|
|
360
|
+
comments: "addComment",
|
|
361
|
+
showHideComments: "toggleComments",
|
|
362
|
+
toggleComments: "toggleComments",
|
|
363
|
+
footnote: "insertFootnote",
|
|
364
|
+
mergeTags: "insertMergeTag",
|
|
365
|
+
pageBreak: "insertPageBreak",
|
|
366
|
+
template: "insertTemplate",
|
|
367
|
+
importWord: "importWord",
|
|
368
|
+
exportWord: "exportWord",
|
|
369
|
+
exportPdf: "exportPdf",
|
|
370
|
+
insertImage: "insertImage",
|
|
371
|
+
insertVideo: "insertVideo",
|
|
372
|
+
codeBlock: "insertCodeBlock"
|
|
373
|
+
};
|
|
374
|
+
return o.forEach((r) => {
|
|
375
|
+
const l = [];
|
|
376
|
+
r.split(/\s+/).filter(Boolean).forEach((u) => {
|
|
377
|
+
if (u === "direction") {
|
|
378
|
+
const c = n.get("setDirectionLTR"), h = n.get("setDirectionRTL");
|
|
379
|
+
c && l.push({
|
|
380
|
+
id: "directionLTR",
|
|
381
|
+
label: c.label,
|
|
382
|
+
command: c.command,
|
|
383
|
+
icon: c.icon,
|
|
384
|
+
type: c.type || "button",
|
|
385
|
+
options: c.options
|
|
386
|
+
}), h && l.push({
|
|
387
|
+
id: "directionRTL",
|
|
388
|
+
label: h.label,
|
|
389
|
+
command: h.command,
|
|
390
|
+
icon: h.icon,
|
|
391
|
+
type: h.type || "button",
|
|
392
|
+
options: h.options
|
|
393
|
+
});
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
if (u === "comments") {
|
|
397
|
+
const c = n.get("addComment"), h = n.get("toggleComments");
|
|
398
|
+
c && l.push({
|
|
399
|
+
id: "addComment",
|
|
400
|
+
label: c.label,
|
|
401
|
+
command: c.command,
|
|
402
|
+
icon: c.icon,
|
|
403
|
+
type: c.type || "button",
|
|
404
|
+
options: c.options
|
|
405
|
+
}), h && l.push({
|
|
406
|
+
id: "toggleComments",
|
|
407
|
+
label: h.label,
|
|
408
|
+
command: h.command,
|
|
409
|
+
icon: h.icon,
|
|
410
|
+
type: h.type || "button",
|
|
411
|
+
options: h.options
|
|
412
|
+
});
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
const p = a[u] || u;
|
|
416
|
+
let d = n.get(p);
|
|
417
|
+
d || (d = n.get(u)), d && l.push({
|
|
418
|
+
id: u,
|
|
419
|
+
label: d.label,
|
|
420
|
+
command: d.command,
|
|
421
|
+
icon: d.icon,
|
|
422
|
+
type: d.type === "separator" ? "separator" : d.type || "button",
|
|
423
|
+
options: d.options,
|
|
424
|
+
items: d.items
|
|
425
|
+
});
|
|
426
|
+
}), l.length > 0 && e.push(l);
|
|
427
|
+
}), e;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Get all available toolbar items from plugins
|
|
431
|
+
*/
|
|
432
|
+
getAvailableToolbarItems() {
|
|
433
|
+
return this.plugins.flatMap((e) => e.toolbar || []);
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Render toolbar to DOM element
|
|
437
|
+
*/
|
|
438
|
+
render(t) {
|
|
439
|
+
this.container = t, t.innerHTML = "", t.className = "editora-toolbar", this.config.sticky && t.classList.add("editora-toolbar-sticky"), this.config.position && t.classList.add(`editora-toolbar-${this.config.position}`);
|
|
440
|
+
const e = this.config.items || this.getDefaultToolbarString(), o = this.parseToolbarString(e);
|
|
441
|
+
o.forEach((i, n) => {
|
|
442
|
+
const a = document.createElement("div");
|
|
443
|
+
if (a.className = "editora-toolbar-group", i.forEach((r) => {
|
|
444
|
+
this.appendToolbarButton(a, r);
|
|
445
|
+
}), t.appendChild(a), n < o.length - 1) {
|
|
446
|
+
const r = document.createElement("div");
|
|
447
|
+
r.className = "editora-toolbar-separator", t.appendChild(r);
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Append a toolbar button or group to a parent element
|
|
453
|
+
*/
|
|
454
|
+
appendToolbarButton(t, e) {
|
|
455
|
+
if (e.type === "separator") {
|
|
456
|
+
const o = document.createElement("div");
|
|
457
|
+
o.className = "editora-toolbar-separator", t.appendChild(o);
|
|
458
|
+
} else if (e.type === "dropdown") {
|
|
459
|
+
const o = this.createDropdown(e);
|
|
460
|
+
t.appendChild(o);
|
|
461
|
+
} else if (e.type === "inline-menu") {
|
|
462
|
+
const o = this.createInlineMenu(e);
|
|
463
|
+
t.appendChild(o);
|
|
464
|
+
} else if (e.type === "group" && e.items && e.items.length) {
|
|
465
|
+
const o = this.createGroupButton(e);
|
|
466
|
+
t.appendChild(o);
|
|
467
|
+
} else if (e.type === "input") {
|
|
468
|
+
const o = this.createInput(e);
|
|
469
|
+
t.appendChild(o);
|
|
470
|
+
} else {
|
|
471
|
+
const o = this.createButton(e);
|
|
472
|
+
t.appendChild(o);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Create a toolbar button element
|
|
477
|
+
*/
|
|
478
|
+
createGroupButton(t) {
|
|
479
|
+
const e = document.createElement("div");
|
|
480
|
+
if (e.className = "editora-toolbar-group-button", e.title = t.label, t.icon)
|
|
481
|
+
if (t.icon.startsWith("<svg") && t.icon.endsWith("</svg>")) {
|
|
482
|
+
const o = document.createElement("span");
|
|
483
|
+
o.className = "editora-toolbar-icon", o.innerHTML = t.icon, e.appendChild(o);
|
|
484
|
+
} else
|
|
485
|
+
e.innerHTML = t.icon;
|
|
486
|
+
if (t.items && t.items.length) {
|
|
487
|
+
const o = document.createElement("div");
|
|
488
|
+
o.className = "editora-toolbar-group-items", t.items.forEach((i) => {
|
|
489
|
+
this.appendToolbarButton(o, i);
|
|
490
|
+
}), e.appendChild(o);
|
|
491
|
+
}
|
|
492
|
+
return e;
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Create a toolbar button element
|
|
496
|
+
*/
|
|
497
|
+
createInput(t) {
|
|
498
|
+
const e = document.createElement("input");
|
|
499
|
+
return e.className = `editora-toolbar-input ${t.label.toLowerCase().replace(/\s+/g, "-")}`, e.type = "text", e.title = t.label, e.placeholder = t.placeholder || "", e.setAttribute("data-command", t.command), t.active && e.classList.add("active"), t.disabled && (e.disabled = !0), e.addEventListener("click", (o) => {
|
|
500
|
+
o.preventDefault(), this.commandHandler && this.commandHandler(t.command);
|
|
501
|
+
}), e;
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Create a toolbar button element
|
|
505
|
+
*/
|
|
506
|
+
createButton(t) {
|
|
507
|
+
const e = document.createElement("button");
|
|
508
|
+
if (e.className = "editora-toolbar-button", e.type = "button", e.title = t.label, e.setAttribute("data-command", t.command), t.icon)
|
|
509
|
+
if (t.icon.startsWith("<svg") && t.icon.endsWith("</svg>")) {
|
|
510
|
+
const o = document.createElement("span");
|
|
511
|
+
o.className = "editora-toolbar-icon", o.innerHTML = t.icon, e.appendChild(o);
|
|
512
|
+
} else
|
|
513
|
+
e.innerHTML = t.icon;
|
|
514
|
+
else
|
|
515
|
+
e.textContent = t.label;
|
|
516
|
+
return t.active && e.classList.add("active"), t.disabled && (e.disabled = !0), e.addEventListener("click", (o) => {
|
|
517
|
+
o.preventDefault(), this.commandHandler && this.commandHandler(t.command);
|
|
518
|
+
}), e;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Create a dropdown element
|
|
522
|
+
*/
|
|
523
|
+
createDropdown(t) {
|
|
524
|
+
const e = document.createElement("div");
|
|
525
|
+
e.className = "editora-toolbar-dropdown";
|
|
526
|
+
const o = document.createElement("button");
|
|
527
|
+
o.className = "editora-toolbar-button editora-toolbar-dropdown-trigger", o.type = "button", o.textContent = t.label;
|
|
528
|
+
const i = document.createElement("div");
|
|
529
|
+
i.className = "editora-toolbar-dropdown-menu", i.style.display = "none", t.options && t.options.forEach((a) => {
|
|
530
|
+
const r = document.createElement("button");
|
|
531
|
+
r.className = "editora-toolbar-dropdown-item", r.type = "button", r.textContent = a.label, r.setAttribute("data-value", a.value), r.addEventListener("click", (l) => {
|
|
532
|
+
l.preventDefault(), this.commandHandler && this.commandHandler(t.command, a.value), i.style.display = "none";
|
|
533
|
+
}), i.appendChild(r);
|
|
534
|
+
}), o.addEventListener("click", (a) => {
|
|
535
|
+
a.preventDefault(), a.stopPropagation();
|
|
536
|
+
const r = i.style.display === "block";
|
|
537
|
+
i.style.display = r ? "none" : "block";
|
|
538
|
+
});
|
|
539
|
+
const n = (a) => {
|
|
540
|
+
e.contains(a.target) || (i.style.display = "none");
|
|
541
|
+
};
|
|
542
|
+
return document.addEventListener("click", n), e._cleanupDropdown = () => {
|
|
543
|
+
document.removeEventListener("click", n);
|
|
544
|
+
}, e.appendChild(o), e.appendChild(i), e;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Create an inline menu element (like dropdown but triggered by button click)
|
|
548
|
+
*/
|
|
549
|
+
createInlineMenu(t) {
|
|
550
|
+
const e = document.createElement("div");
|
|
551
|
+
e.className = "editora-toolbar-dropdown editora-toolbar-inline-menu";
|
|
552
|
+
const o = document.createElement("button");
|
|
553
|
+
if (o.className = "editora-toolbar-button", o.type = "button", o.title = t.label, t.icon)
|
|
554
|
+
if (t.icon.startsWith("<svg") && t.icon.endsWith("</svg>")) {
|
|
555
|
+
const n = document.createElement("span");
|
|
556
|
+
n.className = "editora-toolbar-icon", n.innerHTML = t.icon, o.appendChild(n);
|
|
557
|
+
} else
|
|
558
|
+
o.innerHTML = t.icon;
|
|
559
|
+
else
|
|
560
|
+
o.textContent = t.label;
|
|
561
|
+
const i = document.createElement("div");
|
|
562
|
+
return i.className = "editora-toolbar-dropdown-menu", i.style.display = "none", t.options && t.options.forEach((n) => {
|
|
563
|
+
const a = document.createElement("button");
|
|
564
|
+
a.className = "editora-toolbar-dropdown-item", a.type = "button", a.textContent = n.label, a.setAttribute("data-value", n.value), a.addEventListener("click", (r) => {
|
|
565
|
+
r.preventDefault(), r.stopPropagation(), this.commandHandler && this.commandHandler(t.command, n.value), i.style.display = "none";
|
|
566
|
+
}), i.appendChild(a);
|
|
567
|
+
}), o.addEventListener("click", (n) => {
|
|
568
|
+
var r;
|
|
569
|
+
n.preventDefault(), n.stopPropagation();
|
|
570
|
+
const a = (r = this.container) == null ? void 0 : r.querySelectorAll(
|
|
571
|
+
".editora-toolbar-dropdown-menu"
|
|
572
|
+
);
|
|
573
|
+
a == null || a.forEach((l) => {
|
|
574
|
+
l !== i && (l.style.display = "none");
|
|
575
|
+
}), i.style.display = i.style.display === "none" ? "block" : "none";
|
|
576
|
+
}), document.addEventListener("click", (n) => {
|
|
577
|
+
e.contains(n.target) || (i.style.display = "none");
|
|
578
|
+
}), e.appendChild(o), e.appendChild(i), e;
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Get default toolbar string if none provided
|
|
582
|
+
*/
|
|
583
|
+
getDefaultToolbarString() {
|
|
584
|
+
return this.getAvailableToolbarItems().map((e) => e.command).join(" ");
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Update button state
|
|
588
|
+
*/
|
|
589
|
+
updateButtonState(t, e) {
|
|
590
|
+
if (!this.container) return;
|
|
591
|
+
const o = this.container.querySelector(
|
|
592
|
+
`[data-command="${t}"]`
|
|
593
|
+
);
|
|
594
|
+
o && (e.active !== void 0 && o.classList.toggle("active", e.active), e.disabled !== void 0 && (o.disabled = e.disabled));
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Destroy toolbar
|
|
598
|
+
*/
|
|
599
|
+
destroy() {
|
|
600
|
+
this.container && (this.container.querySelectorAll(".editora-toolbar-dropdown").forEach((e) => {
|
|
601
|
+
const o = e._cleanupDropdown;
|
|
602
|
+
o && o();
|
|
603
|
+
}), this.container.innerHTML = ""), this.commandHandler = void 0;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
class T {
|
|
607
|
+
constructor(t) {
|
|
608
|
+
this.visible = !1, this.config = t;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Create and mount floating toolbar
|
|
612
|
+
*/
|
|
613
|
+
create(t) {
|
|
614
|
+
const e = document.createElement("div");
|
|
615
|
+
return e.className = "editora-floating-toolbar", e.style.display = "none", e.style.position = "absolute", e.style.zIndex = "1000", this.container = e, t.appendChild(e), e;
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Show toolbar at position
|
|
619
|
+
*/
|
|
620
|
+
show(t, e) {
|
|
621
|
+
this.container && (this.container.style.display = "block", this.container.style.left = `${t}px`, this.container.style.top = `${e}px`, this.visible = !0);
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Hide toolbar
|
|
625
|
+
*/
|
|
626
|
+
hide() {
|
|
627
|
+
this.container && (this.container.style.display = "none", this.visible = !1);
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Update position
|
|
631
|
+
*/
|
|
632
|
+
updatePosition(t, e) {
|
|
633
|
+
!this.container || !this.visible || (this.container.style.left = `${t}px`, this.container.style.top = `${e}px`);
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Check if visible
|
|
637
|
+
*/
|
|
638
|
+
isVisible() {
|
|
639
|
+
return this.visible;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Destroy floating toolbar
|
|
643
|
+
*/
|
|
644
|
+
destroy() {
|
|
645
|
+
this.container && this.container.parentNode && this.container.parentNode.removeChild(this.container), this.container = void 0, this.visible = !1;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
class P {
|
|
649
|
+
constructor(t = {}) {
|
|
650
|
+
this.statusInfo = {}, this.config = t;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Create and mount status bar
|
|
654
|
+
*/
|
|
655
|
+
create(t) {
|
|
656
|
+
const e = document.createElement("div");
|
|
657
|
+
return e.className = "editora-statusbar", this.config.position && e.classList.add(`editora-statusbar-${this.config.position}`), this.container = e, t.appendChild(e), e;
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Update status information
|
|
661
|
+
*/
|
|
662
|
+
update(t) {
|
|
663
|
+
this.statusInfo = { ...this.statusInfo, ...t }, this.render();
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Render status bar content
|
|
667
|
+
*/
|
|
668
|
+
render() {
|
|
669
|
+
if (!this.container) return;
|
|
670
|
+
this.container.innerHTML = "";
|
|
671
|
+
const t = document.createElement("div");
|
|
672
|
+
t.className = "editora-statusbar-left";
|
|
673
|
+
const e = document.createElement("div");
|
|
674
|
+
e.className = "editora-statusbar-right";
|
|
675
|
+
const o = [];
|
|
676
|
+
if (this.statusInfo.selectionInfo) {
|
|
677
|
+
const n = this.statusInfo.selectionInfo;
|
|
678
|
+
n.startLine === n.endLine && n.startColumn === n.endColumn ? o.push(`Ln ${n.startLine}, Col ${n.startColumn}`) : (n.startLine === n.endLine ? o.push(`Ln ${n.startLine}, Col ${n.startColumn}-${n.endColumn}`) : o.push(`Ln ${n.startLine}:${n.startColumn} - ${n.endLine}:${n.endColumn}`), o.push(`${n.selectedChars} chars selected`));
|
|
679
|
+
} else if (this.statusInfo.cursorPosition) {
|
|
680
|
+
const n = this.statusInfo.cursorPosition;
|
|
681
|
+
o.push(`Ln ${n.line}, Col ${n.column}`);
|
|
682
|
+
}
|
|
683
|
+
this.statusInfo.language && o.push(this.statusInfo.language);
|
|
684
|
+
const i = [];
|
|
685
|
+
this.statusInfo.wordCount !== void 0 && i.push(`${this.statusInfo.wordCount} words`), this.statusInfo.charCount !== void 0 && i.push(`${this.statusInfo.charCount} chars`), this.statusInfo.lineCount !== void 0 && i.push(`${this.statusInfo.lineCount} lines`), this.statusInfo.custom && Object.entries(this.statusInfo.custom).forEach(([n, a]) => {
|
|
686
|
+
i.push(`${n}: ${a}`);
|
|
687
|
+
}), o.forEach((n, a) => {
|
|
688
|
+
const r = document.createElement("span");
|
|
689
|
+
if (r.className = "editora-statusbar-item", r.textContent = n, t.appendChild(r), a < o.length - 1) {
|
|
690
|
+
const l = document.createElement("span");
|
|
691
|
+
l.className = "editora-statusbar-separator", l.textContent = "|", t.appendChild(l);
|
|
692
|
+
}
|
|
693
|
+
}), i.forEach((n, a) => {
|
|
694
|
+
const r = document.createElement("span");
|
|
695
|
+
if (r.className = "editora-statusbar-item", r.textContent = n, e.appendChild(r), a < i.length - 1) {
|
|
696
|
+
const l = document.createElement("span");
|
|
697
|
+
l.className = "editora-statusbar-separator", l.textContent = "|", e.appendChild(l);
|
|
698
|
+
}
|
|
699
|
+
}), this.container.appendChild(t), this.container.appendChild(e);
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Destroy status bar
|
|
703
|
+
*/
|
|
704
|
+
destroy() {
|
|
705
|
+
this.container && this.container.parentNode && this.container.parentNode.removeChild(this.container), this.container = void 0;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
function I(s, t) {
|
|
709
|
+
const e = s.textContent || "", o = A(s, t.startContainer, t.startOffset), n = e.substring(0, o).split(`
|
|
710
|
+
`), a = n.length, r = n[n.length - 1].length + 1;
|
|
711
|
+
return { line: a, column: r };
|
|
712
|
+
}
|
|
713
|
+
function A(s, t, e) {
|
|
714
|
+
var a;
|
|
715
|
+
let o = 0;
|
|
716
|
+
const i = document.createTreeWalker(
|
|
717
|
+
s,
|
|
718
|
+
NodeFilter.SHOW_TEXT,
|
|
719
|
+
null
|
|
720
|
+
);
|
|
721
|
+
let n = i.firstChild();
|
|
722
|
+
for (; n; ) {
|
|
723
|
+
if (n === t) {
|
|
724
|
+
o += e;
|
|
725
|
+
break;
|
|
726
|
+
} else n.nodeType === Node.TEXT_NODE && (o += ((a = n.textContent) == null ? void 0 : a.length) || 0);
|
|
727
|
+
n = i.nextNode();
|
|
728
|
+
}
|
|
729
|
+
return o;
|
|
730
|
+
}
|
|
731
|
+
function S(s) {
|
|
732
|
+
var o, i;
|
|
733
|
+
const t = s.querySelectorAll("div, p, br, h1, h2, h3, h4, h5, h6, blockquote, li, pre");
|
|
734
|
+
let e = 1;
|
|
735
|
+
if (t.length > 0) {
|
|
736
|
+
e = t.length;
|
|
737
|
+
const n = t[t.length - 1];
|
|
738
|
+
(n.tagName === "BR" || ((o = n.innerHTML) == null ? void 0 : o.trim()) === "" || ((i = n.textContent) == null ? void 0 : i.trim()) === "") && e++;
|
|
739
|
+
} else {
|
|
740
|
+
const a = (s.textContent || "").split(`
|
|
741
|
+
`).length;
|
|
742
|
+
e = Math.max(1, a);
|
|
743
|
+
}
|
|
744
|
+
return e;
|
|
745
|
+
}
|
|
746
|
+
function N(s) {
|
|
747
|
+
const t = s.trim() ? s.trim().split(/\s+/).length : 0, e = s.length;
|
|
748
|
+
return { words: t, chars: e };
|
|
749
|
+
}
|
|
750
|
+
function M(s, t) {
|
|
751
|
+
const e = s.toString();
|
|
752
|
+
return {
|
|
753
|
+
startLine: t.line,
|
|
754
|
+
startColumn: t.column,
|
|
755
|
+
endLine: t.line,
|
|
756
|
+
// For now, assuming single line selections
|
|
757
|
+
endColumn: t.column + e.length,
|
|
758
|
+
selectedChars: e.length,
|
|
759
|
+
selectedWords: e.trim().split(/\s+/).filter(Boolean).length
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
const y = class y {
|
|
763
|
+
/**
|
|
764
|
+
* Resolve configuration from multiple sources with priority
|
|
765
|
+
*/
|
|
766
|
+
static resolve(t) {
|
|
767
|
+
const e = {};
|
|
768
|
+
if (Object.assign(e, this.EDITOR_DEFAULTS), t.pluginDefaults && Object.assign(e, t.pluginDefaults), t.attributes) {
|
|
769
|
+
const o = this.parseAttributes(t.attributes);
|
|
770
|
+
Object.assign(e, o);
|
|
771
|
+
}
|
|
772
|
+
return t.jsConfig && Object.assign(e, t.jsConfig), e;
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Parse web component attributes
|
|
776
|
+
*/
|
|
777
|
+
static parseAttributes(t) {
|
|
778
|
+
const e = {};
|
|
779
|
+
for (const [o, i] of Object.entries(t)) {
|
|
780
|
+
const n = this.kebabToCamel(o);
|
|
781
|
+
e[n] = this.parseAttributeValue(i);
|
|
782
|
+
}
|
|
783
|
+
return e;
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Parse attribute value to appropriate type
|
|
787
|
+
*/
|
|
788
|
+
static parseAttributeValue(t) {
|
|
789
|
+
if (t === "true") return !0;
|
|
790
|
+
if (t === "false") return !1;
|
|
791
|
+
if (/^\d+$/.test(t)) return parseInt(t, 10);
|
|
792
|
+
if (/^\d+\.\d+$/.test(t)) return parseFloat(t);
|
|
793
|
+
if (t.startsWith("{") || t.startsWith("["))
|
|
794
|
+
try {
|
|
795
|
+
return JSON.parse(t);
|
|
796
|
+
} catch (e) {
|
|
797
|
+
return t;
|
|
798
|
+
}
|
|
799
|
+
return t;
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Convert kebab-case to camelCase
|
|
803
|
+
*/
|
|
804
|
+
static kebabToCamel(t) {
|
|
805
|
+
return t.replace(/-([a-z])/g, (e, o) => o.toUpperCase());
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Validate configuration
|
|
809
|
+
*/
|
|
810
|
+
static validate(t) {
|
|
811
|
+
const e = [];
|
|
812
|
+
return t.height !== void 0 && typeof t.height == "number" && t.height < 0 && e.push("height must be a positive number"), t.width !== void 0 && typeof t.width == "number" && t.width < 0 && e.push("width must be a positive number"), t.plugins !== void 0 && !Array.isArray(t.plugins) && typeof t.plugins != "string" && e.push("plugins must be an array or string"), t.theme !== void 0 && typeof t.theme != "string" && e.push("theme must be a string"), {
|
|
813
|
+
valid: e.length === 0,
|
|
814
|
+
errors: e
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Get default configuration
|
|
819
|
+
*/
|
|
820
|
+
static getDefaults() {
|
|
821
|
+
return { ...this.EDITOR_DEFAULTS };
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Merge configurations (deep merge)
|
|
825
|
+
*/
|
|
826
|
+
static merge(...t) {
|
|
827
|
+
const e = {};
|
|
828
|
+
for (const o of t)
|
|
829
|
+
for (const [i, n] of Object.entries(o))
|
|
830
|
+
n != null && (typeof n == "object" && !Array.isArray(n) && e[i] ? e[i] = this.merge(e[i], n) : e[i] = n);
|
|
831
|
+
return e;
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
y.EDITOR_DEFAULTS = {
|
|
835
|
+
height: 400,
|
|
836
|
+
width: "100%",
|
|
837
|
+
readonly: !1,
|
|
838
|
+
disabled: !1,
|
|
839
|
+
menubar: !0,
|
|
840
|
+
toolbar: !0,
|
|
841
|
+
plugins: [],
|
|
842
|
+
theme: "light",
|
|
843
|
+
content: "",
|
|
844
|
+
placeholder: "Start typing...",
|
|
845
|
+
autofocus: !1,
|
|
846
|
+
autosave: !1,
|
|
847
|
+
spellcheck: !1,
|
|
848
|
+
language: "en"
|
|
849
|
+
};
|
|
850
|
+
let b = y;
|
|
851
|
+
const H = '.editora-editor{display:flex;flex-direction:column;border:1px solid #ddd;border-radius:4px;background:#fff;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;font-size:14px;overflow:hidden}.editora-editor *{box-sizing:border-box}.editora-theme-light{background:#fff;color:#333}.editora-theme-dark{background:#1e1e1e;color:#d4d4d4;border-color:#3c3c3c}.editora-toolbar{display:flex;align-items:center;gap:4px;padding:8px;background:#f5f5f5;border-bottom:1px solid #ddd;flex-wrap:wrap}.editora-theme-dark .editora-toolbar{background:#252526;border-bottom-color:#3c3c3c}.editora-toolbar-sticky{position:sticky;top:0;z-index:100;position:-webkit-sticky}.editora-toolbar-group{display:flex;align-items:center;gap:2px}.editora-toolbar-button{padding:6px 12px;border:1px solid #ccc;background:#fff;cursor:pointer;border-radius:3px;font-weight:600;font-size:14px;height:30px;display:flex;align-items:center;white-space:nowrap}.editora-toolbar-input.font-size{width:40px;padding:.25rem;text-align:center;font-size:14px;background:#fff;border:1px solid var(--rte-color-border-light);border-radius:var(--rte-radius-sm)}.editora-toolbar-group-items{display:flex;align-items:center;border:1px solid #ccc;.editora-toolbar-button{border:none;border-radius:0;&:first-child{border-right:1px solid #ccc;border-top-left-radius:3px;border-bottom-left-radius:3px}&:last-child{border-left:1px solid #ccc;border-top-right-radius:3px;border-bottom-right-radius:3px}}}.editora-theme-dark .editora-toolbar-button{color:#d4d4d4}.editora-toolbar-button:hover{background:#e0e0e0;border-color:#ccc}.editora-theme-dark .editora-toolbar-button:hover{background:#37373d;border-color:#555}.editora-toolbar-button:active,.editora-toolbar-button.active{background:#d0d0d0;border-color:#999}.editora-theme-dark .editora-toolbar-button:active,.editora-theme-dark .editora-toolbar-button.active{background:#2a2d2e;border-color:#666}.editora-toolbar-button:disabled{opacity:.5;cursor:not-allowed}.editora-toolbar-icon{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;line-height:1}.editora-toolbar-button svg,.editora-toolbar-icon svg{width:24px;height:24px;display:block}.editora-toolbar-separator{width:1px;height:24px;background:#ddd;margin:0 4px}.editora-theme-dark .editora-toolbar-separator{background:#3c3c3c}.editora-toolbar-dropdown{position:relative}.editora-toolbar-dropdown-menu{position:absolute;top:100%;left:0;min-width:150px;margin-top:4px;padding:4px 0;background:#fff;border:1px solid #ddd;border-radius:4px;box-shadow:0 2px 8px #00000026;z-index:1000}.editora-theme-dark .editora-toolbar-dropdown-menu{background:#252526;border-color:#3c3c3c;box-shadow:0 2px 8px #00000080}.editora-toolbar-dropdown-item{display:block;width:100%;padding:8px 12px;border:none;background:transparent;color:#333;text-align:left;cursor:pointer;font-size:13px;transition:background .15s ease}.editora-theme-dark .editora-toolbar-dropdown-item{color:#d4d4d4}.editora-toolbar-dropdown-item:hover{background:#f5f5f5}.editora-theme-dark .editora-toolbar-dropdown-item:hover{background:#37373d}.editora-content{flex:1;min-height:200px;padding:16px;outline:none;overflow-y:auto;line-height:1.6}.editora-content:empty:before{content:attr(data-placeholder);color:#999;pointer-events:none}.editora-theme-dark .editora-content:empty:before{color:#6a6a6a}.editora-content h1{font-size:2em;margin:.67em 0;font-weight:600}.editora-content h2{font-size:1.5em;margin:.75em 0;font-weight:600}.editora-content h3{font-size:1.17em;margin:.83em 0;font-weight:600}.editora-content p{margin:1em 0}.editora-content ul,.editora-content ol{margin:1em 0;padding-left:2em}.editora-content a{color:#06c;text-decoration:underline}.editora-theme-dark .editora-content a{color:#4db8ff}.editora-content code{padding:2px 4px;background:#f5f5f5;border-radius:3px;font-family:Monaco,Menlo,Consolas,monospace;font-size:.9em}.editora-theme-dark .editora-content code{background:#1e1e1e}.editora-content pre{padding:12px;background:#f5f5f5;border-radius:4px;overflow-x:auto;margin:1em 0}.editora-theme-dark .editora-content pre{background:#1e1e1e}.editora-content blockquote{margin:1em 0;padding-left:1em;border-left:4px solid #ddd;color:#666}.editora-theme-dark .editora-content blockquote{border-left-color:#3c3c3c;color:#9a9a9a}.editora-floating-toolbar{position:absolute;padding:4px;background:#fff;border:1px solid #ddd;border-radius:4px;box-shadow:0 2px 8px #00000026;z-index:1000}.editora-theme-dark .editora-floating-toolbar{background:#252526;border-color:#3c3c3c;box-shadow:0 2px 8px #00000080}.editora-statusbar-container{display:flex;flex-direction:column}.editora-statusbar-left{display:flex;align-items:center;gap:8px}.editora-statusbar-right{display:flex;align-items:center;gap:8px;margin-left:auto}.editora-statusbar{display:flex;align-items:center;gap:12px;padding:6px 12px;background:#f5f5f5;border-top:1px solid #ddd;font-size:12px;color:#666}.editora-theme-dark .editora-statusbar{background:#252526;border-top-color:#3c3c3c;color:#9a9a9a}.editora-statusbar-item{white-space:nowrap}.editora-statusbar-separator{color:#ddd}.editora-theme-dark .editora-statusbar-separator{color:#3c3c3c}.editora-editor[readonly] .editora-content{background:#fafafa;cursor:not-allowed}.editora-theme-dark.editora-editor[readonly] .editora-content{background:#1a1a1a}.editora-editor:focus-within{border-color:#06c;box-shadow:0 0 0 3px #0066cc1a}.editora-theme-dark.editora-editor:focus-within{border-color:#4db8ff;box-shadow:0 0 0 3px #4db8ff1a}.editora-editor[disabled]{opacity:.6;pointer-events:none}@media(max-width:768px){.editora-toolbar{padding:4px}.editora-toolbar-button{min-width:28px;min-height:28px;padding:4px 8px;font-size:12px}.editora-content{padding:12px}}.editora-content ::selection{background:#06c3}.editora-theme-dark .editora-content ::selection{background:#4db8ff33}.editora-content table{border-collapse:collapse;width:100%;margin:1em 0}.editora-content th,.editora-content td{border:1px solid #ddd;padding:8px 12px;text-align:left}.editora-theme-dark .editora-content th,.editora-theme-dark .editora-content td{border-color:#3c3c3c}.editora-content th{background:#f5f5f5;font-weight:600}.editora-theme-dark .editora-content th{background:#252526}.editora-content img{max-width:100%;height:auto;border-radius:4px;display:block}.editora-content video{max-width:100%;height:auto;border-radius:4px;display:block}.editora-editor.loading{opacity:.7;pointer-events:none}.editora-editor.loading:after{content:"";position:absolute;top:50%;left:50%;width:24px;height:24px;margin:-12px 0 0 -12px;border:3px solid #ddd;border-top-color:#06c;border-radius:50%;animation:editora-spin .8s linear infinite}@keyframes editora-spin{to{transform:rotate(360deg)}}.toolbar-container-wrapper{display:flex;align-items:center;background:#fff;border-bottom:1px solid #e0e0e0;padding:0;margin:0;width:100%;box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:14px;line-height:1.5;position:relative}.toolbar-container-wrapper[data-toolbar-sticky=true]{position:sticky;top:0;z-index:999;box-shadow:0 2px 4px #0000001a}.toolbar-container-wrapper[data-toolbar-floating=true]{position:fixed;top:0;left:0;right:0;z-index:1000;box-shadow:0 4px 12px #00000026}.toolbar-container-wrapper[data-toolbar-position=bottom]{border-bottom:none;border-top:1px solid #e0e0e0}.toolbar-container-wrapper .toolbar-wrapper{display:flex;width:100%;padding:8px;gap:4px;flex-wrap:wrap;align-items:center}.toolbar-container-wrapper .toolbar{display:flex;width:100%;gap:4px;flex-wrap:wrap;align-items:center}.toolbar-container-wrapper .toolbar-container{display:flex;gap:4px;flex-wrap:wrap;align-items:center;flex:1;position:relative}.toolbar-container-wrapper .toolbar-item{display:flex;align-items:center;gap:2px}.toolbar-container-wrapper .toolbar-button{padding:6px 10px;border:1px solid #d1d5db;background:#fff;border-radius:4px;cursor:pointer;font-size:13px;display:flex;align-items:center;justify-content:center;gap:4px;transition:all .15s ease;min-height:32px;white-space:nowrap}.toolbar-container-wrapper .toolbar-button:hover{background-color:#f3f4f6;border-color:#9ca3af}.toolbar-container-wrapper .toolbar-button:active,.toolbar-container-wrapper .toolbar-button[data-active=true]{background-color:#06c;color:#fff;border-color:#0052a3;box-shadow:inset 0 1px 3px #0000001a}.toolbar-container-wrapper .toolbar-button:disabled{opacity:.5;cursor:not-allowed;background-color:#f9fafb}.toolbar-container-wrapper .toolbar-more-button{padding:6px 8px;font-size:16px;font-weight:500;line-height:1}.toolbar-container-wrapper .toolbar-separator{width:1px;height:24px;background-color:#d1d5db;margin:0 4px}.toolbar-container-wrapper .toolbar-icon{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;flex-shrink:0}.toolbar-container-wrapper .toolbar-icon svg{width:100%;height:100%}.toolbar-container-wrapper .toolbar-dropdown{position:relative;display:flex;align-items:center}.toolbar-container-wrapper .toolbar-dropdown-arrow{font-size:10px;margin-left:2px;line-height:1}.toolbar-container-wrapper .toolbar-dropdown-menu{position:absolute;top:100%;left:0;background:#fff;border:1px solid #d1d5db;border-radius:6px;box-shadow:0 4px 12px #00000026;z-index:1000;min-width:160px;padding:4px 0;margin-top:4px;display:none}.toolbar-container-wrapper .toolbar-dropdown-menu.show{display:block}.toolbar-container-wrapper .toolbar-dropdown-item{display:block;width:100%;padding:8px 12px;border:none;background:transparent;text-align:left;cursor:pointer;font-size:13px;color:#1f2937;transition:background-color .15s ease;font-family:inherit}.toolbar-container-wrapper .toolbar-dropdown-item:hover{background-color:#f3f4f6}.toolbar-container-wrapper .toolbar-dropdown-item:active{background-color:#e5e7eb}.toolbar-container-wrapper .toolbar-input{padding:6px 8px;border:1px solid #d1d5db;border-radius:4px;font-size:13px;font-family:inherit;background-color:#fff;color:#1f2937;transition:all .15s ease}.toolbar-container-wrapper .toolbar-input:focus{outline:none;border-color:#06c;box-shadow:0 0 0 3px #0066cc1a;background-color:#fff}.toolbar-container-wrapper .toolbar-input::placeholder{color:#9ca3af}.toolbar-overflow-menu{animation:slideDown .2s ease-out}@keyframes slideDown{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.toolbar-overflow-item{transition:background-color .15s ease}.floating-toolbar{user-select:none;-webkit-user-select:none;font-family:system-ui,-apple-system,sans-serif;font-size:14px;animation:fadeInUp .15s ease-out}@keyframes fadeInUp{0%{opacity:0;transform:translate(-50%) translateY(10px)}to{opacity:1;transform:translate(-50%) translateY(0)}}.floating-toolbar-btn{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border:none;background:transparent;border-radius:4px;color:#495057;cursor:pointer;font-size:14px;font-weight:500;transition:all .15s ease;outline:none}.floating-toolbar-btn:hover{background:#f8f9fa;color:#212529}.floating-toolbar-btn:active{background:#e9ecef;transform:scale(.95)}.floating-toolbar-btn.floating-toolbar-toggle{color:#dc3545;font-weight:700}.floating-toolbar-btn.floating-toolbar-toggle:hover{background:#f8d7da;color:#721c24}.floating-toolbar-separator{width:1px;height:20px;background:#e1e5e9;margin:0 2px}@media(max-width:768px){.toolbar-container-wrapper .toolbar-button{padding:5px 8px;font-size:12px;min-height:28px}.toolbar-container-wrapper .toolbar-icon{width:16px;height:16px}.toolbar-container-wrapper .toolbar-dropdown-menu{min-width:140px}.toolbar-container-wrapper .toolbar-dropdown-item{padding:6px 10px;font-size:12px}.floating-toolbar{padding:4px;gap:2px}.floating-toolbar-btn{width:28px;height:28px;font-size:12px}}@media(max-width:480px){.toolbar-container-wrapper{padding:4px}.toolbar-container-wrapper .toolbar-wrapper{padding:4px;gap:2px}.toolbar-container-wrapper .toolbar-button{padding:4px 6px;font-size:11px;min-height:24px}.toolbar-container-wrapper .toolbar-icon{width:14px;height:14px}}.floating-toolbar{pointer-events:auto}.floating-toolbar{max-width:calc(100vw - 20px);overflow-x:auto}@media(prefers-color-scheme:dark){.floating-toolbar{background:#2d3748;border-color:#4a5568;color:#e2e8f0}.floating-toolbar-btn:hover{background:#4a5568;color:#f7fafc}.floating-toolbar-btn:active{background:#718096}.floating-toolbar-separator{background:#4a5568}}';
|
|
852
|
+
function z() {
|
|
853
|
+
const s = "editora-webcomponent-styles";
|
|
854
|
+
if (!document.getElementById(s)) {
|
|
855
|
+
const t = document.createElement("style");
|
|
856
|
+
t.id = s, t.textContent = H, document.head.appendChild(t);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
class g extends HTMLElement {
|
|
860
|
+
constructor() {
|
|
861
|
+
if (super(), this.config = {}, this.isInitialized = !1, z(), !this.hasAttribute("data-initial-content")) {
|
|
862
|
+
const t = this.innerHTML.trim();
|
|
863
|
+
t && this.setAttribute("data-initial-content", t);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
// Observed attributes for reactive updates
|
|
867
|
+
static get observedAttributes() {
|
|
868
|
+
return [
|
|
869
|
+
"height",
|
|
870
|
+
"width",
|
|
871
|
+
"menubar",
|
|
872
|
+
"plugins",
|
|
873
|
+
"toolbar",
|
|
874
|
+
"toolbar-items",
|
|
875
|
+
"readonly",
|
|
876
|
+
"disabled",
|
|
877
|
+
"theme",
|
|
878
|
+
"placeholder",
|
|
879
|
+
"autofocus",
|
|
880
|
+
"language",
|
|
881
|
+
"spellcheck",
|
|
882
|
+
"statusbar"
|
|
883
|
+
];
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Called when element is added to DOM
|
|
887
|
+
*/
|
|
888
|
+
connectedCallback() {
|
|
889
|
+
this.config = this.resolveConfig(), this.waitForPluginLoader().then(() => {
|
|
890
|
+
setTimeout(async () => {
|
|
891
|
+
await this.initialize();
|
|
892
|
+
}, 0);
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Wait for the global plugin loader to be available
|
|
897
|
+
*/
|
|
898
|
+
async waitForPluginLoader() {
|
|
899
|
+
if (g.__globalPluginLoader) {
|
|
900
|
+
this.pluginLoader = g.__globalPluginLoader;
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
return new Promise((t) => {
|
|
904
|
+
const e = () => {
|
|
905
|
+
g.__globalPluginLoader ? (this.pluginLoader = g.__globalPluginLoader, t()) : setTimeout(e, 0);
|
|
906
|
+
};
|
|
907
|
+
e();
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* Called when element is removed from DOM
|
|
912
|
+
*/
|
|
913
|
+
disconnectedCallback() {
|
|
914
|
+
this.destroy();
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Called when an observed attribute changes
|
|
918
|
+
*/
|
|
919
|
+
attributeChangedCallback(t, e, o) {
|
|
920
|
+
e !== o && (this.config = this.resolveConfig(), this.handleAttributeChange(t, o));
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Set configuration via JavaScript API
|
|
924
|
+
*/
|
|
925
|
+
async setConfig(t) {
|
|
926
|
+
this.jsConfig = t, this.config = this.resolveConfig(), this.isConnected && (this.destroy(), await this.waitForPluginLoader(), await this.initialize());
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Initialize the editor
|
|
930
|
+
*/
|
|
931
|
+
async initialize() {
|
|
932
|
+
if (this.querySelector(".editora-toolbar") || this.isInitialized) return;
|
|
933
|
+
this.setAttribute("data-editora-editor", "true"), this.config.height && (this.style.height = typeof this.config.height == "number" ? `${this.config.height}px` : this.config.height), this.config.width && (this.style.width = typeof this.config.width == "number" ? `${this.config.width}px` : this.config.width), this.classList.add("editora-editor"), this.config.theme && this.classList.add(`editora-theme-${this.config.theme}`);
|
|
934
|
+
const t = await this.loadPlugins();
|
|
935
|
+
t.forEach((o) => {
|
|
936
|
+
if (o.init && typeof o.init == "function")
|
|
937
|
+
try {
|
|
938
|
+
o.init({ editorElement: this });
|
|
939
|
+
} catch (i) {
|
|
940
|
+
console.error(`[RichTextEditor] Error initializing plugin ${o.name}:`, i);
|
|
941
|
+
}
|
|
942
|
+
});
|
|
943
|
+
const e = this.getAttribute("data-initial-content") || "";
|
|
944
|
+
this.engine = new v({
|
|
945
|
+
content: e,
|
|
946
|
+
plugins: t,
|
|
947
|
+
readonly: this.config.readonly
|
|
948
|
+
}), this.createUI(t, e), this.setupEventListeners(), this.isInitialized = !0, this.dispatchEvent(new CustomEvent("editor-ready", {
|
|
949
|
+
detail: { api: this.getAPI() },
|
|
950
|
+
bubbles: !0
|
|
951
|
+
}));
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* Get initial content from slot or attribute
|
|
955
|
+
*/
|
|
956
|
+
getInitialContent() {
|
|
957
|
+
if (this.config.content)
|
|
958
|
+
return this.config.content;
|
|
959
|
+
const t = this.querySelector("[slot]");
|
|
960
|
+
return t ? t.innerHTML : this.hasChildNodes() ? Array.from(this.childNodes).map((o) => o.nodeType === Node.TEXT_NODE ? o.textContent : o.nodeType === Node.ELEMENT_NODE ? o.outerHTML : "").join("").trim() : "";
|
|
961
|
+
}
|
|
962
|
+
/**
|
|
963
|
+
* Load plugins based on configuration
|
|
964
|
+
*/
|
|
965
|
+
async loadPlugins() {
|
|
966
|
+
this.pluginLoader || await this.waitForPluginLoader();
|
|
967
|
+
const t = [];
|
|
968
|
+
if (this.config.plugins && (typeof this.config.plugins == "string" && this.config.plugins.length > 0 || Array.isArray(this.config.plugins) && this.config.plugins.length > 0)) {
|
|
969
|
+
if (typeof this.config.plugins == "string") {
|
|
970
|
+
const o = await this.pluginLoader.parsePluginString(this.config.plugins);
|
|
971
|
+
t.push(...o);
|
|
972
|
+
} else if (Array.isArray(this.config.plugins))
|
|
973
|
+
for (const o of this.config.plugins)
|
|
974
|
+
if (typeof o == "string") {
|
|
975
|
+
const i = await this.pluginLoader.load(o);
|
|
976
|
+
i && t.push(i);
|
|
977
|
+
} else
|
|
978
|
+
t.push(o);
|
|
979
|
+
} else {
|
|
980
|
+
const o = this.pluginLoader.getRegisteredPluginNames(), i = await this.pluginLoader.loadMultiple(o);
|
|
981
|
+
t.push(...i);
|
|
982
|
+
}
|
|
983
|
+
return t;
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
* Create UI elements
|
|
987
|
+
*/
|
|
988
|
+
createUI(t, e) {
|
|
989
|
+
const o = this.querySelector('[slot="toolbar"]'), i = this.querySelector('[slot="statusbar"]');
|
|
990
|
+
if (this.innerHTML = "", this.config.toolbar !== !1 && !o) {
|
|
991
|
+
this.toolbarElement = document.createElement("div"), this.toolbarElement.className = "editora-toolbar-container", this.appendChild(this.toolbarElement);
|
|
992
|
+
const n = this.config.toolbarItems || this.config.toolbar;
|
|
993
|
+
this.toolbar = new L(
|
|
994
|
+
{
|
|
995
|
+
items: typeof n == "string" ? n : void 0,
|
|
996
|
+
sticky: this.config.toolbar && typeof this.config.toolbar == "object" ? this.config.toolbar.sticky : !1,
|
|
997
|
+
position: "top"
|
|
998
|
+
},
|
|
999
|
+
t,
|
|
1000
|
+
this.pluginLoader
|
|
1001
|
+
// Pass plugin loader to get all registered plugins
|
|
1002
|
+
), this.toolbar.setCommandHandler((a, r) => {
|
|
1003
|
+
var m, u;
|
|
1004
|
+
if (this.contentElement) {
|
|
1005
|
+
this.contentElement.focus();
|
|
1006
|
+
const p = window.getSelection();
|
|
1007
|
+
if (!p || p.rangeCount === 0 || !this.contentElement.contains(p.anchorNode)) {
|
|
1008
|
+
const d = document.createRange(), c = this.contentElement.lastChild || this.contentElement;
|
|
1009
|
+
c.nodeType === Node.TEXT_NODE ? d.setStart(c, ((m = c.textContent) == null ? void 0 : m.length) || 0) : c.nodeType === Node.ELEMENT_NODE ? (d.selectNodeContents(c), d.collapse(!1)) : d.setStart(this.contentElement, 0), d.collapse(!0), p == null || p.removeAllRanges(), p == null || p.addRange(d);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
const l = t.find((p) => p.commands && p.commands[a]);
|
|
1013
|
+
if (l && l.commands) {
|
|
1014
|
+
const p = l.commands[a];
|
|
1015
|
+
if (typeof p == "function")
|
|
1016
|
+
try {
|
|
1017
|
+
return p(a === "toggleFullscreen" ? this : r);
|
|
1018
|
+
} catch (d) {
|
|
1019
|
+
return console.error(`[RichTextEditor] Error executing native command ${a}:`, d), !1;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
return ((u = this.engine) == null ? void 0 : u.execCommand(a, r)) || !1;
|
|
1023
|
+
}), this.toolbar.render(this.toolbarElement);
|
|
1024
|
+
} else o && this.appendChild(o);
|
|
1025
|
+
this.contentElement = document.createElement("div"), this.contentElement.className = "editora-content rte-content", this.contentElement.contentEditable = this.config.readonly ? "false" : "true", this.contentElement.setAttribute("role", "textbox"), this.contentElement.setAttribute("aria-multiline", "true"), this.config.placeholder && this.contentElement.setAttribute("data-placeholder", this.config.placeholder);
|
|
1026
|
+
try {
|
|
1027
|
+
document.execCommand("defaultParagraphSeparator", !1, "p");
|
|
1028
|
+
} catch (n) {
|
|
1029
|
+
console.warn("defaultParagraphSeparator not supported:", n);
|
|
1030
|
+
}
|
|
1031
|
+
if (e) {
|
|
1032
|
+
const n = document.createElement("div");
|
|
1033
|
+
n.innerHTML = e.trim(), !Array.from(n.childNodes).some((r) => {
|
|
1034
|
+
if (r.nodeType === Node.ELEMENT_NODE) {
|
|
1035
|
+
const l = r.tagName;
|
|
1036
|
+
return ["P", "DIV", "H1", "H2", "H3", "H4", "H5", "H6", "UL", "OL", "BLOCKQUOTE", "PRE"].includes(l);
|
|
1037
|
+
}
|
|
1038
|
+
return !1;
|
|
1039
|
+
}) && e.trim() ? this.contentElement.innerHTML = `<p>${e.trim()}</p>` : this.contentElement.innerHTML = e;
|
|
1040
|
+
} else
|
|
1041
|
+
this.config.placeholder ? this.contentElement.innerHTML = "" : this.contentElement.innerHTML = "<p><br></p>";
|
|
1042
|
+
this.appendChild(this.contentElement), this.config.toolbar && typeof this.config.toolbar == "object" && this.config.toolbar.floating && (this.floatingToolbar = new T({ enabled: !0 }), this.floatingToolbar.create(this)), i ? this.appendChild(i) : this.config.statusbar && (this.statusBarElement = document.createElement("div"), this.statusBarElement.className = "editora-statusbar-container", this.appendChild(this.statusBarElement), this.statusBar = new P({ position: "bottom" }), this.statusBar.create(this.statusBarElement)), this.config.autofocus && setTimeout(() => {
|
|
1043
|
+
var n;
|
|
1044
|
+
return (n = this.contentElement) == null ? void 0 : n.focus();
|
|
1045
|
+
}, 0);
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Setup event listeners
|
|
1049
|
+
*/
|
|
1050
|
+
setupEventListeners() {
|
|
1051
|
+
if (!this.contentElement || !this.engine) return;
|
|
1052
|
+
this.contentElement.addEventListener("input", () => {
|
|
1053
|
+
const e = this.contentElement.innerHTML;
|
|
1054
|
+
this.dispatchEvent(new CustomEvent("content-change", {
|
|
1055
|
+
detail: { html: e },
|
|
1056
|
+
bubbles: !0
|
|
1057
|
+
})), this.updateStatusBar();
|
|
1058
|
+
}), this.contentElement.addEventListener("focus", () => {
|
|
1059
|
+
this.dispatchEvent(new Event("editor-focus", { bubbles: !0 }));
|
|
1060
|
+
}), this.contentElement.addEventListener("blur", () => {
|
|
1061
|
+
this.dispatchEvent(new Event("editor-blur", { bubbles: !0 }));
|
|
1062
|
+
});
|
|
1063
|
+
const t = () => {
|
|
1064
|
+
this.updateFloatingToolbar(), this.updateStatusBar();
|
|
1065
|
+
};
|
|
1066
|
+
document.addEventListener("selectionchange", t);
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Update floating toolbar position
|
|
1070
|
+
*/
|
|
1071
|
+
updateFloatingToolbar() {
|
|
1072
|
+
if (!this.floatingToolbar) return;
|
|
1073
|
+
const t = window.getSelection();
|
|
1074
|
+
if (!t || t.rangeCount === 0) {
|
|
1075
|
+
this.floatingToolbar.hide();
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
const e = t.getRangeAt(0);
|
|
1079
|
+
if (e.collapsed) {
|
|
1080
|
+
this.floatingToolbar.hide();
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
const o = e.getBoundingClientRect();
|
|
1084
|
+
this.floatingToolbar.show(o.left, o.top - 40);
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Update status bar with selection and cursor information
|
|
1088
|
+
*/
|
|
1089
|
+
/**
|
|
1090
|
+
* Update status bar with current content and cursor information
|
|
1091
|
+
*/
|
|
1092
|
+
updateStatusBar() {
|
|
1093
|
+
if (!this.statusBar || !this.contentElement) return;
|
|
1094
|
+
const t = this.contentElement.textContent || "", { words: e, chars: o } = N(t), i = S(this.contentElement), n = window.getSelection();
|
|
1095
|
+
let a, r;
|
|
1096
|
+
if (n && n.rangeCount > 0) {
|
|
1097
|
+
const l = n.getRangeAt(0);
|
|
1098
|
+
a = I(this.contentElement, l), l.collapsed || (r = M(l, a), a = void 0);
|
|
1099
|
+
}
|
|
1100
|
+
this.statusBar.update({
|
|
1101
|
+
wordCount: e,
|
|
1102
|
+
charCount: o,
|
|
1103
|
+
lineCount: i,
|
|
1104
|
+
cursorPosition: a,
|
|
1105
|
+
selectionInfo: r
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
/**
|
|
1109
|
+
* Handle attribute changes
|
|
1110
|
+
*/
|
|
1111
|
+
handleAttributeChange(t, e) {
|
|
1112
|
+
switch (t) {
|
|
1113
|
+
case "readonly":
|
|
1114
|
+
this.contentElement && (this.contentElement.contentEditable = e === "true" ? "false" : "true"), this.engine && this.engine.setReadonly(e === "true");
|
|
1115
|
+
break;
|
|
1116
|
+
case "theme":
|
|
1117
|
+
this.classList.forEach((o) => {
|
|
1118
|
+
o.startsWith("editora-theme-") && this.classList.remove(o);
|
|
1119
|
+
}), e && this.classList.add(`editora-theme-${e}`);
|
|
1120
|
+
break;
|
|
1121
|
+
case "placeholder":
|
|
1122
|
+
this.contentElement && this.contentElement.setAttribute("data-placeholder", e);
|
|
1123
|
+
break;
|
|
1124
|
+
case "toolbar":
|
|
1125
|
+
case "plugins":
|
|
1126
|
+
this.isConnected && (this.destroy(), this.waitForPluginLoader().then(() => {
|
|
1127
|
+
this.initialize().catch((o) => {
|
|
1128
|
+
console.error("[RichTextEditor] Error during attribute change re-initialization:", o);
|
|
1129
|
+
});
|
|
1130
|
+
}));
|
|
1131
|
+
break;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
/**
|
|
1135
|
+
* Resolve configuration from all sources
|
|
1136
|
+
*/
|
|
1137
|
+
resolveConfig() {
|
|
1138
|
+
const t = {};
|
|
1139
|
+
for (let e = 0; e < this.attributes.length; e++) {
|
|
1140
|
+
const o = this.attributes[e];
|
|
1141
|
+
t[o.name] = o.value;
|
|
1142
|
+
}
|
|
1143
|
+
return b.resolve({
|
|
1144
|
+
jsConfig: this.jsConfig,
|
|
1145
|
+
attributes: t
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Get public API
|
|
1150
|
+
*/
|
|
1151
|
+
getAPI() {
|
|
1152
|
+
return {
|
|
1153
|
+
getContent: () => {
|
|
1154
|
+
var t;
|
|
1155
|
+
return ((t = this.contentElement) == null ? void 0 : t.innerHTML) || "";
|
|
1156
|
+
},
|
|
1157
|
+
setContent: (t) => {
|
|
1158
|
+
this.contentElement && (this.contentElement.innerHTML = t);
|
|
1159
|
+
},
|
|
1160
|
+
execCommand: (t, e) => {
|
|
1161
|
+
var o;
|
|
1162
|
+
return ((o = this.engine) == null ? void 0 : o.execCommand(t, e)) || !1;
|
|
1163
|
+
},
|
|
1164
|
+
focus: () => {
|
|
1165
|
+
var t;
|
|
1166
|
+
(t = this.contentElement) == null || t.focus();
|
|
1167
|
+
},
|
|
1168
|
+
blur: () => {
|
|
1169
|
+
var t;
|
|
1170
|
+
(t = this.contentElement) == null || t.blur();
|
|
1171
|
+
},
|
|
1172
|
+
destroy: () => {
|
|
1173
|
+
this.destroy();
|
|
1174
|
+
},
|
|
1175
|
+
on: (t, e) => (this.addEventListener(t, e), () => this.removeEventListener(t, e)),
|
|
1176
|
+
getConfig: () => ({ ...this.config }),
|
|
1177
|
+
setReadonly: (t) => {
|
|
1178
|
+
this.setAttribute("readonly", t.toString());
|
|
1179
|
+
}
|
|
1180
|
+
};
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* Destroy the editor
|
|
1184
|
+
*/
|
|
1185
|
+
destroy() {
|
|
1186
|
+
var t, e, o, i;
|
|
1187
|
+
(t = this.engine) == null || t.destroy(), (e = this.toolbar) == null || e.destroy(), (o = this.floatingToolbar) == null || o.destroy(), (i = this.statusBar) == null || i.destroy(), this.innerHTML = "", this.isInitialized = !1, this.dispatchEvent(new Event("editor-destroy", { bubbles: !0 }));
|
|
1188
|
+
}
|
|
1189
|
+
// Public API methods
|
|
1190
|
+
getContent() {
|
|
1191
|
+
var t;
|
|
1192
|
+
return ((t = this.contentElement) == null ? void 0 : t.innerHTML) || "";
|
|
1193
|
+
}
|
|
1194
|
+
setContent(t) {
|
|
1195
|
+
this.contentElement && (this.contentElement.innerHTML = t);
|
|
1196
|
+
}
|
|
1197
|
+
execCommand(t, e) {
|
|
1198
|
+
var o;
|
|
1199
|
+
return ((o = this.engine) == null ? void 0 : o.execCommand(t, e)) || !1;
|
|
1200
|
+
}
|
|
1201
|
+
focus() {
|
|
1202
|
+
var t;
|
|
1203
|
+
(t = this.contentElement) == null || t.focus();
|
|
1204
|
+
}
|
|
1205
|
+
blur() {
|
|
1206
|
+
var t;
|
|
1207
|
+
(t = this.contentElement) == null || t.blur();
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
const x = new w();
|
|
1211
|
+
g.__globalPluginLoader = x;
|
|
1212
|
+
const B = {
|
|
1213
|
+
// Core editing plugins (always loaded)
|
|
1214
|
+
bold: () => import("./BoldPlugin.native-BAzzoqU5.mjs").then((s) => s.BoldPlugin()),
|
|
1215
|
+
italic: () => import("./ItalicPlugin.native-CQjjDyUL.mjs").then((s) => s.ItalicPlugin()),
|
|
1216
|
+
underline: () => import("./UnderlinePlugin.native-QpIcK4L2.mjs").then((s) => s.UnderlinePlugin()),
|
|
1217
|
+
strikethrough: () => import("./StrikethroughPlugin.native-ChaZLaXw.mjs").then((s) => s.StrikethroughPlugin()),
|
|
1218
|
+
clearFormatting: () => import("./ClearFormattingPlugin.native-BZPDHswo.mjs").then((s) => s.ClearFormattingPlugin()),
|
|
1219
|
+
heading: () => import("./HeadingPlugin.native-DrLYwQnQ.mjs").then((s) => s.HeadingPlugin()),
|
|
1220
|
+
blockquote: () => import("./BlockquotePlugin.native-JFmOLsxN.mjs").then((s) => s.BlockquotePlugin()),
|
|
1221
|
+
code: () => import("./CodePlugin.native-DD9xFIid.mjs").then((s) => s.CodePlugin()),
|
|
1222
|
+
list: () => import("./ListPlugin.native-CLFU5AUQ.mjs").then((s) => s.ListPlugin()),
|
|
1223
|
+
history: () => import("./HistoryPlugin.native-DoDRifCf.mjs").then((s) => s.HistoryPlugin())
|
|
1224
|
+
};
|
|
1225
|
+
async function D() {
|
|
1226
|
+
return Object.entries(B).forEach(([s, t]) => {
|
|
1227
|
+
x.register(s, t);
|
|
1228
|
+
}), x;
|
|
1229
|
+
}
|
|
1230
|
+
typeof window != "undefined" && D().then((s) => {
|
|
1231
|
+
g.__globalPluginLoader = s, customElements.get("editora-editor") || customElements.define("editora-editor", g);
|
|
1232
|
+
const t = document.querySelectorAll("editora-editor:not([data-initial-content])"), e = [];
|
|
1233
|
+
t.forEach((o) => {
|
|
1234
|
+
const i = o.innerHTML.trim();
|
|
1235
|
+
i && (e.push(i), o.setAttribute("data-initial-content", i), o.innerHTML = "");
|
|
1236
|
+
}), t.forEach((o, i) => {
|
|
1237
|
+
o instanceof g && !o.isInitialized && e[i] && o.setAttribute("content", e[i]);
|
|
1238
|
+
});
|
|
1239
|
+
});
|
|
1240
|
+
export {
|
|
1241
|
+
D as initWebComponent
|
|
1242
|
+
};
|
|
1243
|
+
//# sourceMappingURL=webcomponent-core.js.map
|