Current section

Files

Jump to
ckeditor5_phoenix dist index.mjs
Raw

dist/index.mjs

class V {
/**
* Map of registered items.
*/
items = /* @__PURE__ */ new Map();
/**
* Map of initialization errors for items that failed to register.
*/
initializationErrors = /* @__PURE__ */ new Map();
/**
* Map of pending callbacks waiting for items to be registered or fail.
*/
pendingCallbacks = /* @__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 onSuccess The function to execute.
* @param onError Optional error callback.
* @returns A promise that resolves with the result of the function.
*/
execute(t, e, r) {
const a = this.items.get(t), n = this.initializationErrors.get(t);
return n ? (r?.(n), Promise.reject(n)) : a ? Promise.resolve(e(a)) : new Promise((s, u) => {
const o = this.getPendingCallbacks(t);
o.success.push(async (c) => {
s(await e(c));
}), r ? o.error.push(r) : o.error.push(u);
});
}
/**
* Registers an item.
*
* @param id The ID of the item.
* @param item The item instance.
*/
register(t, e) {
if (this.items.has(t))
throw new Error(`Item with ID "${t}" is already registered.`);
this.resetErrors(t), this.items.set(t, e);
const r = this.pendingCallbacks.get(t);
r && (r.success.forEach((a) => a(e)), this.pendingCallbacks.delete(t)), this.registerAsDefault(t, e), this.notifyWatchers();
}
/**
* Registers an error for an item.
*
* @param id The ID of the item.
* @param error The error to register.
*/
error(t, e) {
this.items.delete(t), this.initializationErrors.set(t, e);
const r = this.pendingCallbacks.get(t);
r && (r.error.forEach((a) => a(e)), this.pendingCallbacks.delete(t)), this.initializationErrors.size === 1 && !this.items.size && this.error(null, e), this.notifyWatchers();
}
/**
* Resets errors for an item.
*
* @param id The ID of the item.
*/
resetErrors(t) {
const { initializationErrors: e } = this;
e.has(null) && e.get(null) === e.get(t) && e.delete(null), e.delete(t);
}
/**
* Un-registers an item.
*
* @param id The ID of the item.
*/
unregister(t) {
if (!this.items.has(t))
throw new Error(`Item with ID "${t}" is not registered.`);
t && this.items.get(null) === this.items.get(t) && this.unregister(null), this.items.delete(t), this.pendingCallbacks.delete(t), this.notifyWatchers();
}
/**
* Gets all registered items.
*
* @returns An array of 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 new Promise((e, r) => {
this.execute(t, e, r);
});
}
/**
* 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.pendingCallbacks.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),
new Map(this.initializationErrors)
), 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() {
this.watchers.forEach(
(t) => t(
new Map(this.items),
new Map(this.initializationErrors)
)
);
}
/**
* Gets or creates pending callbacks for a specific ID.
*
* @param id The ID of the item.
* @returns The pending callbacks structure.
*/
getPendingCallbacks(t) {
let e = this.pendingCallbacks.get(t);
return e || (e = { success: [], error: [] }, this.pendingCallbacks.set(t, e)), e;
}
/**
* Registers an item as the default (null ID) item if it's the first one.
*
* @param id The ID of the item being registered.
* @param item The item instance.
*/
registerAsDefault(t, e) {
this.items.size === 1 && t !== null && this.register(null, e);
}
}
function F(i) {
return i.replace(/[-_\s]+(.)?/g, (t, e) => e ? e.toUpperCase() : "").replace(/^./, (t) => t.toLowerCase());
}
function O(i, t) {
let e = null;
return (...r) => {
e && clearTimeout(e), e = setTimeout(() => {
t(...r);
}, i);
};
}
function G(i) {
if (Object.prototype.toString.call(i) !== "[object Object]")
return !1;
const t = Object.getPrototypeOf(i);
return t === Object.prototype || t === null;
}
function b(i) {
if (Array.isArray(i))
return i.map(b);
if (G(i)) {
const t = /* @__PURE__ */ Object.create(null);
for (const [e, r] of Object.entries(i))
t[F(e)] = b(r);
return t;
}
return i;
}
class E {
/**
* 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 k(i) {
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 i();
this.el.instance = t, t.el = this.el, t.liveSocket = this.liveSocket, t.pushEvent = (r, a, n) => this.pushEvent?.(r, a, n), t.pushEventTo = (r, a, n, s) => this.pushEventTo?.(r, a, n, s), t.handleEvent = (r, a) => this.handleEvent?.(r, a), 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 L(i) {
return Object.keys(i).length === 0 && i.constructor === Object;
}
function Y(i) {
return i == null;
}
function A(i, t) {
const e = Object.entries(i).map(([r, a]) => [r, t(a, r)]);
return Object.fromEntries(e);
}
function N(i) {
if (i === null)
return null;
const t = Number.parseInt(i, 10);
return Number.isNaN(t) ? null : t;
}
function J() {
return Math.random().toString(36).substring(2);
}
const I = Symbol.for("context-editor-watchdog");
async function X({ element: i, context: t, creator: e, config: r }) {
const a = J();
await t.add({
creator: (o, c) => e.create(o, c),
id: a,
sourceElementOrData: i,
type: "editor",
config: r
});
const n = t.getItem(a), s = {
state: "available",
editorContextId: a,
context: t
};
n[I] = s;
const u = t.destroy.bind(t);
return t.destroy = async () => (s.state = "unavailable", u()), {
...s,
editor: n
};
}
function Q(i) {
return I in i ? i[I] : null;
}
function y(i) {
return ["inline", "classic", "balloon", "decoupled"].includes(i);
}
async function Z(i) {
const t = await import("ckeditor5"), r = {
inline: t.InlineEditor,
balloon: t.BalloonEditor,
classic: t.ClassicEditor,
decoupled: t.DecoupledEditor,
multiroot: t.MultiRootEditor
}[i];
if (!r)
throw new Error(`Unsupported editor type: ${i}`);
return r;
}
class D {
static the = new D();
/**
* 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 q(i) {
const t = await import("ckeditor5");
let e = null;
const r = i.map(async (a) => {
const n = await D.the.get(a);
if (n)
return n;
const { [a]: s } = t;
if (s)
return s;
if (!e)
try {
e = await import("ckeditor5-premium-features");
} catch (o) {
console.error(`Failed to load premium package: ${o}`);
}
const { [a]: u } = e || {};
if (u)
return u;
throw new Error(`Plugin "${a}" not found in base or premium packages.`);
});
return {
loadedPlugins: await Promise.all(r),
hasPremium: !!e
};
}
async function B(i, t) {
const e = [i.ui, i.content];
return await Promise.all(
[
z("ckeditor5", e),
/* v8 ignore next */
t && z("ckeditor5-premium-features", e)
].filter((a) => !!a)
).then((a) => a.flat());
}
async function z(i, t) {
return await Promise.all(
t.filter((e) => e !== "en").map(async (e) => {
const r = await tt(i, e);
return r?.default ?? r;
}).filter(Boolean)
);
}
async function tt(i, t) {
try {
if (i === "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 ${i}/${t}:`, e), null;
}
}
function U(i) {
return A(i, (t) => ({
dictionary: t
}));
}
function S(i) {
const t = document.querySelectorAll(
[
`[data-cke-editor-id="${i}"][data-cke-editable-root-name]`,
"[data-cke-editable-root-name]:not([data-cke-editor-id])"
].join(", ")
);
return Array.from(t).reduce((e, r) => {
const a = r.getAttribute("data-cke-editable-root-name"), n = r.getAttribute("data-cke-editable-initial-value") || "", s = r.querySelector("[data-cke-editable-content]");
return !a || !s ? e : {
...e,
[a]: {
content: s,
initialValue: n
}
};
}, /* @__PURE__ */ Object.create({}));
}
const W = ["inline", "classic", "balloon", "decoupled", "multiroot"];
function et(i) {
const t = i.getAttribute("cke-preset");
if (!t)
throw new Error('CKEditor5 hook requires a "cke-preset" attribute on the element.');
const { type: e, config: r, license: a, ...n } = JSON.parse(t);
if (!e || !r || !a)
throw new Error('CKEditor5 hook configuration must include "editor", "config", and "license" properties.');
if (!W.includes(e))
throw new Error(`Invalid editor type: ${e}. Must be one of: ${W.join(", ")}.`);
return {
type: e,
license: a,
config: b(r),
customTranslations: n.customTranslations || n.custom_translations
};
}
function x(i) {
if (!i || typeof i != "object")
return i;
if (Array.isArray(i))
return i.map((r) => x(r));
const t = i;
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, a] of Object.entries(i))
e[r] = x(a);
return e;
}
function rt(i, t) {
const { editing: e } = i;
e.view.change((r) => {
r.setStyle("height", `${t}px`, e.view.document.getRoot());
});
}
const T = Symbol.for("elixir-editor-watchdog");
async function it(i) {
const { EditorWatchdog: t } = await import("ckeditor5"), e = new t(i);
return e.setCreator(async (...r) => {
const a = await i.create(...r);
return a[T] = e, a;
}), {
watchdog: e,
Constructor: {
create: async (...r) => (await e.create(...r), e.editor)
}
};
}
function at(i) {
return T in i ? i[T] : null;
}
class p extends V {
static the = new p();
}
function nt(i) {
const t = i.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: b(e),
customTranslations: r.customTranslations || r.custom_translations,
watchdogConfig: r.watchdogConfig || r.watchdog_config
};
}
class st extends E {
/**
* 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: a, config: { plugins: n, ...s } } = this.attrs.config, { loadedPlugins: u, hasPremium: o } = await q(n ?? []), l = [
...await B(e, o),
U(r?.dictionary || {})
].filter((w) => !L(w));
this.contextPromise = (async () => {
const { ContextWatchdog: w, Context: P } = await import("ckeditor5"), m = new w(P, {
crashNumberLimit: 10,
...a
});
return await m.create({
...s,
language: e,
plugins: u,
...l.length && {
translations: l
}
}), m.on("itemError", (...g) => {
console.error("Context item error:", ...g);
}), m;
})();
const h = await this.contextPromise;
this.isBeingDestroyed() || p.the.register(t, h);
}
/**
* 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, p.the.hasItem(t) && p.the.unregister(t);
}
}
}
function ot(i) {
return i.hasAttribute("cke-context");
}
function ct(i) {
let t = i;
for (; t; ) {
if (ot(t))
return t;
t = t.parentElement;
}
return null;
}
async function ut(i) {
const t = ct(i);
return t ? p.the.waitFor(t.id) : null;
}
const lt = k(st);
class d extends V {
static the = new d();
}
class dt extends E {
/**
* The name of the hook.
*/
editorPromise = 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: a } = this.attrs, n = this.el.querySelector(`#${t}_input`);
this.editorPromise = d.the.execute(e, (s) => {
const { ui: u, editing: o, model: c } = s;
if (c.document.getRoot(r))
return s;
s.addRoot(r, {
isUndoable: !1,
data: a
});
const l = this.el.querySelector("[data-cke-editable-content]"), h = u.view.createEditable(r, l);
return u.addEditable(h), o.view.forceRender(), n && ht(n, s, r), s;
});
}
/**
* Destroys the editable component. Unmounts root from the editor.
*/
async destroyed() {
const { rootName: t } = this.attrs;
this.el.style.display = "none";
const e = await this.editorPromise;
if (this.editorPromise = null, e && e.state !== "destroyed") {
const r = e.model.document.getRoot(t);
r && "detachEditable" in e && (e.detachEditable(r), e.detachRoot(t, !1));
}
}
}
const mt = k(dt);
function ht(i, t, e) {
const r = () => {
i.value = t.getData({ rootName: e });
};
t.model.document.on("change:data", O(100, r)), r();
}
async function pt({
editorId: i,
saveDebounceMs: t
}) {
const { Plugin: e } = await import("ckeditor5");
return class extends e {
/**
* The input element to synchronize with.
*/
input = null;
/**
* The form element reference for cleanup.
*/
form = null;
/**
* The name of the plugin.
*/
static get pluginName() {
return "SyncEditorWithInput";
}
/**
* Initializes the plugin.
*/
afterInit() {
const { editor: a } = this;
this.input = document.getElementById(`${i}_input`), this.input && (a.model.document.on("change:data", O(t, () => this.sync())), a.once("ready", this.sync), this.form = this.input.closest("form"), this.form?.addEventListener("submit", this.sync));
}
/**
* Synchronizes the editor's content with the input field.
*/
sync = () => {
const a = this.editor.getData();
this.input.value = a, this.input.dispatchEvent(new Event("input", { bubbles: !0 }));
};
/**
* Destroys the plugin.
*/
destroy() {
this.form && this.form.removeEventListener("submit", this.sync), this.input = null, this.form = null;
}
};
}
async function wt(i) {
const { Plugin: t } = await import("ckeditor5"), { editorId: e, saveDebounceMs: r, events: a, pushEvent: n, handleEvent: s } = i;
return class extends t {
/**
* The name of the plugin.
*/
static get pluginName() {
return "SyncEditorWithPhoenix";
}
/**
* Initializes the plugin.
*/
init() {
const { editor: o } = this;
a.change && this.setupTypingContentPush(), a.blur && this.setupEventPush("blur"), a.focus && this.setupEventPush("focus"), s("ckeditor5:set-data", ({ editorId: c, data: l }) => {
(Y(c) || c === e) && o.setData(l);
});
}
/**
* Setups the content push event for the editor.
*/
setupTypingContentPush() {
const { editor: o } = this, c = () => {
n(
"ckeditor5:change",
{
editorId: e,
data: R(this.editor)
}
);
};
o.model.document.on("change:data", O(r, c)), o.once("ready", c);
}
/**
* Setups the event push for the editor.
*/
setupEventPush(o) {
const { editor: c } = this, l = () => {
const { isFocused: h } = c.ui.focusTracker;
(h ? "focus" : "blur") === o && n(
`ckeditor5:${o}`,
{
editorId: e,
data: R(c)
}
);
};
c.ui.focusTracker.on("change:isFocused", l);
}
};
}
function R(i) {
return i.model.document.getRootNames().reduce((e, r) => (e[r] = i.getData({ rootName: r }), e), /* @__PURE__ */ Object.create({}));
}
class ft extends E {
/**
* 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), a = {
editorId: e("id"),
contextId: e("cke-context-id"),
preset: et(t),
editableHeight: N(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: N(e("cke-save-debounce-ms")) ?? 400,
language: {
ui: e("cke-language") || "en",
content: e("cke-content-language") || "en"
}
};
return Object.defineProperty(this, "attrs", {
value: a,
writable: !1,
configurable: !1,
enumerable: !0
}), a;
}
/**
* Mounts the editor component.
*/
async mounted() {
const { editorId: t } = this.attrs;
d.the.resetErrors(t);
try {
this.editorPromise = this.createEditor();
const e = await this.editorPromise;
this.isBeingDestroyed() || (d.the.register(t, e), e.once("destroy", () => {
d.the.hasItem(t) && d.the.unregister(t);
}));
} catch (e) {
this.editorPromise = null, d.the.error(t, e);
}
return 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;
if (!t)
return;
const e = Q(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: a, events: n, saveDebounceMs: s, language: u, watchdog: o } = this.attrs, { customTranslations: c, type: l, license: h, config: { plugins: w, ...P } } = t;
let m = await Z(l);
const g = await (r ? p.the.waitFor(r) : ut(this.el));
if (o && !g) {
const f = await it(m);
({ Constructor: m } = f), f.watchdog.on("restart", () => {
const H = f.watchdog.editor;
this.editorPromise = Promise.resolve(H), d.the.register(e, H);
});
}
const { loadedPlugins: v, hasPremium: K } = await q(w);
y(l) && v.push(
await pt({
editorId: e,
saveDebounceMs: s
})
), v.push(
await wt({
editorId: e,
saveDebounceMs: s,
events: n,
pushEvent: this.pushEvent.bind(this),
handleEvent: this.handleEvent.bind(this)
})
);
const $ = [
...await B(u, K),
U(c?.dictionary || {})
].filter((f) => !L(f)), C = gt(e, l), j = {
...x(P),
initialData: bt(e, l),
licenseKey: h.key,
plugins: v,
language: u,
...$.length && {
translations: $
}
}, M = await (async () => !g || !(C instanceof HTMLElement) ? m.create(C, j) : (await X({
context: g,
element: C,
creator: m,
config: j
})).editor)();
return y(l) && a && rt(M, a), M;
}
}
function gt(i, t) {
if (t === "decoupled") {
const { content: r } = _(i);
return r;
}
if (y(t))
return document.getElementById(`${i}_editor`);
const e = S(i);
return A(e, ({ content: r }) => r);
}
function bt(i, t) {
if (t === "decoupled") {
const { initialValue: r } = _(i);
if (r)
return r;
}
if (y(t))
return document.getElementById(i)?.getAttribute("cke-initial-value") || "";
const e = S(i);
return A(e, ({ initialValue: r }) => r);
}
function _(i) {
const t = S(i).main;
if (!t)
throw new Error(`No "main" editable found for editor with ID "${i}".`);
return t;
}
const yt = k(ft);
class Et extends E {
/**
* 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 = d.the.execute(t, (r) => {
const { ui: a } = r, n = kt(e), s = a.view[n];
if (!s) {
console.error(`Unknown UI part name: "${e}". Supported names are "toolbar" and "menubar".`);
return;
}
this.el.appendChild(s.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(i) {
switch (i) {
case "toolbar":
return "toolbar";
case "menubar":
return "menuBarView";
default:
return null;
}
}
const Pt = k(Et), xt = {
CKEditor5: yt,
CKEditable: mt,
CKUIPart: Pt,
CKContext: lt
};
export {
D as CustomEditorPluginsRegistry,
d as EditorsRegistry,
xt as Hooks,
Q as unwrapEditorContext,
at as unwrapEditorWatchdog
};
//# sourceMappingURL=index.mjs.map