@ckeditor/ckeditor5-ckbox 44.3.0-alpha.7 → 45.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.
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
+ */
5
+
6
+ import type { Translations } from '@ckeditor/ckeditor5-utils';
7
+ declare const translations: Translations;
8
+ export default translations;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
+ */
5
+ export default {"be":{"dictionary":{"Open file manager":"Адкрыць менеджэр файлаў","Cannot determine a category for the uploaded file.":"Немагчыма вызначыць катэгорыю для запампаванага файла.","Cannot access default workspace.":"Немагчыма атрымаць доступ да прадвызначанай працоўнай прасторы.","You have no image editing permissions.":"У вас няма дозволу на рэдагаванне відарыса.","Edit image":"Рэдагаваць відарыс","Processing the edited image.":"Апрацоўка адрэдагаванага відарыса.","Server failed to process the image.":"Сервер не здольны апрацаваць відарыс.","Failed to determine category of edited image.":"Не здольны вызначыць катэгорыю адрэдагаванага відарыса."},getPluralForm(n){return (n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);}}}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
+ */
5
+
6
+ ( e => {
7
+ const { [ 'be' ]: { dictionary, getPluralForm } } = {"be":{"dictionary":{"Open file manager":"Адкрыць менеджэр файлаў","Cannot determine a category for the uploaded file.":"Немагчыма вызначыць катэгорыю для запампаванага файла.","Cannot access default workspace.":"Немагчыма атрымаць доступ да прадвызначанай працоўнай прасторы.","You have no image editing permissions.":"У вас няма дозволу на рэдагаванне відарыса.","Edit image":"Рэдагаваць відарыс","Processing the edited image.":"Апрацоўка адрэдагаванага відарыса.","Server failed to process the image.":"Сервер не здольны апрацаваць відарыс.","Failed to determine category of edited image.":"Не здольны вызначыць катэгорыю адрэдагаванага відарыса."},getPluralForm(n){return (n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);}}};
8
+ e[ 'be' ] ||= { dictionary: {}, getPluralForm: null };
9
+ e[ 'be' ].dictionary = Object.assign( e[ 'be' ].dictionary, dictionary );
10
+ e[ 'be' ].getPluralForm = getPluralForm;
11
+ } )( window.CKEDITOR_TRANSLATIONS ||= {} );
@@ -0,0 +1,44 @@
1
+ # Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
2
+ #
3
+ # Want to contribute to this file? Submit your changes via a GitHub Pull Request.
4
+ #
5
+ # Check out the official contributor's guide:
6
+ # https://ckeditor.com/docs/ckeditor5/latest/framework/guides/contributing/contributing.html
7
+ #
8
+ msgid ""
9
+ msgstr ""
10
+ "Language: be\n"
11
+ "Plural-Forms: nplurals=3; plural=(n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);\n"
12
+ "Content-Type: text/plain; charset=UTF-8\n"
13
+
14
+ msgctxt "A toolbar button tooltip for opening the file browser that allows inserting an image or a file to the editor."
15
+ msgid "Open file manager"
16
+ msgstr "Адкрыць менеджэр файлаў"
17
+
18
+ msgctxt "A message is displayed when CKEditor 5 cannot associate an image with any of the categories defined in CKBox while uploading an asset."
19
+ msgid "Cannot determine a category for the uploaded file."
20
+ msgstr "Немагчыма вызначыць катэгорыю для запампаванага файла."
21
+
22
+ msgctxt "A message is displayed when the user is not authorised to access the CKBox workspace configured as default one."
23
+ msgid "Cannot access default workspace."
24
+ msgstr "Немагчыма атрымаць доступ да прадвызначанай працоўнай прасторы."
25
+
26
+ msgctxt "The title of the notification displayed when there is no permission to edit assets."
27
+ msgid "You have no image editing permissions."
28
+ msgstr "У вас няма дозволу на рэдагаванне відарыса."
29
+
30
+ msgctxt "Image toolbar button tooltip for opening a dialog to manipulate the image."
31
+ msgid "Edit image"
32
+ msgstr "Рэдагаваць відарыс"
33
+
34
+ msgctxt "A message stating that image editing is in progress."
35
+ msgid "Processing the edited image."
36
+ msgstr "Апрацоўка адрэдагаванага відарыса."
37
+
38
+ msgctxt "A message is displayed when the server fails to process an image or doesn't respond."
39
+ msgid "Server failed to process the image."
40
+ msgstr "Сервер не здольны апрацаваць відарыс."
41
+
42
+ msgctxt "A message is displayed when category of the image user wants to edit can't be determined."
43
+ msgid "Failed to determine category of edited image."
44
+ msgstr "Не здольны вызначыць катэгорыю адрэдагаванага відарыса."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckeditor/ckeditor5-ckbox",
3
- "version": "44.3.0-alpha.7",
3
+ "version": "45.0.0-alpha.0",
4
4
  "description": "CKBox integration for CKEditor 5.",
5
5
  "keywords": [
6
6
  "ckeditor",
@@ -13,16 +13,17 @@
13
13
  "type": "module",
14
14
  "main": "src/index.js",
15
15
  "dependencies": {
16
- "@ckeditor/ckeditor5-cloud-services": "44.3.0-alpha.7",
17
- "@ckeditor/ckeditor5-core": "44.3.0-alpha.7",
18
- "@ckeditor/ckeditor5-engine": "44.3.0-alpha.7",
19
- "@ckeditor/ckeditor5-image": "44.3.0-alpha.7",
20
- "@ckeditor/ckeditor5-ui": "44.3.0-alpha.7",
21
- "@ckeditor/ckeditor5-upload": "44.3.0-alpha.7",
22
- "@ckeditor/ckeditor5-utils": "44.3.0-alpha.7",
23
- "ckeditor5": "44.3.0-alpha.7",
16
+ "@ckeditor/ckeditor5-cloud-services": "45.0.0-alpha.0",
17
+ "@ckeditor/ckeditor5-core": "45.0.0-alpha.0",
18
+ "@ckeditor/ckeditor5-engine": "45.0.0-alpha.0",
19
+ "@ckeditor/ckeditor5-icons": "45.0.0-alpha.0",
20
+ "@ckeditor/ckeditor5-image": "45.0.0-alpha.0",
21
+ "@ckeditor/ckeditor5-ui": "45.0.0-alpha.0",
22
+ "@ckeditor/ckeditor5-upload": "45.0.0-alpha.0",
23
+ "@ckeditor/ckeditor5-utils": "45.0.0-alpha.0",
24
+ "ckeditor5": "45.0.0-alpha.0",
24
25
  "blurhash": "2.0.5",
25
- "lodash-es": "4.17.21"
26
+ "es-toolkit": "1.32.0"
26
27
  },
27
28
  "author": "CKSource (http://cksource.com/)",
28
29
  "license": "SEE LICENSE IN LICENSE.md",
@@ -24,33 +24,33 @@ const ASSET_INSERTION_WAIT_TIMEOUT = 1000;
24
24
  * {@link module:link/link~Link Link feature}.
25
25
  */
26
26
  export default class CKBoxCommand extends Command {
27
+ /**
28
+ * A set of all chosen assets. They are stored temporarily and they are automatically removed 1 second after being chosen.
29
+ * Chosen assets have to be "remembered" for a while to be able to map the given asset with the element inserted into the model.
30
+ * This association map is then used to set the ID on the model element.
31
+ *
32
+ * All chosen assets are automatically removed after the timeout, because (theoretically) it may happen that they will never be
33
+ * inserted into the model, even if the {@link module:link/linkcommand~LinkCommand `'link'`} command or the
34
+ * {@link module:image/image/insertimagecommand~InsertImageCommand `'insertImage'`} command is enabled. Such a case may arise when
35
+ * another plugin blocks the command execution. Then, in order not to keep the chosen (but not inserted) assets forever, we delete
36
+ * them automatically to prevent memory leakage. The 1 second timeout is enough to insert the asset into the model and extract the
37
+ * ID from the chosen asset.
38
+ *
39
+ * The assets are stored only if
40
+ * the {@link module:ckbox/ckboxconfig~CKBoxConfig#ignoreDataId `config.ckbox.ignoreDataId`} option is set to `false` (by default).
41
+ *
42
+ * @internal
43
+ */
44
+ _chosenAssets = new Set();
45
+ /**
46
+ * The DOM element that acts as a mounting point for the CKBox dialog.
47
+ */
48
+ _wrapper = null;
27
49
  /**
28
50
  * @inheritDoc
29
51
  */
30
52
  constructor(editor) {
31
53
  super(editor);
32
- /**
33
- * A set of all chosen assets. They are stored temporarily and they are automatically removed 1 second after being chosen.
34
- * Chosen assets have to be "remembered" for a while to be able to map the given asset with the element inserted into the model.
35
- * This association map is then used to set the ID on the model element.
36
- *
37
- * All chosen assets are automatically removed after the timeout, because (theoretically) it may happen that they will never be
38
- * inserted into the model, even if the {@link module:link/linkcommand~LinkCommand `'link'`} command or the
39
- * {@link module:image/image/insertimagecommand~InsertImageCommand `'insertImage'`} command is enabled. Such a case may arise when
40
- * another plugin blocks the command execution. Then, in order not to keep the chosen (but not inserted) assets forever, we delete
41
- * them automatically to prevent memory leakage. The 1 second timeout is enough to insert the asset into the model and extract the
42
- * ID from the chosen asset.
43
- *
44
- * The assets are stored only if
45
- * the {@link module:ckbox/ckboxconfig~CKBoxConfig#ignoreDataId `config.ckbox.ignoreDataId`} option is set to `false` (by default).
46
- *
47
- * @internal
48
- */
49
- this._chosenAssets = new Set();
50
- /**
51
- * The DOM element that acts as a mounting point for the CKBox dialog.
52
- */
53
- this._wrapper = null;
54
54
  this._initListeners();
55
55
  }
56
56
  /**
@@ -9,7 +9,7 @@
9
9
  import { Command, PendingActions } from 'ckeditor5/src/core.js';
10
10
  import { CKEditorError, abortableDebounce, createElement, retry, delay } from 'ckeditor5/src/utils.js';
11
11
  import { Notification } from 'ckeditor5/src/ui.js';
12
- import { isEqual } from 'lodash-es';
12
+ import { isEqual } from 'es-toolkit/compat';
13
13
  import { sendHttpRequest } from '../utils.js';
14
14
  import { prepareImageAssetAttributes } from '../ckboxcommand.js';
15
15
  import { createEditabilityChecker } from './utils.js';
@@ -20,27 +20,35 @@ import CKBoxUtils from '../ckboxutils.js';
20
20
  * Opens the CKBox dialog for editing the image.
21
21
  */
22
22
  export default class CKBoxImageEditCommand extends Command {
23
+ /**
24
+ * The DOM element that acts as a mounting point for the CKBox Edit Image dialog.
25
+ */
26
+ _wrapper = null;
27
+ /**
28
+ * The states of image processing in progress.
29
+ */
30
+ _processInProgress = new Set();
31
+ /**
32
+ * Determines if the element can be edited.
33
+ */
34
+ _canEdit;
35
+ /**
36
+ * A wrapper function to prepare mount options. Ensures that at most one preparation is in-flight.
37
+ */
38
+ _prepareOptions;
39
+ /**
40
+ * CKBox's onClose function runs before the final cleanup, potentially causing
41
+ * page layout changes after it finishes. To address this, we use a setTimeout hack
42
+ * to ensure that floating elements on the page maintain their correct position.
43
+ *
44
+ * See: https://github.com/ckeditor/ckeditor5/issues/16153.
45
+ */
46
+ _updateUiDelayed = delay(() => this.editor.ui.update(), 0);
23
47
  /**
24
48
  * @inheritDoc
25
49
  */
26
50
  constructor(editor) {
27
51
  super(editor);
28
- /**
29
- * The DOM element that acts as a mounting point for the CKBox Edit Image dialog.
30
- */
31
- this._wrapper = null;
32
- /**
33
- * The states of image processing in progress.
34
- */
35
- this._processInProgress = new Set();
36
- /**
37
- * CKBox's onClose function runs before the final cleanup, potentially causing
38
- * page layout changes after it finishes. To address this, we use a setTimeout hack
39
- * to ensure that floating elements on the page maintain their correct position.
40
- *
41
- * See: https://github.com/ckeditor/ckeditor5/issues/16153.
42
- */
43
- this._updateUiDelayed = delay(() => this.editor.ui.update(), 0);
44
52
  this.value = false;
45
53
  this._canEdit = createEditabilityChecker(editor.config.get('ckbox.allowExternalImagesEditing'));
46
54
  this._prepareOptions = abortableDebounce((signal, state) => this._prepareOptionsAbortable(signal, state));
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import { Plugin } from 'ckeditor5/src/core.js';
9
9
  import { ButtonView } from 'ckeditor5/src/ui.js';
10
- import ckboxImageEditIcon from '../../theme/icons/ckbox-image-edit.svg';
10
+ import { IconCkboxImageEdit } from 'ckeditor5/src/icons.js';
11
11
  /**
12
12
  * The UI plugin of the CKBox image edit feature.
13
13
  *
@@ -38,7 +38,7 @@ export default class CKBoxImageEditUI extends Plugin {
38
38
  const view = new ButtonView(locale);
39
39
  const t = locale.t;
40
40
  view.set({
41
- icon: ckboxImageEditIcon,
41
+ icon: IconCkboxImageEdit,
42
42
  tooltip: true
43
43
  });
44
44
  view.bind('label').to(uploadImageCommand, 'isAccessAllowed', isAccessAllowed => isAccessAllowed ?
package/src/ckboxui.js CHANGED
@@ -5,8 +5,9 @@
5
5
  /**
6
6
  * @module ckbox/ckboxui
7
7
  */
8
- import { icons, Plugin } from 'ckeditor5/src/core.js';
8
+ import { Plugin } from 'ckeditor5/src/core.js';
9
9
  import { ButtonView, MenuBarMenuListItemButtonView } from 'ckeditor5/src/ui.js';
10
+ import { IconBrowseFiles, IconImageAssetManager } from 'ckeditor5/src/icons.js';
10
11
  /**
11
12
  * Introduces UI components for the `CKBox` plugin.
12
13
  *
@@ -72,7 +73,7 @@ export default class CKBoxUI extends Plugin {
72
73
  _createFileToolbarButton() {
73
74
  const t = this.editor.locale.t;
74
75
  const button = this._createButton(ButtonView);
75
- button.icon = icons.browseFiles;
76
+ button.icon = IconBrowseFiles;
76
77
  button.label = t('Open file manager');
77
78
  button.tooltip = true;
78
79
  return button;
@@ -84,7 +85,7 @@ export default class CKBoxUI extends Plugin {
84
85
  const t = this.editor.locale.t;
85
86
  const imageInsertUI = this.editor.plugins.get('ImageInsertUI');
86
87
  const button = this._createButton(ButtonView);
87
- button.icon = icons.imageAssetManager;
88
+ button.icon = IconImageAssetManager;
88
89
  button.bind('label').to(imageInsertUI, 'isImageSelected', isImageSelected => isImageSelected ? t('Replace image with file manager') : t('Insert image with file manager'));
89
90
  button.tooltip = true;
90
91
  return button;
@@ -96,7 +97,7 @@ export default class CKBoxUI extends Plugin {
96
97
  const t = this.editor.locale.t;
97
98
  const imageInsertUI = this.editor.plugins.get('ImageInsertUI');
98
99
  const button = this._createButton(ButtonView);
99
- button.icon = icons.imageAssetManager;
100
+ button.icon = IconImageAssetManager;
100
101
  button.withText = true;
101
102
  button.bind('label').to(imageInsertUI, 'isImageSelected', isImageSelected => isImageSelected ? t('Replace with file manager') : t('Insert with file manager'));
102
103
  button.on('execute', () => {
@@ -110,7 +111,7 @@ export default class CKBoxUI extends Plugin {
110
111
  _createFileMenuBarButton() {
111
112
  const t = this.editor.locale.t;
112
113
  const button = this._createButton(MenuBarMenuListItemButtonView);
113
- button.icon = icons.browseFiles;
114
+ button.icon = IconBrowseFiles;
114
115
  button.withText = true;
115
116
  button.label = t('File');
116
117
  return button;
@@ -123,7 +124,7 @@ export default class CKBoxUI extends Plugin {
123
124
  const translateVariableKey = this.editor.locale.t;
124
125
  const t = this.editor.locale.t;
125
126
  const button = this._createButton(MenuBarMenuListItemButtonView);
126
- button.icon = icons.imageAssetManager;
127
+ button.icon = IconImageAssetManager;
127
128
  button.withText = true;
128
129
  switch (type) {
129
130
  case 'insertOnly':
@@ -71,6 +71,30 @@ export default class CKBoxUploadAdapter extends Plugin {
71
71
  * Upload adapter for CKBox.
72
72
  */
73
73
  class Adapter {
74
+ /**
75
+ * FileLoader instance to use during the upload.
76
+ */
77
+ loader;
78
+ /**
79
+ * CKEditor Cloud Services access token.
80
+ */
81
+ token;
82
+ /**
83
+ * The editor instance.
84
+ */
85
+ editor;
86
+ /**
87
+ * The abort controller for aborting asynchronous processes.
88
+ */
89
+ controller;
90
+ /**
91
+ * The base URL where all requests should be sent.
92
+ */
93
+ serviceOrigin;
94
+ /**
95
+ * The reference to CKBoxUtils plugin.
96
+ */
97
+ ckboxUtils;
74
98
  /**
75
99
  * Creates a new adapter instance.
76
100
  */
@@ -51,4 +51,9 @@ export default class CKBoxUtils extends Plugin {
51
51
  * If the API returns limited results, the method will collect all items.
52
52
  */
53
53
  private _getAvailableCategories;
54
+ /**
55
+ * Authorize private categories access to the CKBox service. Request sets cookie for the current domain,
56
+ * that allows user to preview images from private categories.
57
+ */
58
+ private _authorizePrivateCategoriesAccess;
54
59
  }
package/src/ckboxutils.js CHANGED
@@ -10,6 +10,10 @@ const DEFAULT_CKBOX_THEME_NAME = 'lark';
10
10
  * The CKBox utilities plugin.
11
11
  */
12
12
  export default class CKBoxUtils extends Plugin {
13
+ /**
14
+ * CKEditor Cloud Services access token.
15
+ */
16
+ _token;
13
17
  /**
14
18
  * @inheritDoc
15
19
  */
@@ -77,6 +81,13 @@ export default class CKBoxUtils extends Plugin {
77
81
  else {
78
82
  this._token = cloudServices.registerTokenUrl(ckboxTokenUrl);
79
83
  }
84
+ // Grant access to private categories after token is fetched. This is done within the same promise chain
85
+ // to ensure all services using the token have access to private categories.
86
+ // This step is critical as previewing images from private categories requires proper cookies.
87
+ this._token = this._token.then(async (token) => {
88
+ await this._authorizePrivateCategoriesAccess(token.value);
89
+ return token;
90
+ });
80
91
  }
81
92
  /**
82
93
  * Returns a token used by the CKBox plugin for communication with the CKBox service.
@@ -186,4 +197,19 @@ export default class CKBoxUtils extends Plugin {
186
197
  });
187
198
  }
188
199
  }
200
+ /**
201
+ * Authorize private categories access to the CKBox service. Request sets cookie for the current domain,
202
+ * that allows user to preview images from private categories.
203
+ */
204
+ async _authorizePrivateCategoriesAccess(token) {
205
+ const serviceUrl = this.editor.config.get('ckbox.serviceOrigin');
206
+ const formData = new FormData();
207
+ formData.set('token', token);
208
+ await fetch(`${serviceUrl}/categories/authorizePrivateAccess`, {
209
+ method: 'POST',
210
+ credentials: 'include',
211
+ mode: 'no-cors',
212
+ body: formData
213
+ });
214
+ }
189
215
  }
package/src/utils.js CHANGED
@@ -38,12 +38,11 @@ export function getImageUrls(imageUrls) {
38
38
  export function getWorkspaceId(token, defaultWorkspaceId) {
39
39
  const [, binaryTokenPayload] = token.value.split('.');
40
40
  const payload = JSON.parse(atob(binaryTokenPayload));
41
- const workspaces = (payload.auth && payload.auth.ckbox && payload.auth.ckbox.workspaces) || [payload.aud];
41
+ const workspaces = payload.auth?.ckbox?.workspaces || [payload.aud];
42
42
  if (!defaultWorkspaceId) {
43
43
  return workspaces[0];
44
44
  }
45
- const role = payload.auth && payload.auth.ckbox && payload.auth.ckbox.role;
46
- if (role == 'superadmin' || workspaces.includes(defaultWorkspaceId)) {
45
+ if (payload.auth?.ckbox?.role == 'superadmin' || workspaces.includes(defaultWorkspaceId)) {
47
46
  return defaultWorkspaceId;
48
47
  }
49
48
  return null;
@@ -1 +0,0 @@
1
- <svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M1.201 1C.538 1 0 1.47 0 2.1v14.363c0 .64.534 1.037 1.186 1.037H5.06l5.058-5.078L6.617 9.15a.696.696 0 0 0-.957-.033L1.5 13.6V2.5h15v4.354a3.478 3.478 0 0 1 1.5.049V2.1c0-.63-.547-1.1-1.2-1.1H1.202Zm11.713 2.803a2.147 2.147 0 0 0-2.049 1.992 2.14 2.14 0 0 0 1.28 2.096 2.13 2.13 0 0 0 2.642-3.11 2.129 2.129 0 0 0-1.873-.978ZM8.089 17.635v2.388h2.389l7.046-7.046-2.39-2.39-7.045 7.048Zm11.282-6.507a.637.637 0 0 0 .139-.692.603.603 0 0 0-.139-.205l-1.49-1.488a.63.63 0 0 0-.899 0l-1.166 1.163 2.39 2.39 1.165-1.168Z"/></svg>