@ckeditor/ckeditor5-core 43.3.1-alpha.0 → 44.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2,10 +2,10 @@
2
2
  * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
- import { ObservableMixin, insertToPriorityArray, EmitterMixin, CKEditorError, Config, Locale, Collection, KeystrokeHandler, setDataInElement } from '@ckeditor/ckeditor5-utils/dist/index.js';
5
+ import { ObservableMixin, insertToPriorityArray, EmitterMixin, CKEditorError, Config, Locale, Collection, KeystrokeHandler, env, uid, global, parseBase64EncodedObject, toArray, crc32, releaseDate, logError, setDataInElement } from '@ckeditor/ckeditor5-utils/dist/index.js';
6
+ import { get, set, isFunction } from 'lodash-es';
6
7
  import { Model, StylesProcessor, DataController, EditingController, Conversion } from '@ckeditor/ckeditor5-engine/dist/index.js';
7
8
  import { EditorWatchdog, ContextWatchdog } from '@ckeditor/ckeditor5-watchdog/dist/index.js';
8
- import { isFunction } from 'lodash-es';
9
9
 
10
10
  /**
11
11
  * The base class for CKEditor plugin classes.
@@ -652,7 +652,7 @@ import { isFunction } from 'lodash-es';
652
652
  * that you tried loading plugins by name. However, unlike CKEditor 4, CKEditor 5 does not implement a "plugin loader".
653
653
  * This means that CKEditor 5 does not know where to load the plugin modules from. Therefore, you need to
654
654
  * provide each plugin through a reference (as a constructor function). Check out the examples in the
655
- * {@glink getting-started/installation/quick-start Quick start} guide.
655
+ * {@glink getting-started/installation/cloud/quick-start Quick start} guide.
656
656
  *
657
657
  * @error plugincollection-plugin-not-found
658
658
  * @param plugin The name of the plugin which could not be loaded.
@@ -1657,6 +1657,119 @@ const DEFAULT_GROUP_ID = 'common';
1657
1657
  }
1658
1658
  }
1659
1659
 
1660
+ /**
1661
+ * This part of the code is not executed in open-source implementations using a GPL key.
1662
+ * It only runs when a specific license key is provided. If you are uncertain whether
1663
+ * this applies to your installation, please contact our support team.
1664
+ *
1665
+ * @internal
1666
+ */ function getEditorUsageData(editor) {
1667
+ return {
1668
+ sessionId: getSessionId(),
1669
+ pageSessionId: getPageSessionID(),
1670
+ hostname: window.location.hostname,
1671
+ version: globalThis.CKEDITOR_VERSION,
1672
+ type: getEditorType(editor),
1673
+ plugins: getPluginsUsageData(editor.plugins),
1674
+ distribution: getDistributionUsageData(),
1675
+ env: getEnvUsageData(),
1676
+ integration: Object.create(null),
1677
+ menuBar: {
1678
+ isVisible: !!editor.config.get('menuBar.isVisible')
1679
+ },
1680
+ language: {
1681
+ ui: editor.locale.uiLanguage,
1682
+ content: editor.locale.contentLanguage
1683
+ },
1684
+ toolbar: {
1685
+ main: getToolbarUsageData(editor.config.get('toolbar')),
1686
+ block: getToolbarUsageData(editor.config.get('blockToolbar')),
1687
+ balloon: getToolbarUsageData(editor.config.get('balloonToolbar'))
1688
+ }
1689
+ };
1690
+ }
1691
+ function getEditorType(editor) {
1692
+ return Object.getPrototypeOf(editor).constructor.editorName;
1693
+ }
1694
+ function getPluginsUsageData(collection) {
1695
+ return Array.from(collection).filter(([PluginConstructor])=>!!PluginConstructor.pluginName).map(([PluginConstructor])=>{
1696
+ const { pluginName, isContextPlugin, isOfficialPlugin, isPremiumPlugin } = PluginConstructor;
1697
+ return {
1698
+ isContext: !!isContextPlugin,
1699
+ isOfficial: !!isOfficialPlugin,
1700
+ isPremium: !!isPremiumPlugin,
1701
+ name: pluginName
1702
+ };
1703
+ });
1704
+ }
1705
+ function getToolbarUsageData(toolbarConfig) {
1706
+ if (!toolbarConfig) {
1707
+ return undefined;
1708
+ }
1709
+ const normalizedToolbar = Array.isArray(toolbarConfig) ? {
1710
+ items: toolbarConfig
1711
+ } : toolbarConfig;
1712
+ const flattenToolbarConfigNames = extractToolbarConfigItemsNames(normalizedToolbar.items || []);
1713
+ const isMultiline = flattenToolbarConfigNames.includes('-');
1714
+ return {
1715
+ isMultiline,
1716
+ shouldNotGroupWhenFull: !!normalizedToolbar.shouldNotGroupWhenFull,
1717
+ items: stripToolbarSeparatorItems(flattenToolbarConfigNames)
1718
+ };
1719
+ function stripToolbarSeparatorItems(items) {
1720
+ return items.filter((item)=>item !== '|' && item !== '-');
1721
+ }
1722
+ function extractToolbarConfigItemsNames(items) {
1723
+ return items.flatMap((item)=>{
1724
+ if (typeof item === 'string') {
1725
+ return [
1726
+ item
1727
+ ];
1728
+ }
1729
+ return extractToolbarConfigItemsNames(item.items);
1730
+ });
1731
+ }
1732
+ }
1733
+ function getDistributionUsageData() {
1734
+ return {
1735
+ channel: window[Symbol.for('cke distribution')] || 'sh'
1736
+ };
1737
+ }
1738
+ function getEnvUsageData() {
1739
+ let os = 'unknown';
1740
+ let browser = 'unknown';
1741
+ if (env.isMac) {
1742
+ os = 'mac';
1743
+ } else if (env.isWindows) {
1744
+ os = 'windows';
1745
+ } else if (env.isiOS) {
1746
+ os = 'ios';
1747
+ } else if (env.isAndroid) {
1748
+ os = 'android';
1749
+ }
1750
+ if (env.isGecko) {
1751
+ browser = 'gecko';
1752
+ } else if (env.isBlink) {
1753
+ browser = 'blink';
1754
+ } else if (env.isSafari) {
1755
+ browser = 'safari';
1756
+ }
1757
+ return {
1758
+ os,
1759
+ browser
1760
+ };
1761
+ }
1762
+ function getSessionId() {
1763
+ if (!localStorage.getItem('__ckeditor-session-id')) {
1764
+ localStorage.setItem('__ckeditor-session-id', uid());
1765
+ }
1766
+ return localStorage.getItem('__ckeditor-session-id');
1767
+ }
1768
+ function getPageSessionID() {
1769
+ global.window.CKEDITOR_PAGE_SESSION_ID = global.window.CKEDITOR_PAGE_SESSION_ID || uid();
1770
+ return global.window.CKEDITOR_PAGE_SESSION_ID;
1771
+ }
1772
+
1660
1773
  /**
1661
1774
  * The class representing a basic, generic editor.
1662
1775
  *
@@ -1675,6 +1788,11 @@ const DEFAULT_GROUP_ID = 'common';
1675
1788
  * the specific editor implements also the {@link ~Editor#ui} property
1676
1789
  * (as most editor implementations do).
1677
1790
  */ class Editor extends /* #__PURE__ */ ObservableMixin() {
1791
+ /**
1792
+ * A required name of the editor class. The name should reflect the constructor name.
1793
+ */ static get editorName() {
1794
+ return 'Editor';
1795
+ }
1678
1796
  /**
1679
1797
  * A namespace for the accessibility features of the editor.
1680
1798
  */ accessibility;
@@ -1873,6 +1991,7 @@ const DEFAULT_GROUP_ID = 'common';
1873
1991
  this.config = new Config(rest, defaultConfig);
1874
1992
  this.config.define('plugins', availablePlugins);
1875
1993
  this.config.define(this._context._getEditorConfig());
1994
+ checkLicenseKeyIsDefined(this.config);
1876
1995
  this.plugins = new PluginCollection(this, availablePlugins, this._context.plugins);
1877
1996
  this.locale = this._context.locale;
1878
1997
  this.t = this.locale.t;
@@ -1902,6 +2021,169 @@ const DEFAULT_GROUP_ID = 'common';
1902
2021
  this.keystrokes = new EditingKeystrokeHandler(this);
1903
2022
  this.keystrokes.listenTo(this.editing.view.document);
1904
2023
  this.accessibility = new Accessibility(this);
2024
+ verifyLicenseKey(this);
2025
+ // Checks if the license key is defined and throws an error if it is not.
2026
+ function checkLicenseKeyIsDefined(config) {
2027
+ let licenseKey = config.get('licenseKey');
2028
+ if (!licenseKey && window.CKEDITOR_GLOBAL_LICENSE_KEY) {
2029
+ licenseKey = window.CKEDITOR_GLOBAL_LICENSE_KEY;
2030
+ config.set('licenseKey', licenseKey);
2031
+ }
2032
+ if (!licenseKey) {
2033
+ /**
2034
+ * The `licenseKey` property is missing in the editor configuration.
2035
+ *
2036
+ * * If you are using the editor in a commercial setup, please provide your license key.
2037
+ * * If you still need to acquire a key, please [contact us](https://ckeditor.com/contact/) or
2038
+ * [create a free account with a 14 day premium features trial](https://portal.ckeditor.com/checkout?plan=free).
2039
+ * * If you are using the editor under a GPL license or another license from our Open Source Initiative,
2040
+ * use the 'GPL' license key instead.
2041
+ *
2042
+ * ```js
2043
+ * ClassicEditor.create( document.querySelector( '#editor' ), {
2044
+ * licenseKey: '<YOUR_LICENSE_KEY>', // Or 'GPL'.
2045
+ * // ... Other configuration options ...
2046
+ * } ) ;
2047
+ *
2048
+ * @error license-key-missing
2049
+ */ throw new CKEditorError('license-key-missing');
2050
+ }
2051
+ }
2052
+ function verifyLicenseKey(editor) {
2053
+ const licenseKey = editor.config.get('licenseKey');
2054
+ const distributionChannel = window[Symbol.for('cke distribution')] || 'sh';
2055
+ function blockEditor(reason) {
2056
+ editor.enableReadOnlyMode(Symbol('invalidLicense'));
2057
+ editor._showLicenseError(reason);
2058
+ }
2059
+ function getPayload(licenseKey) {
2060
+ const parts = licenseKey.split('.');
2061
+ if (parts.length != 3) {
2062
+ return null;
2063
+ }
2064
+ return parts[1];
2065
+ }
2066
+ function hasAllRequiredFields(licensePayload) {
2067
+ const requiredFields = [
2068
+ 'exp',
2069
+ 'jti',
2070
+ 'vc'
2071
+ ];
2072
+ return requiredFields.every((field)=>field in licensePayload);
2073
+ }
2074
+ function getCrcInputData(licensePayload) {
2075
+ const keysToCheck = Object.getOwnPropertyNames(licensePayload).sort();
2076
+ const filteredValues = keysToCheck.filter((key)=>key != 'vc' && licensePayload[key] != null).map((key)=>licensePayload[key]);
2077
+ return filteredValues;
2078
+ }
2079
+ function checkLicensedHosts(licensedHosts) {
2080
+ const { hostname } = new URL(window.location.href);
2081
+ if (licensedHosts.includes(hostname)) {
2082
+ return true;
2083
+ }
2084
+ const segments = hostname.split('.');
2085
+ return licensedHosts// Filter out hosts without wildcards.
2086
+ .filter((host)=>host.includes('*'))// Split the hosts into segments.
2087
+ .map((host)=>host.split('.'))// Filter out hosts that have more segments than the current hostname.
2088
+ .filter((host)=>host.length <= segments.length)// Pad the beginning of the licensed host if it's shorter than the current hostname.
2089
+ .map((host)=>Array(segments.length - host.length).fill(host[0] === '*' ? '*' : '').concat(host))// Check if some license host matches the hostname.
2090
+ .some((octets)=>segments.every((segment, index)=>octets[index] === segment || octets[index] === '*'));
2091
+ }
2092
+ if (licenseKey == 'GPL') {
2093
+ if (distributionChannel == 'cloud') {
2094
+ blockEditor('distributionChannel');
2095
+ }
2096
+ return;
2097
+ }
2098
+ const encodedPayload = getPayload(licenseKey);
2099
+ if (!encodedPayload) {
2100
+ blockEditor('invalid');
2101
+ return;
2102
+ }
2103
+ const licensePayload = parseBase64EncodedObject(encodedPayload);
2104
+ if (!licensePayload) {
2105
+ blockEditor('invalid');
2106
+ return;
2107
+ }
2108
+ if (!hasAllRequiredFields(licensePayload)) {
2109
+ blockEditor('invalid');
2110
+ return;
2111
+ }
2112
+ if (licensePayload.distributionChannel && !toArray(licensePayload.distributionChannel).includes(distributionChannel)) {
2113
+ blockEditor('distributionChannel');
2114
+ return;
2115
+ }
2116
+ if (crc32(getCrcInputData(licensePayload)) != licensePayload.vc.toLowerCase()) {
2117
+ blockEditor('invalid');
2118
+ return;
2119
+ }
2120
+ const expirationDate = new Date(licensePayload.exp * 1000);
2121
+ if (expirationDate < releaseDate) {
2122
+ blockEditor('expired');
2123
+ return;
2124
+ }
2125
+ const licensedHosts = licensePayload.licensedHosts;
2126
+ if (licensedHosts && licensedHosts.length > 0 && !checkLicensedHosts(licensedHosts)) {
2127
+ blockEditor('domainLimit');
2128
+ return;
2129
+ }
2130
+ if ([
2131
+ 'evaluation',
2132
+ 'trial'
2133
+ ].includes(licensePayload.licenseType) && licensePayload.exp * 1000 < Date.now()) {
2134
+ blockEditor('expired');
2135
+ return;
2136
+ }
2137
+ if ([
2138
+ 'evaluation',
2139
+ 'trial',
2140
+ 'development'
2141
+ ].includes(licensePayload.licenseType)) {
2142
+ const licenseType = licensePayload.licenseType;
2143
+ console.info(`You are using the ${licenseType} version of CKEditor 5 with limited usage. ` + 'Make sure you will not use it in the production environment.');
2144
+ const timerId = setTimeout(()=>{
2145
+ blockEditor(`${licenseType}Limit`);
2146
+ }, 600000);
2147
+ editor.on('destroy', ()=>{
2148
+ clearTimeout(timerId);
2149
+ });
2150
+ }
2151
+ if (licensePayload.usageEndpoint) {
2152
+ editor.once('ready', ()=>{
2153
+ const request = {
2154
+ requestId: uid(),
2155
+ requestTime: Math.round(Date.now() / 1000),
2156
+ license: licenseKey,
2157
+ editor: collectUsageData(editor)
2158
+ };
2159
+ /**
2160
+ * This part of the code is not executed in open-source implementations using a GPL key.
2161
+ * It only runs when a specific license key is provided. If you are uncertain whether
2162
+ * this applies to your installation, please contact our support team.
2163
+ */ editor._sendUsageRequest(licensePayload.usageEndpoint, request).then((response)=>{
2164
+ const { status, message } = response;
2165
+ if (message) {
2166
+ console.warn(message);
2167
+ }
2168
+ if (status != 'ok') {
2169
+ blockEditor('usageLimit');
2170
+ }
2171
+ }, ()=>{
2172
+ /**
2173
+ * Your license key cannot be validated due to a network issue.
2174
+ * Please ensure that your setup does not block requests to the validation endpoint.
2175
+ *
2176
+ * @error license-key-validation-endpoint-not-reachable
2177
+ * @param {String} url The URL that was attempted to be reached for validation.
2178
+ */ logError('license-key-validation-endpoint-not-reachable', {
2179
+ url: licensePayload.usageEndpoint
2180
+ });
2181
+ });
2182
+ }, {
2183
+ priority: 'high'
2184
+ });
2185
+ }
2186
+ }
1905
2187
  }
1906
2188
  /**
1907
2189
  * Defines whether the editor is in the read-only mode.
@@ -2184,6 +2466,147 @@ const DEFAULT_GROUP_ID = 'common';
2184
2466
  *
2185
2467
  * Exposed as static editor field for easier access in editor builds.
2186
2468
  */ static ContextWatchdog = ContextWatchdog;
2469
+ _showLicenseError(reason, pluginName) {
2470
+ setTimeout(()=>{
2471
+ if (reason == 'invalid') {
2472
+ /**
2473
+ * The license key provided is invalid. Please ensure that it is copied correctly
2474
+ * from the [Customer Portal](http://portal.ckeditor.com). If the issue persists,
2475
+ * please [contact our customer support](https://ckeditor.com/contact/).
2476
+ *
2477
+ * @error invalid-license-key
2478
+ */ throw new CKEditorError('invalid-license-key');
2479
+ }
2480
+ if (reason == 'expired') {
2481
+ /**
2482
+ * Your license key has expired. Please renew your license on the
2483
+ * [Customer Portal](https://portal.ckeditor.com).
2484
+ *
2485
+ * @error license-key-expired
2486
+ */ throw new CKEditorError('license-key-expired');
2487
+ }
2488
+ if (reason == 'domainLimit') {
2489
+ /**
2490
+ * The provided license does not allow the editor to run on this domain.
2491
+ * Some license keys are restricted to local test environments only.
2492
+ * For more details, please refer to the
2493
+ * {@glink getting-started/licensing/license-key-and-activation#license-key-types license key type documentation}.
2494
+ *
2495
+ * @error license-key-domain-limit
2496
+ */ throw new CKEditorError('license-key-domain-limit');
2497
+ }
2498
+ if (reason == 'featureNotAllowed') {
2499
+ /**
2500
+ * The plugin you are trying to use is not permitted under your current license.
2501
+ * Please check the available features on the
2502
+ * [Customer Portal](https://portal.ckeditor.com) or
2503
+ * [contact support](https://ckeditor.com/contact/) for more information.
2504
+ *
2505
+ * @error license-key-plugin-not-allowed
2506
+ * @param {String} pluginName The plugin you tried to load.
2507
+ */ throw new CKEditorError('license-key-plugin-not-allowed', null, {
2508
+ pluginName
2509
+ });
2510
+ }
2511
+ if (reason == 'evaluationLimit') {
2512
+ /**
2513
+ * You have exceeded the editor operation limit available for your evaluation license key.
2514
+ * Please restart the editor to continue using it.
2515
+ * {@glink getting-started/licensing/license-key-and-activation#license-key-types Read more about license key types}.
2516
+ *
2517
+ * @error license-key-evaluation-limit
2518
+ */ throw new CKEditorError('license-key-evaluation-limit');
2519
+ }
2520
+ if (reason == 'trialLimit') {
2521
+ /**
2522
+ * You have exceeded the editor operation limit for your trial license key.
2523
+ * Please restart the editor to continue using it.
2524
+ * {@glink getting-started/licensing/license-key-and-activation#license-key-types Read more about license key types}.
2525
+ *
2526
+ * @error license-key-trial-limit
2527
+ */ throw new CKEditorError('license-key-trial-limit');
2528
+ }
2529
+ if (reason == 'developmentLimit') {
2530
+ /**
2531
+ * You have exceeded the operation limit for your development license key within the editor.
2532
+ * Please restart the editor to continue using it.
2533
+ * {@glink getting-started/licensing/license-key-and-activation#license-key-types Read more about license key types}.
2534
+ *
2535
+ * @error license-key-development-limit
2536
+ */ throw new CKEditorError('license-key-development-limit');
2537
+ }
2538
+ if (reason == 'usageLimit') {
2539
+ /**
2540
+ * You have reached the usage limit of your license key. This can occur in the following situations:
2541
+ *
2542
+ * * You are on a free subscription without a connected payment method and have exceeded the allowed usage threshold.
2543
+ * * Your account has overdue invoices and the grace period has ended.
2544
+ *
2545
+ * To extend the limit and restore access, please update the required details in the
2546
+ * [Customer Portal](https://portal.ckeditor.com) or
2547
+ * [contact our customer support](https://ckeditor.com/contact).
2548
+ *
2549
+ * @error license-key-usage-limit
2550
+ */ throw new CKEditorError('license-key-usage-limit');
2551
+ }
2552
+ if (reason == 'distributionChannel') {
2553
+ /**
2554
+ * Your license does not allow the current distribution channel.
2555
+ *
2556
+ * * With a 'GPL' license key, you may use the editor installed via npm or a ZIP package (self-hosted).
2557
+ * * With the CKEditor Cloud plans, you may use the editor via our CDN.
2558
+ * * With the CKEditor Custom plans, depending on your plan details, you can use the editor via npm
2559
+ * or a ZIP package (self-hosted) or Cloud (CDN)
2560
+ *
2561
+ * {@glink getting-started/licensing/usage-based-billing#key-terms Read more about distributions in the documentation}.
2562
+ * Please verify your installation or [contact support](https://ckeditor.com/contact/) for assistance.
2563
+ *
2564
+ * @error license-key-invalid-distribution-channel
2565
+ */ throw new CKEditorError('license-key-invalid-distribution-channel');
2566
+ }
2567
+ }, 0);
2568
+ this._showLicenseError = ()=>{};
2569
+ }
2570
+ /**
2571
+ * This part of the code is _not_ executed in installations under the GPL license (with `config.licenseKey = 'GPL'`).
2572
+ *
2573
+ * It is only executed when a specific license key is provided. If you are uncertain whether
2574
+ * this applies to your installation, please contact our support team.
2575
+ */ async _sendUsageRequest(endpoint, request) {
2576
+ const headers = new Headers({
2577
+ 'Content-Type': 'application/json'
2578
+ });
2579
+ const response = await fetch(new URL(endpoint), {
2580
+ method: 'POST',
2581
+ headers,
2582
+ body: JSON.stringify(request)
2583
+ });
2584
+ if (!response.ok) {
2585
+ // TODO: refine message.
2586
+ throw new Error(`HTTP Response: ${response.status}`);
2587
+ }
2588
+ return response.json();
2589
+ }
2590
+ }
2591
+ function collectUsageData(editor) {
2592
+ const collectedData = getEditorUsageData(editor);
2593
+ function setUsageData(path, value) {
2594
+ if (get(collectedData, path) !== undefined) {
2595
+ /**
2596
+ * The error thrown when trying to set the usage data path that was already set.
2597
+ * Make sure that you are not setting the same path multiple times.
2598
+ *
2599
+ * @error editor-usage-data-path-already-set
2600
+ */ throw new CKEditorError('editor-usage-data-path-already-set', {
2601
+ path
2602
+ });
2603
+ }
2604
+ set(collectedData, path, value);
2605
+ }
2606
+ editor.fire('collectUsageData', {
2607
+ setUsageData
2608
+ });
2609
+ return collectedData;
2187
2610
  }
2188
2611
  /**
2189
2612
  * This error is thrown when trying to pass a `<textarea>` element to a `create()` function of an editor class.
@@ -2560,6 +2983,12 @@ var outdent = "<svg viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><
2560
2983
 
2561
2984
  var table = "<svg viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M3 5.5v3h4v-3H3Zm0 4v3h4v-3H3Zm0 4v3h4v-3H3Zm5 3h4v-3H8v3Zm5 0h4v-3h-4v3Zm4-4v-3h-4v3h4Zm0-4v-3h-4v3h4Zm1.5 8A1.5 1.5 0 0 1 17 18H3a1.5 1.5 0 0 1-1.5-1.5V3c.222-.863 1.068-1.5 2-1.5h13c.932 0 1.778.637 2 1.5v13.5Zm-6.5-4v-3H8v3h4Zm0-4v-3H8v3h4Z\"/></svg>";
2562
2985
 
2986
+ var remove = "<svg viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M5.2 7h9.2c.6 0 1 .4 1 1v9.9c0 .5-.4 1-1 1H5.2a1 1 0 0 1-1-1V8c0-.6.4-1 1-1Zm1 1.5c-.3 0-.5.2-.5.5v8c0 .3.2.5.5.5h.5c.2 0 .5-.2.5-.5V9c0-.3-.3-.5-.5-.5h-.5Zm3.2 0c-.2 0-.5.2-.5.5v8c0 .3.3.5.5.5h.5c.3 0 .5-.2.5-.5V9c0-.3-.2-.5-.5-.5h-.5Zm3.5 0c-.2 0-.5.2-.5.5v8c0 .3.3.5.5.5h.5c.3 0 .5-.2.5-.5V9c0-.3-.2-.5-.5-.5h-.5Zm-1.4-7.1H8.3L6.5 3.6H3.8c-.5 0-.7.3-.7.8s.2.7.7.7h12c.6 0 .9-.2.9-.7 0-.5-.3-.8-1-.8h-2.4l-1.8-2.2Z\"/></svg>";
2987
+
2988
+ var bookmark = "<svg viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2000/svg\"><path clip-rule=\"evenodd\" d=\"M5.68 3.417a.238.238 0 0 0-.24.236v12.66l3.793-3.102a1.215 1.215 0 0 1 1.534 0l3.793 3.103V3.654a.238.238 0 0 0-.24-.237H5.68ZM4 3.653C4 2.74 4.752 2 5.68 2h8.64c.928 0 1.68.74 1.68 1.653v13.164c0 1-1.185 1.547-1.967.908L10 14.426l-4.033 3.299c-.782.64-1.967.092-1.967-.908V3.653Z\"/></svg>";
2989
+
2990
+ var bookmarkInline = "<svg viewBox=\"0 0 14 16\" xmlns=\"http://www.w3.org/2000/svg\"><path class=\"ck-icon__fill\" d=\"M2 14.436V2a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v12.436a.5.5 0 0 1-.819.385l-3.862-3.2a.5.5 0 0 0-.638 0l-3.862 3.2A.5.5 0 0 1 2 14.436Z\"/></svg>";
2991
+
2563
2992
  const icons = {
2564
2993
  bold,
2565
2994
  cancel,
@@ -2623,7 +3052,10 @@ const icons = {
2623
3052
  html,
2624
3053
  indent,
2625
3054
  outdent,
2626
- table
3055
+ table,
3056
+ remove,
3057
+ bookmark,
3058
+ bookmarkInline
2627
3059
  };
2628
3060
 
2629
3061
  export { Command, Context, ContextPlugin, DataApiMixin, Editor, ElementApiMixin, MultiCommand, PendingActions, Plugin, attachToForm, icons, secureSourceElement };