@ckeditor/ckeditor5-integrations-common
Version:
This package implements common utility modules for integration projects.
880 lines (838 loc) • 29.6 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.CKEDITOR_INTEGRATIONS_COMMON = {}));
})(this, (function (exports) { 'use strict';
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function createDefer() {
const deferred = {
resolve: null,
promise: null
};
deferred.promise = new Promise((resolve) => {
deferred.resolve = resolve;
});
return deferred;
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function waitFor(callback, {
timeOutAfter = 500,
retryAfter = 100
} = {}) {
return new Promise((resolve, reject) => {
const startTime = Date.now();
let lastError = null;
const timeoutTimerId = setTimeout(() => {
reject(lastError ?? new Error("Timeout"));
}, timeOutAfter);
const tick = async () => {
try {
const result = await callback();
clearTimeout(timeoutTimerId);
resolve(result);
} catch (err) {
lastError = err;
if (Date.now() - startTime > timeOutAfter) {
reject(err);
} else {
setTimeout(tick, retryAfter);
}
}
};
tick();
});
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
const INJECTED_SCRIPTS = /* @__PURE__ */ new Map();
function injectScript(src, { attributes } = {}) {
if (INJECTED_SCRIPTS.has(src)) {
return INJECTED_SCRIPTS.get(src);
}
const maybePrevScript = document.querySelector(`script[src="${src}"]`);
if (maybePrevScript) {
console.warn(`Script with "${src}" src is already present in DOM!`);
maybePrevScript.remove();
}
const promise = new Promise((resolve, reject) => {
const script = document.createElement("script");
script.onerror = reject;
script.onload = () => {
resolve();
};
for (const [key, value] of Object.entries(attributes || {})) {
script.setAttribute(key, value);
}
script.setAttribute("data-injected-by", "ckeditor-integration");
script.type = "text/javascript";
script.async = true;
script.src = src;
document.head.appendChild(script);
const observer = new MutationObserver((mutations) => {
const removedNodes = mutations.flatMap((mutation) => Array.from(mutation.removedNodes));
if (removedNodes.includes(script)) {
INJECTED_SCRIPTS.delete(src);
observer.disconnect();
}
});
observer.observe(document.head, {
childList: true,
subtree: true
});
});
INJECTED_SCRIPTS.set(src, promise);
return promise;
}
async function injectScriptsInParallel(sources, props) {
await Promise.all(
sources.map((src) => injectScript(src, props))
);
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
const INJECTED_STYLESHEETS = /* @__PURE__ */ new Map();
function injectStylesheet({
href,
placementInHead = "start",
attributes = {}
}) {
if (INJECTED_STYLESHEETS.has(href)) {
return INJECTED_STYLESHEETS.get(href);
}
const maybePrevStylesheet = document.querySelector(`link[href="${href}"][rel="stylesheet"]`);
if (maybePrevStylesheet) {
console.warn(`Stylesheet with "${href}" href is already present in DOM!`);
maybePrevStylesheet.remove();
}
const appendLinkTagToHead = (link) => {
const previouslyInjectedLinks = Array.from(
document.head.querySelectorAll('link[data-injected-by="ckeditor-integration"]')
);
switch (placementInHead) {
case "start":
if (previouslyInjectedLinks.length) {
previouslyInjectedLinks.slice(-1)[0].after(link);
} else {
document.head.insertBefore(link, document.head.firstChild);
}
break;
case "end":
document.head.appendChild(link);
break;
}
};
const promise = new Promise((resolve, reject) => {
const link = document.createElement("link");
for (const [key, value] of Object.entries(attributes || {})) {
link.setAttribute(key, value);
}
link.setAttribute("data-injected-by", "ckeditor-integration");
link.rel = "stylesheet";
link.href = href;
link.onerror = reject;
link.onload = () => {
resolve();
};
appendLinkTagToHead(link);
const observer = new MutationObserver((mutations) => {
const removedNodes = mutations.flatMap((mutation) => Array.from(mutation.removedNodes));
if (removedNodes.includes(link)) {
INJECTED_STYLESHEETS.delete(href);
observer.disconnect();
}
});
observer.observe(document.head, {
childList: true,
subtree: true
});
});
INJECTED_STYLESHEETS.set(href, promise);
return promise;
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function isSSR() {
return typeof window === "undefined";
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function once(fn) {
let lastResult = null;
return (...args) => {
if (!lastResult) {
lastResult = {
current: fn(...args)
};
}
return lastResult.current;
};
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function overwriteArray(source, destination) {
destination.length = 0;
destination.push(...source);
return destination;
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function overwriteObject(source, destination) {
for (const prop of Object.getOwnPropertyNames(destination)) {
delete destination[prop];
}
for (const [key, value] of Object.entries(source)) {
if (value !== destination && key !== "prototype" && key !== "__proto__") {
destination[key] = value;
}
}
return destination;
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function preloadResource(url, { attributes } = {}) {
if (document.head.querySelector(`link[href="${url}"][rel="preload"]`)) {
return;
}
const link = document.createElement("link");
for (const [key, value] of Object.entries(attributes || {})) {
link.setAttribute(key, value);
}
link.setAttribute("data-injected-by", "ckeditor-integration");
link.rel = "preload";
link.as = detectTypeOfResource(url);
link.href = url;
document.head.insertBefore(link, document.head.firstChild);
}
function detectTypeOfResource(url) {
switch (true) {
case /\.css$/.test(url):
return "style";
case /\.js$/.test(url):
return "script";
default:
return "fetch";
}
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function shallowCompareArrays(a, b) {
if (a === b) {
return true;
}
if (!a || !b) {
return false;
}
for (let i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
const HEX_NUMBERS = new Array(256).fill("").map((_, index) => ("0" + index.toString(16)).slice(-2));
function uid() {
const [r1, r2, r3, r4] = crypto.getRandomValues(new Uint32Array(4));
return "e" + HEX_NUMBERS[r1 >> 0 & 255] + HEX_NUMBERS[r1 >> 8 & 255] + HEX_NUMBERS[r1 >> 16 & 255] + HEX_NUMBERS[r1 >> 24 & 255] + HEX_NUMBERS[r2 >> 0 & 255] + HEX_NUMBERS[r2 >> 8 & 255] + HEX_NUMBERS[r2 >> 16 & 255] + HEX_NUMBERS[r2 >> 24 & 255] + HEX_NUMBERS[r3 >> 0 & 255] + HEX_NUMBERS[r3 >> 8 & 255] + HEX_NUMBERS[r3 >> 16 & 255] + HEX_NUMBERS[r3 >> 24 & 255] + HEX_NUMBERS[r4 >> 0 & 255] + HEX_NUMBERS[r4 >> 8 & 255] + HEX_NUMBERS[r4 >> 16 & 255] + HEX_NUMBERS[r4 >> 24 & 255];
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function uniq(source) {
return Array.from(new Set(source));
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
async function waitForWindowEntry(entryNames, config) {
const tryPickBundle = () => entryNames.map((name) => window[name]).filter(Boolean)[0];
return waitFor(
() => {
const result = tryPickBundle();
if (!result) {
throw new Error(`Window entry "${entryNames.join(",")}" not found.`);
}
return result;
},
config
);
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function filterObjectValues(obj, filter) {
const filteredEntries = Object.entries(obj).filter(([key, value]) => filter(value, key));
return Object.fromEntries(filteredEntries);
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function filterBlankObjectValues(obj) {
return filterObjectValues(
obj,
(value) => value !== null && value !== void 0
);
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function mapObjectValues(obj, mapper) {
const mappedEntries = Object.entries(obj).map(([key, value]) => [key, mapper(value, key)]);
return Object.fromEntries(mappedEntries);
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function without(itemsToRemove, items) {
return items.filter((item) => !itemsToRemove.includes(item));
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function appendExtraPluginsToEditorConfig(config, plugins) {
const extraPlugins = config.extraPlugins || [];
return {
...config,
extraPlugins: [
...extraPlugins,
...plugins.filter((item) => !extraPlugins.includes(item))
]
};
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function isSemanticVersion(version) {
return !!version && /^\d+\.\d+\.\d+/.test(version);
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function isCKCdnTestingVersion(version) {
if (!version) {
return false;
}
return ["nightly", "alpha", "internal", "nightly-", "staging"].some((testVersion) => version.includes(testVersion));
}
function isCKCdnVersion(version) {
return isSemanticVersion(version) || isCKCdnTestingVersion(version);
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function destructureSemanticVersion(version) {
if (!isSemanticVersion(version)) {
throw new Error(`Invalid semantic version: ${version || "<blank>"}.`);
}
const [major, minor, patch] = version.split(".");
return {
major: Number.parseInt(major, 10),
minor: Number.parseInt(minor, 10),
patch: Number.parseInt(patch, 10)
};
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function getLicenseVersionFromEditorVersion(version) {
if (isCKCdnTestingVersion(version)) {
return 3;
}
const { major } = destructureSemanticVersion(version);
switch (true) {
case major >= 44:
return 3;
case major >= 38:
return 2;
default:
return 1;
}
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function getCKBaseBundleInstallationInfo() {
const { CKEDITOR_VERSION, CKEDITOR } = window;
if (!isCKCdnVersion(CKEDITOR_VERSION)) {
return null;
}
return {
source: CKEDITOR ? "cdn" : "npm",
version: CKEDITOR_VERSION
};
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function getSupportedLicenseVersionInstallationInfo() {
const installationInfo = getCKBaseBundleInstallationInfo();
if (!installationInfo) {
return null;
}
return getLicenseVersionFromEditorVersion(installationInfo.version);
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function isCKEditorFreeLicense(licenseKey, licenseVersion) {
licenseVersion ||= getSupportedLicenseVersionInstallationInfo() || void 0;
switch (licenseVersion) {
case 1:
case 2:
return licenseKey === void 0;
case 3:
return licenseKey === "GPL";
default: {
return false;
}
}
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function createIntegrationUsageDataPlugin(integrationName, usageData) {
return function IntegrationUsageDataPlugin(editor) {
if (isCKEditorFreeLicense(editor.config.get("licenseKey"))) {
return;
}
editor.on("collectUsageData", (source, { setUsageData }) => {
setUsageData(`integration.${integrationName}`, usageData);
});
};
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
const CK_CDN_URL = "https://cdn.ckeditor.com";
function createCKCdnUrl(bundle, file, version) {
return `${CK_CDN_URL}/${bundle}/${version}/${file}`;
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
const CKBOX_CDN_URL = "https://cdn.ckbox.io";
function createCKBoxCdnUrl(bundle, file, version) {
return `${CKBOX_CDN_URL}/${bundle}/${version}/${file}`;
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
const CK_DOCS_URL = "https://ckeditor.com/docs/ckeditor5";
function createCKDocsUrl(path, version = "latest") {
return `${CK_DOCS_URL}/${version}/${path}`;
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function createCKCdnBaseBundlePack({
version,
translations,
createCustomCdnUrl = createCKCdnUrl
}) {
const urls = {
scripts: [
// Load the main script of the base features.
createCustomCdnUrl("ckeditor5", "ckeditor5.umd.js", version),
// Load all JavaScript files from the base features.
// EN bundle is prebuilt into the main script, so we don't need to load it separately.
...without(["en"], translations || []).map(
(translation) => createCustomCdnUrl("ckeditor5", `translations/${translation}.umd.js`, version)
)
],
stylesheets: [
createCustomCdnUrl("ckeditor5", "ckeditor5.css", version)
]
};
return {
// Preload resources specified in the pack, before loading the main script.
preload: [
...urls.stylesheets,
...urls.scripts
],
scripts: [
// It's safe to load translations and the main script in parallel.
async (attributes) => injectScriptsInParallel(urls.scripts, attributes)
],
// Load all stylesheets of the base features.
stylesheets: urls.stylesheets,
// Pick the exported global variables from the window object.
checkPluginLoaded: async () => waitForWindowEntry(["CKEDITOR"]),
// Check if the CKEditor base bundle is already loaded and throw an error if it is.
beforeInject: () => {
const installationInfo = getCKBaseBundleInstallationInfo();
switch (installationInfo?.source) {
case "npm":
throw new Error(
"CKEditor 5 is already loaded from npm. Check the migration guide for more details: " + createCKDocsUrl("updating/migration-to-cdn/vanilla-js.html")
);
case "cdn":
if (installationInfo.version !== version) {
throw new Error(
`CKEditor 5 is already loaded from CDN in version ${installationInfo.version}. Remove the old <script> and <link> tags loading CKEditor 5 to allow loading the ${version} version.`
);
}
break;
}
}
};
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function createCKCdnPremiumBundlePack({
version,
translations,
createCustomCdnUrl = createCKCdnUrl
}) {
const urls = {
scripts: [
// Load the main script of the premium features.
createCustomCdnUrl("ckeditor5-premium-features", "ckeditor5-premium-features.umd.js", version),
// Load all JavaScript files from the premium features.
// EN bundle is prebuilt into the main script, so we don't need to load it separately.
...without(["en"], translations || []).map(
(translation) => createCustomCdnUrl("ckeditor5-premium-features", `translations/${translation}.umd.js`, version)
)
],
stylesheets: [
createCustomCdnUrl("ckeditor5-premium-features", "ckeditor5-premium-features.css", version)
]
};
return {
// Preload resources specified in the pack, before loading the main script.
preload: [
...urls.stylesheets,
...urls.scripts
],
scripts: [
// It's safe to load translations and the main script in parallel.
async (attributes) => injectScriptsInParallel(urls.scripts, attributes)
],
// Load all stylesheets of the premium features.
stylesheets: urls.stylesheets,
// Pick the exported global variables from the window object.
checkPluginLoaded: async () => waitForWindowEntry(["CKEDITOR_PREMIUM_FEATURES"])
};
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
async function loadCKCdnResourcesPack(pack) {
let {
htmlAttributes = {},
scripts = [],
stylesheets = [],
preload,
beforeInject,
checkPluginLoaded
} = normalizeCKCdnResourcesPack(pack);
beforeInject?.();
if (!preload) {
preload = uniq([
...stylesheets.filter((item) => typeof item === "string"),
...scripts.filter((item) => typeof item === "string")
]);
}
for (const url of preload) {
preloadResource(url, {
attributes: htmlAttributes
});
}
await Promise.all(
uniq(stylesheets).map((href) => injectStylesheet({
href,
attributes: htmlAttributes,
placementInHead: "start"
}))
);
for (const script of uniq(scripts)) {
const injectorProps = {
attributes: htmlAttributes
};
if (typeof script === "string") {
await injectScript(script, injectorProps);
} else {
await script(injectorProps);
}
}
return checkPluginLoaded?.();
}
function normalizeCKCdnResourcesPack(pack) {
if (Array.isArray(pack)) {
return {
scripts: pack.filter(
(item) => typeof item === "function" || item.endsWith(".js")
),
stylesheets: pack.filter(
(item) => item.endsWith(".css")
)
};
}
if (typeof pack === "function") {
return {
checkPluginLoaded: pack
};
}
return pack;
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function combineCKCdnBundlesPacks(packs) {
const normalizedPacks = mapObjectValues(
filterBlankObjectValues(packs),
normalizeCKCdnResourcesPack
);
const mergedPacks = Object.values(normalizedPacks).reduce(
(acc, pack) => {
acc.scripts.push(...pack.scripts ?? []);
acc.stylesheets.push(...pack.stylesheets ?? []);
acc.preload.push(...pack.preload ?? []);
return acc;
},
{
preload: [],
scripts: [],
stylesheets: []
}
);
const checkPluginLoaded = async () => {
const exportedGlobalVariables = /* @__PURE__ */ Object.create(null);
for (const [name, pack] of Object.entries(normalizedPacks)) {
exportedGlobalVariables[name] = await pack?.checkPluginLoaded?.();
}
return exportedGlobalVariables;
};
const beforeInject = () => {
for (const pack of Object.values(normalizedPacks)) {
pack.beforeInject?.();
}
};
return {
...mergedPacks,
beforeInject,
checkPluginLoaded
};
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function getCKBoxInstallationInfo() {
const version = window.CKBox?.version;
if (!isSemanticVersion(version)) {
return null;
}
return {
source: "cdn",
version
};
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function createCKBoxBundlePack({
version,
theme = "lark",
translations,
createCustomCdnUrl = createCKBoxCdnUrl
}) {
return {
// Load the main script of the base features.
scripts: [
createCustomCdnUrl("ckbox", "ckbox.js", version),
// EN bundle is prebuilt into the main script, so we don't need to load it separately.
...without(["en"], translations || []).map(
(translation) => createCustomCdnUrl("ckbox", `translations/${translation}.js`, version)
)
],
// Load optional theme, if provided. It's not required but recommended because it improves the look and feel.
...theme && {
stylesheets: [
createCustomCdnUrl("ckbox", `styles/themes/${theme}.css`, version)
]
},
// Pick the exported global variables from the window object.
checkPluginLoaded: async () => waitForWindowEntry(["CKBox"]),
// Check if the CKBox bundle is already loaded and throw an error if it is.
beforeInject: () => {
const installationInfo = getCKBoxInstallationInfo();
if (installationInfo && installationInfo.version !== version) {
throw new Error(
`CKBox is already loaded from CDN in version ${installationInfo.version}. Remove the old <script> and <link> tags loading CKBox to allow loading the ${version} version.`
);
}
}
};
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function isCKCdnSupportedByEditorVersion(version) {
if (isCKCdnTestingVersion(version)) {
return true;
}
const { major } = destructureSemanticVersion(version);
const licenseVersion = getLicenseVersionFromEditorVersion(version);
switch (licenseVersion) {
case 3:
return true;
default:
return major === 43;
}
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function combineCdnPluginsPacks(pluginsPacks) {
const normalizedPluginsPacks = mapObjectValues(pluginsPacks, (pluginPack, pluginName) => {
if (!pluginPack) {
return void 0;
}
const normalizedPluginPack = normalizeCKCdnResourcesPack(pluginPack);
return {
// Provide default window accessor object if the plugin pack does not define it.
checkPluginLoaded: async () => waitForWindowEntry([pluginName]),
// Transform the plugin pack to a normalized advanced pack.
...normalizedPluginPack
};
});
return combineCKCdnBundlesPacks(
normalizedPluginsPacks
);
}
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
function loadCKEditorCloud(config) {
const {
version,
translations,
plugins,
premium,
ckbox,
createCustomCdnUrl,
injectedHtmlElementsAttributes = {
crossorigin: "anonymous"
}
} = config;
validateCKEditorVersion(version);
const pack = combineCKCdnBundlesPacks({
CKEditor: createCKCdnBaseBundlePack({
version,
translations,
createCustomCdnUrl
}),
...premium && {
CKEditorPremiumFeatures: createCKCdnPremiumBundlePack({
version,
translations,
createCustomCdnUrl
})
},
...ckbox && {
CKBox: createCKBoxBundlePack(ckbox)
},
loadedPlugins: combineCdnPluginsPacks(plugins ?? {})
});
return loadCKCdnResourcesPack(
{
...pack,
htmlAttributes: injectedHtmlElementsAttributes
}
);
}
function validateCKEditorVersion(version) {
if (isCKCdnTestingVersion(version)) {
console.warn(
"You are using a testing version of CKEditor 5. Please remember that it is not suitable for production environments."
);
}
if (!isCKCdnSupportedByEditorVersion(version)) {
throw new Error(
`The CKEditor 5 CDN can't be used with the given editor version: ${version}. Please make sure you are using at least the CKEditor 5 version 44.`
);
}
}
exports.CKBOX_CDN_URL = CKBOX_CDN_URL;
exports.CK_CDN_URL = CK_CDN_URL;
exports.INJECTED_SCRIPTS = INJECTED_SCRIPTS;
exports.INJECTED_STYLESHEETS = INJECTED_STYLESHEETS;
exports.appendExtraPluginsToEditorConfig = appendExtraPluginsToEditorConfig;
exports.createCKBoxCdnUrl = createCKBoxCdnUrl;
exports.createCKCdnUrl = createCKCdnUrl;
exports.createDefer = createDefer;
exports.createIntegrationUsageDataPlugin = createIntegrationUsageDataPlugin;
exports.filterBlankObjectValues = filterBlankObjectValues;
exports.filterObjectValues = filterObjectValues;
exports.injectScript = injectScript;
exports.injectScriptsInParallel = injectScriptsInParallel;
exports.injectStylesheet = injectStylesheet;
exports.isCKEditorFreeLicense = isCKEditorFreeLicense;
exports.isSSR = isSSR;
exports.loadCKEditorCloud = loadCKEditorCloud;
exports.mapObjectValues = mapObjectValues;
exports.once = once;
exports.overwriteArray = overwriteArray;
exports.overwriteObject = overwriteObject;
exports.preloadResource = preloadResource;
exports.shallowCompareArrays = shallowCompareArrays;
exports.uid = uid;
exports.uniq = uniq;
exports.waitFor = waitFor;
exports.waitForWindowEntry = waitForWindowEntry;
exports.without = without;
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}));
//# sourceMappingURL=index.umd.cjs.map