Packages
ckeditor5_phoenix
1.11.0
1.28.2
1.28.1
1.28.0
1.27.2
1.27.1
1.27.0
1.26.0
1.25.1
1.25.0
1.24.2
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.0
1.19.0
1.18.0
1.17.2
1.17.1
1.17.0
1.16.1
1.16.0
1.15.8
1.15.7
1.15.6
1.15.5
1.15.4
1.15.3
1.15.2
1.15.1
1.15.0
1.14.2
1.14.1
1.14.0
1.13.0
1.12.0
1.11.0
1.10.2
1.10.1
1.10.0
1.9.0
1.8.0
1.7.0
1.6.0
1.5.0
1.4.1
1.4.0
1.3.0
1.2.1
1.2.0
1.1.0
1.0.8
1.0.7
CKEditor 5 integration for Phoenix Framework
Current section
Files
Jump to
Current section
Files
dist/index.mjs
class q {
/**
* Map of registered items.
*/
items = /* @__PURE__ */ new Map();
/**
* Map of callbacks that are waiting for an item to be registered.
*/
callbacks = /* @__PURE__ */ new Map();
/**
* Set of watchers that observe changes to the registry.
*/
watchers = /* @__PURE__ */ new Set();
/**
* Executes a function on an item.
* If the item is not yet registered, it will wait for it to be registered.
*
* @param id The ID of the item.
* @param fn The function to execute.
* @returns A promise that resolves with the result of the function.
*/
execute(t, e) {
const { callbacks: r, items: n } = this, i = n.get(t);
return i ? Promise.resolve(e(i)) : new Promise((o) => {
const s = async (c) => o(await e(c));
this.callbacks.has(t) || r.set(t, []), r.set(t, [
...r.get(t),
s
]);
});
}
/**
* Registers an item.
*
* @param id The ID of the item.
* @param item The item instance.
*/
register(t, e) {
const { items: r, callbacks: n } = this, i = n.get(t);
if (r.has(t))
throw new Error(`Item with ID "${t}" is already registered.`);
r.set(t, e), i && (i.forEach((o) => o(e)), n.delete(t)), this.items.size === 1 && this.register(null, e), this.notifyWatchers();
}
/**
* Un-registers an item.
*
* @param id The ID of the item.
*/
unregister(t) {
const { items: e, callbacks: r } = this;
if (!e.has(t))
throw new Error(`Item with ID "${t}" is not registered.`);
t && this.items.get(null) === e.get(t) && this.unregister(null), e.delete(t), r.delete(t), this.notifyWatchers();
}
/**
* Gets all registered items.
*/
getItems() {
return Array.from(this.items.values());
}
/**
* Checks if an item with the given ID is registered.
*
* @param id The ID of the item.
* @returns `true` if the item is registered, `false` otherwise.
*/
hasItem(t) {
return this.items.has(t);
}
/**
* Gets a promise that resolves with the item instance for the given ID.
* If the item is not registered yet, it will wait for it to be registered.
*
* @param id The ID of the item.
* @returns A promise that resolves with the item instance.
*/
waitFor(t) {
return this.execute(t, (e) => e);
}
/**
* Destroys all registered items and clears the registry.
* This will call the `destroy` method on each item.
*/
async destroyAll() {
const t = Array.from(new Set(this.items.values())).map((e) => e.destroy());
this.items.clear(), this.callbacks.clear(), await Promise.all(t), this.notifyWatchers();
}
/**
* Registers a watcher that will be called whenever the registry changes.
*
* @param watcher The watcher function to register.
* @returns A function to unregister the watcher.
*/
watch(t) {
return this.watchers.add(t), t(new Map(this.items)), this.unwatch.bind(this, t);
}
/**
* Un-registers a watcher.
*
* @param watcher The watcher function to unregister.
*/
unwatch(t) {
this.watchers.delete(t);
}
/**
* Notifies all watchers about changes to the registry.
*/
notifyWatchers() {
const t = new Map(this.items);
this.watchers.forEach((e) => e(t));
}
}
function F(a) {
return a.replace(/[-_\s]+(.)?/g, (t, e) => e ? e.toUpperCase() : "").replace(/^./, (t) => t.toLowerCase());
}
function T(a, t) {
let e = null;
return (...r) => {
e && clearTimeout(e), e = setTimeout(() => {
t(...r);
}, a);
};
}
function G(a) {
if (Object.prototype.toString.call(a) !== "[object Object]")
return !1;
const t = Object.getPrototypeOf(a);
return t === Object.prototype || t === null;
}
function y(a) {
if (Array.isArray(a))
return a.map(y);
if (G(a)) {
const t = /* @__PURE__ */ Object.create(null);
for (const [e, r] of Object.entries(a))
t[F(e)] = y(r);
return t;
}
return a;
}
class k {
/**
* The current state of the hook.
*/
state = "mounting";
/**
* The DOM element the hook is attached to.
* It includes an `instance` property to hold the hook instance.
*/
el;
/**
* The LiveView socket instance, providing connection to the server.
*/
liveSocket;
/**
* Pushes an event from the client to the LiveView server process.
* @param _event The name of the event.
* @param _payload The data to send with the event.
* @param _callback An optional function to be called with the server's reply.
*/
pushEvent;
/**
* Pushes an event to another hook on the page.
* @param _selector The CSS selector of the target element with the hook.
* @param _event The name of the event.
* @param _payload The data to send with the event.
* @param _callback An optional function to be called with the reply.
*/
pushEventTo;
/**
* Registers a handler for an event pushed from the server.
* @param _event The name of the event to handle.
* @param _callback The function to execute when the event is received.
*/
handleEvent;
/**
* Checks if the hook is in the process of being destroyed.
*/
isBeingDestroyed() {
return this.state === "destroyed" || this.state === "destroying";
}
}
function E(a) {
return {
/**
* The mounted lifecycle callback for the LiveView hook object.
* It creates an instance of the user-defined hook class and sets up the necessary properties and methods.
*/
async mounted() {
const t = new a();
this.el.instance = t, t.el = this.el, t.liveSocket = this.liveSocket, t.pushEvent = (r, n, i) => this.pushEvent?.(r, n, i), t.pushEventTo = (r, n, i, o) => this.pushEventTo?.(r, n, i, o), t.handleEvent = (r, n) => this.handleEvent?.(r, n), t.state = "mounting";
const e = await t.mounted?.();
return t.state = "mounted", e;
},
/**
* The beforeUpdate lifecycle callback that delegates to the hook instance.
*/
beforeUpdate() {
this.el.instance.beforeUpdate?.();
},
/**
* The destroyed lifecycle callback that delegates to the hook instance.
*/
async destroyed() {
const { instance: t } = this.el;
t.state = "destroying", await t.destroyed?.(), t.state = "destroyed";
},
/**
* The disconnected lifecycle callback that delegates to the hook instance.
*/
disconnected() {
this.el.instance.disconnected?.();
},
/**
* The reconnected lifecycle callback that delegates to the hook instance.
*/
reconnected() {
this.el.instance.reconnected?.();
}
};
}
function B(a) {
return Object.keys(a).length === 0 && a.constructor === Object;
}
function O(a, t) {
const e = Object.entries(a).map(([r, n]) => [r, t(n, r)]);
return Object.fromEntries(e);
}
function M(a) {
if (a === null)
return null;
const t = Number.parseInt(a, 10);
return Number.isNaN(t) ? null : t;
}
function Y() {
return Math.random().toString(36).substring(2);
}
const C = Symbol.for("context-editor-watchdog");
async function J({ element: a, context: t, creator: e, config: r }) {
const n = Y();
await t.add({
creator: (c, h) => e.create(c, h),
id: n,
sourceElementOrData: a,
type: "editor",
config: r
});
const i = t.getItem(n), o = {
state: "available",
editorContextId: n,
context: t
};
i[C] = o;
const s = t.destroy.bind(t);
return t.destroy = async () => (o.state = "unavailable", s()), {
...o,
editor: i
};
}
function X(a) {
return C in a ? a[C] : null;
}
function A(a) {
return ["inline", "classic", "balloon", "decoupled"].includes(a);
}
async function Q(a) {
const t = await import("ckeditor5"), r = {
inline: t.InlineEditor,
balloon: t.BalloonEditor,
classic: t.ClassicEditor,
decoupled: t.DecoupledEditor,
multiroot: t.MultiRootEditor
}[a];
if (!r)
throw new Error(`Unsupported editor type: ${a}`);
return r;
}
class $ {
static the = new $();
/**
* Map of registered custom plugins.
*/
plugins = /* @__PURE__ */ new Map();
/**
* Private constructor to enforce singleton pattern.
*/
constructor() {
}
/**
* Registers a custom plugin for the CKEditor.
*
* @param name The name of the plugin.
* @param reader The plugin reader function that returns the plugin constructor.
* @returns A function to unregister the plugin.
*/
register(t, e) {
if (this.plugins.has(t))
throw new Error(`Plugin with name "${t}" is already registered.`);
return this.plugins.set(t, e), this.unregister.bind(this, t);
}
/**
* Removes a custom plugin by its name.
*
* @param name The name of the plugin to unregister.
* @throws Will throw an error if the plugin is not registered.
*/
unregister(t) {
if (!this.plugins.has(t))
throw new Error(`Plugin with name "${t}" is not registered.`);
this.plugins.delete(t);
}
/**
* Removes all custom editor plugins.
* This is useful for cleanup in tests or when reloading plugins.
*/
unregisterAll() {
this.plugins.clear();
}
/**
* Retrieves a custom plugin by its name.
*
* @param name The name of the plugin.
* @returns The plugin constructor or undefined if not found.
*/
async get(t) {
return this.plugins.get(t)?.();
}
/**
* Checks if a plugin with the given name is registered.
*
* @param name The name of the plugin.
* @returns `true` if the plugin is registered, `false` otherwise.
*/
has(t) {
return this.plugins.has(t);
}
}
async function L(a) {
const t = await import("ckeditor5");
let e = null;
const r = a.map(async (n) => {
const i = await $.the.get(n);
if (i)
return i;
const { [n]: o } = t;
if (o)
return o;
if (!e)
try {
e = await import("ckeditor5-premium-features");
} catch (c) {
console.error(`Failed to load premium package: ${c}`);
}
const { [n]: s } = e || {};
if (s)
return s;
throw new Error(`Plugin "${n}" not found in base or premium packages.`);
});
return {
loadedPlugins: await Promise.all(r),
hasPremium: !!e
};
}
async function U(a, t) {
const e = [a.ui, a.content];
return await Promise.all(
[
N("ckeditor5", e),
/* v8 ignore next */
t && N("ckeditor5-premium-features", e)
].filter((n) => !!n)
).then((n) => n.flat());
}
async function N(a, t) {
return await Promise.all(
t.filter((e) => e !== "en").map(async (e) => {
const r = await Z(a, e);
return r?.default ?? r;
}).filter(Boolean)
);
}
async function Z(a, t) {
try {
if (a === "ckeditor5")
switch (t) {
case "af":
return await import("ckeditor5/translations/af.js");
case "ar":
return await import("ckeditor5/translations/ar.js");
case "ast":
return await import("ckeditor5/translations/ast.js");
case "az":
return await import("ckeditor5/translations/az.js");
case "bg":
return await import("ckeditor5/translations/bg.js");
case "bn":
return await import("ckeditor5/translations/bn.js");
case "bs":
return await import("ckeditor5/translations/bs.js");
case "ca":
return await import("ckeditor5/translations/ca.js");
case "cs":
return await import("ckeditor5/translations/cs.js");
case "da":
return await import("ckeditor5/translations/da.js");
case "de":
return await import("ckeditor5/translations/de.js");
case "de-ch":
return await import("ckeditor5/translations/de-ch.js");
case "el":
return await import("ckeditor5/translations/el.js");
case "en":
return await import("ckeditor5/translations/en.js");
case "en-au":
return await import("ckeditor5/translations/en-au.js");
case "en-gb":
return await import("ckeditor5/translations/en-gb.js");
case "eo":
return await import("ckeditor5/translations/eo.js");
case "es":
return await import("ckeditor5/translations/es.js");
case "es-co":
return await import("ckeditor5/translations/es-co.js");
case "et":
return await import("ckeditor5/translations/et.js");
case "eu":
return await import("ckeditor5/translations/eu.js");
case "fa":
return await import("ckeditor5/translations/fa.js");
case "fi":
return await import("ckeditor5/translations/fi.js");
case "fr":
return await import("ckeditor5/translations/fr.js");
case "gl":
return await import("ckeditor5/translations/gl.js");
case "gu":
return await import("ckeditor5/translations/gu.js");
case "he":
return await import("ckeditor5/translations/he.js");
case "hi":
return await import("ckeditor5/translations/hi.js");
case "hr":
return await import("ckeditor5/translations/hr.js");
case "hu":
return await import("ckeditor5/translations/hu.js");
case "hy":
return await import("ckeditor5/translations/hy.js");
case "id":
return await import("ckeditor5/translations/id.js");
case "it":
return await import("ckeditor5/translations/it.js");
case "ja":
return await import("ckeditor5/translations/ja.js");
case "jv":
return await import("ckeditor5/translations/jv.js");
case "kk":
return await import("ckeditor5/translations/kk.js");
case "km":
return await import("ckeditor5/translations/km.js");
case "kn":
return await import("ckeditor5/translations/kn.js");
case "ko":
return await import("ckeditor5/translations/ko.js");
case "ku":
return await import("ckeditor5/translations/ku.js");
case "lt":
return await import("ckeditor5/translations/lt.js");
case "lv":
return await import("ckeditor5/translations/lv.js");
case "ms":
return await import("ckeditor5/translations/ms.js");
case "nb":
return await import("ckeditor5/translations/nb.js");
case "ne":
return await import("ckeditor5/translations/ne.js");
case "nl":
return await import("ckeditor5/translations/nl.js");
case "no":
return await import("ckeditor5/translations/no.js");
case "oc":
return await import("ckeditor5/translations/oc.js");
case "pl":
return await import("ckeditor5/translations/pl.js");
case "pt":
return await import("ckeditor5/translations/pt.js");
case "pt-br":
return await import("ckeditor5/translations/pt-br.js");
case "ro":
return await import("ckeditor5/translations/ro.js");
case "ru":
return await import("ckeditor5/translations/ru.js");
case "si":
return await import("ckeditor5/translations/si.js");
case "sk":
return await import("ckeditor5/translations/sk.js");
case "sl":
return await import("ckeditor5/translations/sl.js");
case "sq":
return await import("ckeditor5/translations/sq.js");
case "sr":
return await import("ckeditor5/translations/sr.js");
case "sr-latn":
return await import("ckeditor5/translations/sr-latn.js");
case "sv":
return await import("ckeditor5/translations/sv.js");
case "th":
return await import("ckeditor5/translations/th.js");
case "tk":
return await import("ckeditor5/translations/tk.js");
case "tr":
return await import("ckeditor5/translations/tr.js");
case "tt":
return await import("ckeditor5/translations/tt.js");
case "ug":
return await import("ckeditor5/translations/ug.js");
case "uk":
return await import("ckeditor5/translations/uk.js");
case "ur":
return await import("ckeditor5/translations/ur.js");
case "uz":
return await import("ckeditor5/translations/uz.js");
case "vi":
return await import("ckeditor5/translations/vi.js");
case "zh":
return await import("ckeditor5/translations/zh.js");
case "zh-cn":
return await import("ckeditor5/translations/zh-cn.js");
default:
return console.warn(`Language ${t} not found in ckeditor5 translations`), null;
}
else
switch (t) {
case "af":
return await import("ckeditor5-premium-features/translations/af.js");
case "ar":
return await import("ckeditor5-premium-features/translations/ar.js");
case "ast":
return await import("ckeditor5-premium-features/translations/ast.js");
case "az":
return await import("ckeditor5-premium-features/translations/az.js");
case "bg":
return await import("ckeditor5-premium-features/translations/bg.js");
case "bn":
return await import("ckeditor5-premium-features/translations/bn.js");
case "bs":
return await import("ckeditor5-premium-features/translations/bs.js");
case "ca":
return await import("ckeditor5-premium-features/translations/ca.js");
case "cs":
return await import("ckeditor5-premium-features/translations/cs.js");
case "da":
return await import("ckeditor5-premium-features/translations/da.js");
case "de":
return await import("ckeditor5-premium-features/translations/de.js");
case "de-ch":
return await import("ckeditor5-premium-features/translations/de-ch.js");
case "el":
return await import("ckeditor5-premium-features/translations/el.js");
case "en":
return await import("ckeditor5-premium-features/translations/en.js");
case "en-au":
return await import("ckeditor5-premium-features/translations/en-au.js");
case "en-gb":
return await import("ckeditor5-premium-features/translations/en-gb.js");
case "eo":
return await import("ckeditor5-premium-features/translations/eo.js");
case "es":
return await import("ckeditor5-premium-features/translations/es.js");
case "es-co":
return await import("ckeditor5-premium-features/translations/es-co.js");
case "et":
return await import("ckeditor5-premium-features/translations/et.js");
case "eu":
return await import("ckeditor5-premium-features/translations/eu.js");
case "fa":
return await import("ckeditor5-premium-features/translations/fa.js");
case "fi":
return await import("ckeditor5-premium-features/translations/fi.js");
case "fr":
return await import("ckeditor5-premium-features/translations/fr.js");
case "gl":
return await import("ckeditor5-premium-features/translations/gl.js");
case "gu":
return await import("ckeditor5-premium-features/translations/gu.js");
case "he":
return await import("ckeditor5-premium-features/translations/he.js");
case "hi":
return await import("ckeditor5-premium-features/translations/hi.js");
case "hr":
return await import("ckeditor5-premium-features/translations/hr.js");
case "hu":
return await import("ckeditor5-premium-features/translations/hu.js");
case "hy":
return await import("ckeditor5-premium-features/translations/hy.js");
case "id":
return await import("ckeditor5-premium-features/translations/id.js");
case "it":
return await import("ckeditor5-premium-features/translations/it.js");
case "ja":
return await import("ckeditor5-premium-features/translations/ja.js");
case "jv":
return await import("ckeditor5-premium-features/translations/jv.js");
case "kk":
return await import("ckeditor5-premium-features/translations/kk.js");
case "km":
return await import("ckeditor5-premium-features/translations/km.js");
case "kn":
return await import("ckeditor5-premium-features/translations/kn.js");
case "ko":
return await import("ckeditor5-premium-features/translations/ko.js");
case "ku":
return await import("ckeditor5-premium-features/translations/ku.js");
case "lt":
return await import("ckeditor5-premium-features/translations/lt.js");
case "lv":
return await import("ckeditor5-premium-features/translations/lv.js");
case "ms":
return await import("ckeditor5-premium-features/translations/ms.js");
case "nb":
return await import("ckeditor5-premium-features/translations/nb.js");
case "ne":
return await import("ckeditor5-premium-features/translations/ne.js");
case "nl":
return await import("ckeditor5-premium-features/translations/nl.js");
case "no":
return await import("ckeditor5-premium-features/translations/no.js");
case "oc":
return await import("ckeditor5-premium-features/translations/oc.js");
case "pl":
return await import("ckeditor5-premium-features/translations/pl.js");
case "pt":
return await import("ckeditor5-premium-features/translations/pt.js");
case "pt-br":
return await import("ckeditor5-premium-features/translations/pt-br.js");
case "ro":
return await import("ckeditor5-premium-features/translations/ro.js");
case "ru":
return await import("ckeditor5-premium-features/translations/ru.js");
case "si":
return await import("ckeditor5-premium-features/translations/si.js");
case "sk":
return await import("ckeditor5-premium-features/translations/sk.js");
case "sl":
return await import("ckeditor5-premium-features/translations/sl.js");
case "sq":
return await import("ckeditor5-premium-features/translations/sq.js");
case "sr":
return await import("ckeditor5-premium-features/translations/sr.js");
case "sr-latn":
return await import("ckeditor5-premium-features/translations/sr-latn.js");
case "sv":
return await import("ckeditor5-premium-features/translations/sv.js");
case "th":
return await import("ckeditor5-premium-features/translations/th.js");
case "tk":
return await import("ckeditor5-premium-features/translations/tk.js");
case "tr":
return await import("ckeditor5-premium-features/translations/tr.js");
case "tt":
return await import("ckeditor5-premium-features/translations/tt.js");
case "ug":
return await import("ckeditor5-premium-features/translations/ug.js");
case "uk":
return await import("ckeditor5-premium-features/translations/uk.js");
case "ur":
return await import("ckeditor5-premium-features/translations/ur.js");
case "uz":
return await import("ckeditor5-premium-features/translations/uz.js");
case "vi":
return await import("ckeditor5-premium-features/translations/vi.js");
case "zh":
return await import("ckeditor5-premium-features/translations/zh.js");
case "zh-cn":
return await import("ckeditor5-premium-features/translations/zh-cn.js");
default:
return console.warn(`Language ${t} not found in premium translations`), await import("ckeditor5-premium-features/translations/en.js");
}
} catch (e) {
return console.error(`Failed to load translation for ${a}/${t}:`, e), null;
}
}
function W(a) {
return O(a, (t) => ({
dictionary: t
}));
}
function D(a) {
const t = document.querySelectorAll(
[
`[data-cke-editor-id="${a}"][data-cke-editable-root-name]`,
"[data-cke-editable-root-name]:not([data-cke-editor-id])"
].join(", ")
);
return Array.from(t).reduce((e, r) => {
const n = r.getAttribute("data-cke-editable-root-name"), i = r.getAttribute("data-cke-editable-initial-value") || "", o = r.querySelector("[data-cke-editable-content]");
return !n || !o ? e : {
...e,
[n]: {
content: o,
initialValue: i
}
};
}, /* @__PURE__ */ Object.create({}));
}
const R = ["inline", "classic", "balloon", "decoupled", "multiroot"];
function tt(a) {
const t = a.getAttribute("cke-preset");
if (!t)
throw new Error('CKEditor5 hook requires a "cke-preset" attribute on the element.');
const { type: e, config: r, license: n, ...i } = JSON.parse(t);
if (!e || !r || !n)
throw new Error('CKEditor5 hook configuration must include "editor", "config", and "license" properties.');
if (!R.includes(e))
throw new Error(`Invalid editor type: ${e}. Must be one of: ${R.join(", ")}.`);
return {
type: e,
license: n,
config: y(r),
customTranslations: i.customTranslations || i.custom_translations
};
}
function I(a) {
if (!a || typeof a != "object")
return a;
if (Array.isArray(a))
return a.map((r) => I(r));
const t = a;
if (t.$element && typeof t.$element == "string") {
const r = document.querySelector(t.$element);
return r || console.warn(`Element not found for selector: ${t.$element}`), r || null;
}
const e = /* @__PURE__ */ Object.create(null);
for (const [r, n] of Object.entries(a))
e[r] = I(n);
return e;
}
function et(a, t) {
const { editing: e } = a;
e.view.change((r) => {
r.setStyle("height", `${t}px`, e.view.document.getRoot());
});
}
const x = Symbol.for("elixir-editor-watchdog");
async function rt(a) {
const { EditorWatchdog: t } = await import("ckeditor5"), e = new t(a);
return e.setCreator(async (...r) => {
const n = await a.create(...r);
return n[x] = e, n;
}), {
watchdog: e,
Constructor: {
create: async (...r) => (await e.create(...r), e.editor)
}
};
}
function at(a) {
return x in a ? a[x] : null;
}
class w extends q {
static the = new w();
}
function nt(a) {
const t = a.getAttribute("cke-context");
if (!t)
throw new Error('CKEditor5 hook requires a "cke-context" attribute on the element.');
const { config: e, ...r } = JSON.parse(t);
return {
config: y(e),
customTranslations: r.customTranslations || r.custom_translations,
watchdogConfig: r.watchdogConfig || r.watchdog_config
};
}
class it extends k {
/**
* The promise that resolves to the context instance.
*/
contextPromise = null;
/**
* Attributes for the context instance.
*/
get attrs() {
const t = (r) => this.el.getAttribute(r) || null, e = {
id: this.el.id,
config: nt(this.el),
language: {
ui: t("cke-language") || "en",
content: t("cke-content-language") || "en"
}
};
return Object.defineProperty(this, "attrs", {
value: e,
writable: !1,
configurable: !1,
enumerable: !0
}), e;
}
/**
* Mounts the context component.
*/
async mounted() {
const { id: t, language: e } = this.attrs, { customTranslations: r, watchdogConfig: n, config: { plugins: i, ...o } } = this.attrs.config, { loadedPlugins: s, hasPremium: c } = await L(i ?? []), l = [
...await U(e, c),
W(r?.dictionary || {})
].filter((g) => !B(g));
this.contextPromise = (async () => {
const { ContextWatchdog: g, Context: P } = await import("ckeditor5"), d = new g(P, {
crashNumberLimit: 10,
...n
});
return await d.create({
...o,
language: e,
plugins: s,
...l.length && {
translations: l
}
}), d.on("itemError", (...b) => {
console.error("Context item error:", ...b);
}), d;
})();
const f = await this.contextPromise;
this.isBeingDestroyed() || w.the.register(t, f);
}
/**
* Destroys the context component. Unmounts root from the editor.
*/
async destroyed() {
const { id: t } = this.attrs;
this.el.style.display = "none";
try {
await (await this.contextPromise)?.destroy();
} finally {
this.contextPromise = null, w.the.hasItem(t) && w.the.unregister(t);
}
}
}
function ot(a) {
return a.hasAttribute("cke-context");
}
function st(a) {
let t = a;
for (; t; ) {
if (ot(t))
return t;
t = t.parentElement;
}
return null;
}
async function ct(a) {
const t = st(a);
return t ? w.the.waitFor(t.id) : null;
}
const ut = E(it);
class m extends q {
static the = new m();
}
class lt extends k {
/**
* The name of the hook.
*/
mountedPromise = null;
/**
* Attributes for the editable instance.
*/
get attrs() {
const t = {
editableId: this.el.getAttribute("id"),
editorId: this.el.getAttribute("data-cke-editor-id") || null,
rootName: this.el.getAttribute("data-cke-editable-root-name"),
initialValue: this.el.getAttribute("data-cke-editable-initial-value") || ""
};
return Object.defineProperty(this, "attrs", {
value: t,
writable: !1,
configurable: !1,
enumerable: !0
}), t;
}
/**
* Mounts the editable component.
*/
async mounted() {
const { editableId: t, editorId: e, rootName: r, initialValue: n } = this.attrs, i = this.el.querySelector(`#${t}_input`);
this.mountedPromise = m.the.execute(e, (o) => {
const { ui: s, editing: c, model: h } = o;
if (h.document.getRoot(r))
return;
o.addRoot(r, {
isUndoable: !1,
data: n
});
const l = this.el.querySelector("[data-cke-editable-content]"), f = s.view.createEditable(r, l);
s.addEditable(f), c.view.forceRender(), i && dt(i, o, r);
});
}
/**
* Destroys the editable component. Unmounts root from the editor.
*/
async destroyed() {
const { editorId: t, rootName: e } = this.attrs;
this.el.style.display = "none", await this.mountedPromise, this.mountedPromise = null, await m.the.execute(t, (r) => {
const n = r.model.document.getRoot(e);
n && "detachEditable" in r && (r.detachEditable(n), r.detachRoot(e, !1));
});
}
}
const mt = E(lt);
function dt(a, t, e) {
const r = () => {
a.value = t.getData({ rootName: e });
};
t.model.document.on("change:data", T(100, r)), r();
}
class pt extends k {
/**
* The promise that resolves to the editor instance.
*/
editorPromise = null;
/**
* Attributes for the editor instance.
*/
get attrs() {
const { el: t } = this, e = t.getAttribute.bind(t), r = t.hasAttribute.bind(t), n = {
editorId: e("id"),
contextId: e("cke-context-id"),
preset: tt(t),
editableHeight: M(e("cke-editable-height")),
watchdog: r("cke-watchdog"),
events: {
change: r("cke-change-event"),
blur: r("cke-blur-event"),
focus: r("cke-focus-event")
},
saveDebounceMs: M(e("cke-save-debounce-ms")) ?? 400,
language: {
ui: e("cke-language") || "en",
content: e("cke-content-language") || "en"
}
};
return Object.defineProperty(this, "attrs", {
value: n,
writable: !1,
configurable: !1,
enumerable: !0
}), n;
}
/**
* Mounts the editor component.
*/
async mounted() {
const { editorId: t } = this.attrs;
this.editorPromise = this.createEditor();
const e = await this.editorPromise;
return this.isBeingDestroyed() || (m.the.register(t, e), e.once("destroy", () => {
m.the.hasItem(t) && m.the.unregister(t);
})), this;
}
/**
* Destroys the editor instance when the component is destroyed.
* This is important to prevent memory leaks and ensure that the editor is properly cleaned up.
*/
async destroyed() {
this.el.style.display = "none";
try {
const t = await this.editorPromise, e = X(t), r = at(t);
e ? e.state !== "unavailable" && await e.context.remove(e.editorContextId) : r ? await r.destroy() : await t.destroy();
} finally {
this.editorPromise = null;
}
}
/**
* Creates the CKEditor instance.
*/
async createEditor() {
const { preset: t, editorId: e, contextId: r, editableHeight: n, events: i, saveDebounceMs: o, language: s, watchdog: c } = this.attrs, { customTranslations: h, type: l, license: f, config: { plugins: g, ...P } } = t;
let d = await Q(l);
const b = await (r ? w.the.waitFor(r) : ct(this.el));
if (c && !b) {
const u = await rt(d);
({ Constructor: d } = u), u.watchdog.on("restart", () => {
const H = u.watchdog.editor;
this.editorPromise = Promise.resolve(H), m.the.register(e, H);
});
}
const { loadedPlugins: z, hasPremium: K } = await L(g), j = [
...await U(s, K),
W(h?.dictionary || {})
].filter((u) => !B(u)), v = ft(e, l), S = {
...I(P),
initialData: gt(e, l),
licenseKey: f.key,
plugins: z,
language: s,
...j.length && {
translations: j
}
}, p = await (async () => !b || !(v instanceof HTMLElement) ? d.create(v, S) : (await J({
context: b,
element: v,
creator: d,
config: S
})).editor)();
if (i.change && this.setupTypingContentPush(e, p, o), i.blur && this.setupEventPush(e, p, "blur"), i.focus && this.setupEventPush(e, p, "focus"), this.handleEvent("ckeditor5:set-data", ({ data: u }) => {
p.setData(u);
}), A(l)) {
const u = document.getElementById(`${e}_input`);
u && wt(u, p, o), n && et(p, n);
}
return p;
}
/**
* Setups the content push event for the editor.
*/
setupTypingContentPush(t, e, r) {
const n = () => {
this.pushEvent(
"ckeditor5:change",
{
editorId: t,
data: V(e)
}
);
};
e.model.document.on("change:data", T(r, n)), n();
}
/**
* Setups the event push for the editor.
*/
setupEventPush(t, e, r) {
const n = () => {
const { isFocused: i } = e.ui.focusTracker;
(i ? "focus" : "blur") === r && this.pushEvent(
`ckeditor5:${r}`,
{
editorId: t,
data: V(e)
}
);
};
e.ui.focusTracker.on("change:isFocused", n);
}
}
function V(a) {
return a.model.document.getRootNames().reduce((e, r) => (e[r] = a.getData({ rootName: r }), e), /* @__PURE__ */ Object.create({}));
}
function wt(a, t, e) {
const r = () => {
const n = t.getData();
a.value = n, a.dispatchEvent(new Event("input", { bubbles: !0 }));
};
t.model.document.on("change:data", T(e, r)), ht(a)?.addEventListener("submit", r), r();
}
function ht(a) {
return a.closest("form");
}
function ft(a, t) {
if (t === "decoupled") {
const { content: r } = _(a);
return r;
}
if (A(t))
return document.getElementById(`${a}_editor`);
const e = D(a);
return O(e, ({ content: r }) => r);
}
function gt(a, t) {
if (t === "decoupled") {
const { initialValue: r } = _(a);
if (r)
return r;
}
if (A(t))
return document.getElementById(a)?.getAttribute("cke-initial-value") || "";
const e = D(a);
return O(e, ({ initialValue: r }) => r);
}
function _(a) {
const t = D(a).main;
if (!t)
throw new Error(`No "main" editable found for editor with ID "${a}".`);
return t;
}
const bt = E(pt);
class yt extends k {
/**
* The name of the hook.
*/
mountedPromise = null;
/**
* Attributes for the editable instance.
*/
get attrs() {
const t = {
editorId: this.el.getAttribute("data-cke-editor-id") || null,
name: this.el.getAttribute("data-cke-ui-part-name")
};
return Object.defineProperty(this, "attrs", {
value: t,
writable: !1,
configurable: !1,
enumerable: !0
}), t;
}
/**
* Mounts the editable component.
*/
async mounted() {
const { editorId: t, name: e } = this.attrs;
this.mountedPromise = m.the.execute(t, (r) => {
const { ui: n } = r, i = kt(e), o = n.view[i];
if (!o) {
console.error(`Unknown UI part name: "${e}". Supported names are "toolbar" and "menubar".`);
return;
}
this.el.appendChild(o.element);
});
}
/**
* Destroys the editable component. Unmounts root from the editor.
*/
async destroyed() {
this.el.style.display = "none", await this.mountedPromise, this.mountedPromise = null, this.el.innerHTML = "";
}
}
function kt(a) {
switch (a) {
case "toolbar":
return "toolbar";
case "menubar":
return "menuBarView";
default:
return null;
}
}
const Et = E(yt), vt = {
CKEditor5: bt,
CKEditable: mt,
CKUIPart: Et,
CKContext: ut
};
export {
$ as CustomEditorPluginsRegistry,
m as EditorsRegistry,
vt as Hooks,
X as unwrapEditorContext,
at as unwrapEditorWatchdog
};
//# sourceMappingURL=index.mjs.map