@ckeditor/ckeditor5-ckbox 0.0.0-nightly-20240509.0 → 0.0.0-nightly-20240510.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
@@ -5,20 +5,22 @@
5
5
  import { Plugin, icons, Command, PendingActions } from '@ckeditor/ckeditor5-core/dist/index.js';
6
6
  import { ButtonView, MenuBarMenuListItemButtonView, Notification } from '@ckeditor/ckeditor5-ui/dist/index.js';
7
7
  import { Range } from '@ckeditor/ckeditor5-engine/dist/index.js';
8
- import { createElement, toMap, CKEditorError, logError, global, retry, abortableDebounce } from '@ckeditor/ckeditor5-utils/dist/index.js';
8
+ import { createElement, toMap, CKEditorError, logError, global, abortableDebounce, retry } from '@ckeditor/ckeditor5-utils/dist/index.js';
9
9
  import { decode } from 'blurhash';
10
10
  import { FileRepository } from '@ckeditor/ckeditor5-upload/dist/index.js';
11
11
  import { isEqual } from 'lodash-es';
12
12
 
13
- class CKBoxUI extends Plugin {
13
+ /**
14
+ * The CKBoxUI plugin. It introduces the `'ckbox'` toolbar button.
15
+ */ class CKBoxUI extends Plugin {
14
16
  /**
15
- * @inheritDoc
16
- */ static get pluginName() {
17
+ * @inheritDoc
18
+ */ static get pluginName() {
17
19
  return 'CKBoxUI';
18
20
  }
19
21
  /**
20
- * @inheritDoc
21
- */ afterInit() {
22
+ * @inheritDoc
23
+ */ afterInit() {
22
24
  const editor = this.editor;
23
25
  // Do not register the `ckbox` button if the command does not exist.
24
26
  // This might happen when CKBox library is not loaded on the page.
@@ -58,8 +60,8 @@ class CKBoxUI extends Plugin {
58
60
  }
59
61
  }
60
62
  /**
61
- * Creates a button for CKBox command to use either in toolbar or in menu bar.
62
- */ _createButton(ButtonClass) {
63
+ * Creates a button for CKBox command to use either in toolbar or in menu bar.
64
+ */ _createButton(ButtonClass) {
63
65
  const editor = this.editor;
64
66
  const locale = editor.locale;
65
67
  const view = new ButtonClass(locale);
@@ -235,7 +237,7 @@ const MIME_TO_EXTENSION = {
235
237
  * Returns an extension from the given value.
236
238
  */ function getFileExtension(file) {
237
239
  const fileName = file.name;
238
- const extensionRegExp = RegExp("\\.(?<ext>[^.]+)$");
240
+ const extensionRegExp = /\.(?<ext>[^.]+)$/;
239
241
  const match = fileName.match(extensionRegExp);
240
242
  return match.groups.ext.toLowerCase();
241
243
  }
@@ -244,29 +246,68 @@ const MIME_TO_EXTENSION = {
244
246
  // `CKBoxCommand#_chosenAssets` and it is removed from there automatically after this time. See `CKBoxCommand#_chosenAssets` for more
245
247
  // details.
246
248
  const ASSET_INSERTION_WAIT_TIMEOUT = 1000;
247
- class CKBoxCommand extends Command {
249
+ /**
250
+ * The CKBox command. It is used by the {@link module:ckbox/ckboxediting~CKBoxEditing CKBox editing feature} to open the CKBox file manager.
251
+ * The file manager allows inserting an image or a link to a file into the editor content.
252
+ *
253
+ * ```ts
254
+ * editor.execute( 'ckbox' );
255
+ * ```
256
+ *
257
+ * **Note:** This command uses other features to perform the following tasks:
258
+ * - To insert images it uses the {@link module:image/image/insertimagecommand~InsertImageCommand 'insertImage'} command from the
259
+ * {@link module:image/image~Image Image feature}.
260
+ * - To insert links to other files it uses the {@link module:link/linkcommand~LinkCommand 'link'} command from the
261
+ * {@link module:link/link~Link Link feature}.
262
+ */ class CKBoxCommand extends Command {
263
+ /**
264
+ * A set of all chosen assets. They are stored temporarily and they are automatically removed 1 second after being chosen.
265
+ * Chosen assets have to be "remembered" for a while to be able to map the given asset with the element inserted into the model.
266
+ * This association map is then used to set the ID on the model element.
267
+ *
268
+ * All chosen assets are automatically removed after the timeout, because (theoretically) it may happen that they will never be
269
+ * inserted into the model, even if the {@link module:link/linkcommand~LinkCommand `'link'`} command or the
270
+ * {@link module:image/image/insertimagecommand~InsertImageCommand `'insertImage'`} command is enabled. Such a case may arise when
271
+ * another plugin blocks the command execution. Then, in order not to keep the chosen (but not inserted) assets forever, we delete
272
+ * them automatically to prevent memory leakage. The 1 second timeout is enough to insert the asset into the model and extract the
273
+ * ID from the chosen asset.
274
+ *
275
+ * The assets are stored only if
276
+ * the {@link module:ckbox/ckboxconfig~CKBoxConfig#ignoreDataId `config.ckbox.ignoreDataId`} option is set to `false` (by default).
277
+ *
278
+ * @internal
279
+ */ _chosenAssets = new Set();
280
+ /**
281
+ * The DOM element that acts as a mounting point for the CKBox dialog.
282
+ */ _wrapper = null;
283
+ /**
284
+ * @inheritDoc
285
+ */ constructor(editor){
286
+ super(editor);
287
+ this._initListeners();
288
+ }
248
289
  /**
249
- * @inheritDoc
250
- */ refresh() {
290
+ * @inheritDoc
291
+ */ refresh() {
251
292
  this.value = this._getValue();
252
293
  this.isEnabled = this._checkEnabled();
253
294
  }
254
295
  /**
255
- * @inheritDoc
256
- */ execute() {
296
+ * @inheritDoc
297
+ */ execute() {
257
298
  this.fire('ckbox:open');
258
299
  }
259
300
  /**
260
- * Indicates if the CKBox dialog is already opened.
261
- *
262
- * @protected
263
- * @returns {Boolean}
264
- */ _getValue() {
301
+ * Indicates if the CKBox dialog is already opened.
302
+ *
303
+ * @protected
304
+ * @returns {Boolean}
305
+ */ _getValue() {
265
306
  return this._wrapper !== null;
266
307
  }
267
308
  /**
268
- * Checks whether the command can be enabled in the current context.
269
- */ _checkEnabled() {
309
+ * Checks whether the command can be enabled in the current context.
310
+ */ _checkEnabled() {
270
311
  const imageCommand = this.editor.commands.get('insertImage');
271
312
  const linkCommand = this.editor.commands.get('link');
272
313
  if (!imageCommand.isEnabled && !linkCommand.isEnabled) {
@@ -275,17 +316,17 @@ class CKBoxCommand extends Command {
275
316
  return true;
276
317
  }
277
318
  /**
278
- * Creates the options object for the CKBox dialog.
279
- *
280
- * @returns The object with properties:
281
- * - theme The theme for CKBox dialog.
282
- * - language The language for CKBox dialog.
283
- * - tokenUrl The token endpoint URL.
284
- * - serviceOrigin The base URL of the API service.
285
- * - forceDemoLabel Whether to force "Powered by CKBox" link.
286
- * - dialog.onClose The callback function invoked after closing the CKBox dialog.
287
- * - assets.onChoose The callback function invoked after choosing the assets.
288
- */ _prepareOptions() {
319
+ * Creates the options object for the CKBox dialog.
320
+ *
321
+ * @returns The object with properties:
322
+ * - theme The theme for CKBox dialog.
323
+ * - language The language for CKBox dialog.
324
+ * - tokenUrl The token endpoint URL.
325
+ * - serviceOrigin The base URL of the API service.
326
+ * - forceDemoLabel Whether to force "Powered by CKBox" link.
327
+ * - dialog.onClose The callback function invoked after closing the CKBox dialog.
328
+ * - assets.onChoose The callback function invoked after choosing the assets.
329
+ */ _prepareOptions() {
289
330
  const editor = this.editor;
290
331
  const ckboxConfig = editor.config.get('ckbox');
291
332
  return {
@@ -303,8 +344,8 @@ class CKBoxCommand extends Command {
303
344
  };
304
345
  }
305
346
  /**
306
- * Initializes various event listeners for the `ckbox:*` events, because all functionality of the `ckbox` command is event-based.
307
- */ _initListeners() {
347
+ * Initializes various event listeners for the `ckbox:*` events, because all functionality of the `ckbox` command is event-based.
348
+ */ _initListeners() {
308
349
  const editor = this.editor;
309
350
  const model = editor.model;
310
351
  const shouldInsertDataId = !editor.config.get('ckbox.ignoreDataId');
@@ -373,13 +414,13 @@ class CKBoxCommand extends Command {
373
414
  });
374
415
  }
375
416
  /**
376
- * Inserts the asset into the model.
377
- *
378
- * @param asset The asset to be inserted.
379
- * @param isLastAsset Indicates if the current asset is the last one from the chosen set.
380
- * @param writer An instance of the model writer.
381
- * @param isSingleAsset It's true when only one asset is processed.
382
- */ _insertAsset(asset, isLastAsset, writer, isSingleAsset) {
417
+ * Inserts the asset into the model.
418
+ *
419
+ * @param asset The asset to be inserted.
420
+ * @param isLastAsset Indicates if the current asset is the last one from the chosen set.
421
+ * @param writer An instance of the model writer.
422
+ * @param isSingleAsset It's true when only one asset is processed.
423
+ */ _insertAsset(asset, isLastAsset, writer, isSingleAsset) {
383
424
  const editor = this.editor;
384
425
  const model = editor.model;
385
426
  const selection = model.document.selection;
@@ -397,10 +438,10 @@ class CKBoxCommand extends Command {
397
438
  }
398
439
  }
399
440
  /**
400
- * Inserts the image by calling the `insertImage` command.
401
- *
402
- * @param asset The asset to be inserted.
403
- */ _insertImage(asset) {
441
+ * Inserts the image by calling the `insertImage` command.
442
+ *
443
+ * @param asset The asset to be inserted.
444
+ */ _insertImage(asset) {
404
445
  const editor = this.editor;
405
446
  const { imageFallbackUrl, imageSources, imageTextAlternative, imageWidth, imageHeight, imagePlaceholder } = asset.attributes;
406
447
  editor.execute('insertImage', {
@@ -417,12 +458,12 @@ class CKBoxCommand extends Command {
417
458
  });
418
459
  }
419
460
  /**
420
- * Inserts the link to the asset by calling the `link` command.
421
- *
422
- * @param asset The asset to be inserted.
423
- * @param writer An instance of the model writer.
424
- * @param isSingleAsset It's true when only one asset is processed.
425
- */ _insertLink(asset, writer, isSingleAsset) {
461
+ * Inserts the link to the asset by calling the `link` command.
462
+ *
463
+ * @param asset The asset to be inserted.
464
+ * @param writer An instance of the model writer.
465
+ * @param isSingleAsset It's true when only one asset is processed.
466
+ */ _insertLink(asset, writer, isSingleAsset) {
426
467
  const editor = this.editor;
427
468
  const model = editor.model;
428
469
  const selection = model.document.selection;
@@ -450,32 +491,6 @@ class CKBoxCommand extends Command {
450
491
  }
451
492
  editor.execute('link', linkHref);
452
493
  }
453
- /**
454
- * @inheritDoc
455
- */ constructor(editor){
456
- super(editor);
457
- /**
458
- * A set of all chosen assets. They are stored temporarily and they are automatically removed 1 second after being chosen.
459
- * Chosen assets have to be "remembered" for a while to be able to map the given asset with the element inserted into the model.
460
- * This association map is then used to set the ID on the model element.
461
- *
462
- * All chosen assets are automatically removed after the timeout, because (theoretically) it may happen that they will never be
463
- * inserted into the model, even if the {@link module:link/linkcommand~LinkCommand `'link'`} command or the
464
- * {@link module:image/image/insertimagecommand~InsertImageCommand `'insertImage'`} command is enabled. Such a case may arise when
465
- * another plugin blocks the command execution. Then, in order not to keep the chosen (but not inserted) assets forever, we delete
466
- * them automatically to prevent memory leakage. The 1 second timeout is enough to insert the asset into the model and extract the
467
- * ID from the chosen asset.
468
- *
469
- * The assets are stored only if
470
- * the {@link module:ckbox/ckboxconfig~CKBoxConfig#ignoreDataId `config.ckbox.ignoreDataId`} option is set to `false` (by default).
471
- *
472
- * @internal
473
- */ this._chosenAssets = new Set();
474
- /**
475
- * The DOM element that acts as a mounting point for the CKBox dialog.
476
- */ this._wrapper = null;
477
- this._initListeners();
478
- }
479
494
  }
480
495
  /**
481
496
  * Parses the chosen assets into the internal data format. Filters out chosen assets that are not allowed.
@@ -539,22 +554,27 @@ class CKBoxCommand extends Command {
539
554
  }
540
555
 
541
556
  const DEFAULT_CKBOX_THEME_NAME = 'lark';
542
- class CKBoxUtils extends Plugin {
557
+ /**
558
+ * The CKBox utilities plugin.
559
+ */ class CKBoxUtils extends Plugin {
560
+ /**
561
+ * CKEditor Cloud Services access token.
562
+ */ _token;
543
563
  /**
544
- * @inheritDoc
545
- */ static get pluginName() {
564
+ * @inheritDoc
565
+ */ static get pluginName() {
546
566
  return 'CKBoxUtils';
547
567
  }
548
568
  /**
549
- * @inheritDoc
550
- */ static get requires() {
569
+ * @inheritDoc
570
+ */ static get requires() {
551
571
  return [
552
572
  'CloudServices'
553
573
  ];
554
574
  }
555
575
  /**
556
- * @inheritDoc
557
- */ async init() {
576
+ * @inheritDoc
577
+ */ async init() {
558
578
  const editor = this.editor;
559
579
  const hasConfiguration = !!editor.config.get('ckbox');
560
580
  const isLibraryLoaded = !!window.CKBox;
@@ -576,22 +596,22 @@ class CKBoxUtils extends Plugin {
576
596
  const ckboxTokenUrl = editor.config.get('ckbox.tokenUrl');
577
597
  if (!ckboxTokenUrl) {
578
598
  /**
579
- * The {@link module:ckbox/ckboxconfig~CKBoxConfig#tokenUrl `config.ckbox.tokenUrl`} or the
580
- * {@link module:cloud-services/cloudservicesconfig~CloudServicesConfig#tokenUrl `config.cloudServices.tokenUrl`}
581
- * configuration is required for the CKBox plugin.
582
- *
583
- * ```ts
584
- * ClassicEditor.create( document.createElement( 'div' ), {
585
- * ckbox: {
586
- * tokenUrl: "YOUR_TOKEN_URL"
587
- * // ...
588
- * }
589
- * // ...
590
- * } );
591
- * ```
592
- *
593
- * @error ckbox-plugin-missing-token-url
594
- */ throw new CKEditorError('ckbox-plugin-missing-token-url', this);
599
+ * The {@link module:ckbox/ckboxconfig~CKBoxConfig#tokenUrl `config.ckbox.tokenUrl`} or the
600
+ * {@link module:cloud-services/cloudservicesconfig~CloudServicesConfig#tokenUrl `config.cloudServices.tokenUrl`}
601
+ * configuration is required for the CKBox plugin.
602
+ *
603
+ * ```ts
604
+ * ClassicEditor.create( document.createElement( 'div' ), {
605
+ * ckbox: {
606
+ * tokenUrl: "YOUR_TOKEN_URL"
607
+ * // ...
608
+ * }
609
+ * // ...
610
+ * } );
611
+ * ```
612
+ *
613
+ * @error ckbox-plugin-missing-token-url
614
+ */ throw new CKEditorError('ckbox-plugin-missing-token-url', this);
595
615
  }
596
616
  if (ckboxTokenUrl == cloudServicesTokenUrl) {
597
617
  this._token = cloudServices.token;
@@ -600,30 +620,30 @@ class CKBoxUtils extends Plugin {
600
620
  }
601
621
  }
602
622
  /**
603
- * Returns a token used by the CKBox plugin for communication with the CKBox service.
604
- */ getToken() {
623
+ * Returns a token used by the CKBox plugin for communication with the CKBox service.
624
+ */ getToken() {
605
625
  return this._token;
606
626
  }
607
627
  /**
608
- * The ID of workspace to use when uploading an image.
609
- */ getWorkspaceId() {
628
+ * The ID of workspace to use when uploading an image.
629
+ */ getWorkspaceId() {
610
630
  const t = this.editor.t;
611
631
  const cannotAccessDefaultWorkspaceError = t('Cannot access default workspace.');
612
632
  const defaultWorkspaceId = this.editor.config.get('ckbox.defaultUploadWorkspaceId');
613
633
  const workspaceId = getWorkspaceId(this._token, defaultWorkspaceId);
614
634
  if (workspaceId == null) {
615
635
  /**
616
- * The user is not authorized to access the workspace defined in the`ckbox.defaultUploadWorkspaceId` configuration.
617
- *
618
- * @error ckbox-access-default-workspace-error
619
- */ logError('ckbox-access-default-workspace-error');
636
+ * The user is not authorized to access the workspace defined in the`ckbox.defaultUploadWorkspaceId` configuration.
637
+ *
638
+ * @error ckbox-access-default-workspace-error
639
+ */ logError('ckbox-access-default-workspace-error');
620
640
  throw cannotAccessDefaultWorkspaceError;
621
641
  }
622
642
  return workspaceId;
623
643
  }
624
644
  /**
625
- * Resolves a promise with an object containing a category with which the uploaded file is associated or an error code.
626
- */ async getCategoryIdForFile(fileOrUrl, options) {
645
+ * Resolves a promise with an object containing a category with which the uploaded file is associated or an error code.
646
+ */ async getCategoryIdForFile(fileOrUrl, options) {
627
647
  const t = this.editor.t;
628
648
  const cannotFindCategoryError = t('Cannot determine a category for the uploaded file.');
629
649
  const defaultCategories = this.editor.config.get('ckbox.defaultUploadCategories');
@@ -656,10 +676,10 @@ class CKBoxUtils extends Plugin {
656
676
  return category.id;
657
677
  }
658
678
  /**
659
- * Resolves a promise with an array containing available categories with which the uploaded file can be associated.
660
- *
661
- * If the API returns limited results, the method will collect all items.
662
- */ async _getAvailableCategories(options) {
679
+ * Resolves a promise with an array containing available categories with which the uploaded file can be associated.
680
+ *
681
+ * If the API returns limited results, the method will collect all items.
682
+ */ async _getAvailableCategories(options) {
663
683
  const ITEMS_PER_REQUEST = 50;
664
684
  const editor = this.editor;
665
685
  const token = this._token;
@@ -680,10 +700,10 @@ class CKBoxUtils extends Plugin {
680
700
  } catch {
681
701
  signal.throwIfAborted();
682
702
  /**
683
- * Fetching a list of available categories with which an uploaded file can be associated failed.
684
- *
685
- * @error ckbox-fetch-category-http-error
686
- */ logError('ckbox-fetch-category-http-error');
703
+ * Fetching a list of available categories with which an uploaded file can be associated failed.
704
+ *
705
+ * @error ckbox-fetch-category-http-error
706
+ */ logError('ckbox-fetch-category-http-error');
687
707
  return undefined;
688
708
  }
689
709
  function fetchCategories(offset) {
@@ -700,10 +720,18 @@ class CKBoxUtils extends Plugin {
700
720
  }
701
721
  }
702
722
 
703
- class CKBoxUploadAdapter extends Plugin {
723
+ /**
724
+ * A plugin that enables file uploads in CKEditor 5 using the CKBox server–side connector.
725
+ * See the {@glink features/file-management/ckbox CKBox file manager integration} guide to learn how to configure
726
+ * and use this feature as well as find out more about the full integration with the file manager
727
+ * provided by the {@link module:ckbox/ckbox~CKBox} plugin.
728
+ *
729
+ * Check out the {@glink features/images/image-upload/image-upload Image upload overview} guide to learn about
730
+ * other ways to upload images into CKEditor 5.
731
+ */ class CKBoxUploadAdapter extends Plugin {
704
732
  /**
705
- * @inheritDoc
706
- */ static get requires() {
733
+ * @inheritDoc
734
+ */ static get requires() {
707
735
  return [
708
736
  'ImageUploadEditing',
709
737
  'ImageUploadProgress',
@@ -712,13 +740,13 @@ class CKBoxUploadAdapter extends Plugin {
712
740
  ];
713
741
  }
714
742
  /**
715
- * @inheritDoc
716
- */ static get pluginName() {
743
+ * @inheritDoc
744
+ */ static get pluginName() {
717
745
  return 'CKBoxUploadAdapter';
718
746
  }
719
747
  /**
720
- * @inheritDoc
721
- */ async afterInit() {
748
+ * @inheritDoc
749
+ */ async afterInit() {
722
750
  const editor = this.editor;
723
751
  const hasConfiguration = !!editor.config.get('ckbox');
724
752
  const isLibraryLoaded = !!window.CKBox;
@@ -747,10 +775,38 @@ class CKBoxUploadAdapter extends Plugin {
747
775
  * Upload adapter for CKBox.
748
776
  */ class Adapter {
749
777
  /**
750
- * Starts the upload process.
751
- *
752
- * @see module:upload/filerepository~UploadAdapter#upload
753
- */ async upload() {
778
+ * FileLoader instance to use during the upload.
779
+ */ loader;
780
+ /**
781
+ * CKEditor Cloud Services access token.
782
+ */ token;
783
+ /**
784
+ * The editor instance.
785
+ */ editor;
786
+ /**
787
+ * The abort controller for aborting asynchronous processes.
788
+ */ controller;
789
+ /**
790
+ * The base URL where all requests should be sent.
791
+ */ serviceOrigin;
792
+ /**
793
+ * The reference to CKBoxUtils plugin.
794
+ */ ckboxUtils;
795
+ /**
796
+ * Creates a new adapter instance.
797
+ */ constructor(loader, editor, ckboxUtils){
798
+ this.loader = loader;
799
+ this.token = ckboxUtils.getToken();
800
+ this.ckboxUtils = ckboxUtils;
801
+ this.editor = editor;
802
+ this.controller = new AbortController();
803
+ this.serviceOrigin = editor.config.get('ckbox.serviceOrigin');
804
+ }
805
+ /**
806
+ * Starts the upload process.
807
+ *
808
+ * @see module:upload/filerepository~UploadAdapter#upload
809
+ */ async upload() {
754
810
  const ckboxUtils = this.ckboxUtils;
755
811
  const t = this.editor.t;
756
812
  const file = await this.loader.file;
@@ -788,33 +844,29 @@ class CKBoxUploadAdapter extends Plugin {
788
844
  });
789
845
  }
790
846
  /**
791
- * Aborts the upload process.
792
- *
793
- * @see module:upload/filerepository~UploadAdapter#abort
794
- */ abort() {
847
+ * Aborts the upload process.
848
+ *
849
+ * @see module:upload/filerepository~UploadAdapter#abort
850
+ */ abort() {
795
851
  this.controller.abort();
796
852
  }
797
- /**
798
- * Creates a new adapter instance.
799
- */ constructor(loader, editor, ckboxUtils){
800
- this.loader = loader;
801
- this.token = ckboxUtils.getToken();
802
- this.ckboxUtils = ckboxUtils;
803
- this.editor = editor;
804
- this.controller = new AbortController();
805
- this.serviceOrigin = editor.config.get('ckbox.serviceOrigin');
806
- }
807
853
  }
808
854
 
809
- class CKBoxEditing extends Plugin {
855
+ /**
856
+ * The CKBox editing feature. It introduces the {@link module:ckbox/ckboxcommand~CKBoxCommand CKBox command} and
857
+ * {@link module:ckbox/ckboxuploadadapter~CKBoxUploadAdapter CKBox upload adapter}.
858
+ */ class CKBoxEditing extends Plugin {
810
859
  /**
811
- * @inheritDoc
812
- */ static get pluginName() {
860
+ * CKEditor Cloud Services access token.
861
+ */ _token;
862
+ /**
863
+ * @inheritDoc
864
+ */ static get pluginName() {
813
865
  return 'CKBoxEditing';
814
866
  }
815
867
  /**
816
- * @inheritDoc
817
- */ static get requires() {
868
+ * @inheritDoc
869
+ */ static get requires() {
818
870
  return [
819
871
  'LinkEditing',
820
872
  'PictureEditing',
@@ -823,8 +875,8 @@ class CKBoxEditing extends Plugin {
823
875
  ];
824
876
  }
825
877
  /**
826
- * @inheritDoc
827
- */ init() {
878
+ * @inheritDoc
879
+ */ init() {
828
880
  const editor = this.editor;
829
881
  if (!this._shouldBeInitialised()) {
830
882
  return;
@@ -836,8 +888,8 @@ class CKBoxEditing extends Plugin {
836
888
  }
837
889
  }
838
890
  /**
839
- * @inheritDoc
840
- */ afterInit() {
891
+ * @inheritDoc
892
+ */ afterInit() {
841
893
  const editor = this.editor;
842
894
  if (!this._shouldBeInitialised()) {
843
895
  return;
@@ -851,35 +903,35 @@ class CKBoxEditing extends Plugin {
851
903
  }
852
904
  }
853
905
  /**
854
- * Returns true only when the integrator intentionally wants to use the plugin, i.e. when the `config.ckbox` exists or
855
- * the CKBox JavaScript library is loaded.
856
- */ _shouldBeInitialised() {
906
+ * Returns true only when the integrator intentionally wants to use the plugin, i.e. when the `config.ckbox` exists or
907
+ * the CKBox JavaScript library is loaded.
908
+ */ _shouldBeInitialised() {
857
909
  const editor = this.editor;
858
910
  const hasConfiguration = !!editor.config.get('ckbox');
859
911
  return hasConfiguration || isLibraryLoaded();
860
912
  }
861
913
  /**
862
- * Checks if at least one image plugin is loaded.
863
- */ _checkImagePlugins() {
914
+ * Checks if at least one image plugin is loaded.
915
+ */ _checkImagePlugins() {
864
916
  const editor = this.editor;
865
917
  if (!editor.plugins.has('ImageBlockEditing') && !editor.plugins.has('ImageInlineEditing')) {
866
918
  /**
867
- * The CKBox feature requires one of the following plugins to be loaded to work correctly:
868
- *
869
- * * {@link module:image/imageblock~ImageBlock},
870
- * * {@link module:image/imageinline~ImageInline},
871
- * * {@link module:image/image~Image} (loads both `ImageBlock` and `ImageInline`)
872
- *
873
- * Please make sure your editor configuration is correct.
874
- *
875
- * @error ckbox-plugin-image-feature-missing
876
- * @param {module:core/editor/editor~Editor} editor
877
- */ logError('ckbox-plugin-image-feature-missing', editor);
919
+ * The CKBox feature requires one of the following plugins to be loaded to work correctly:
920
+ *
921
+ * * {@link module:image/imageblock~ImageBlock},
922
+ * * {@link module:image/imageinline~ImageInline},
923
+ * * {@link module:image/image~Image} (loads both `ImageBlock` and `ImageInline`)
924
+ *
925
+ * Please make sure your editor configuration is correct.
926
+ *
927
+ * @error ckbox-plugin-image-feature-missing
928
+ * @param {module:core/editor/editor~Editor} editor
929
+ */ logError('ckbox-plugin-image-feature-missing', editor);
878
930
  }
879
931
  }
880
932
  /**
881
- * Extends the schema to allow the `ckboxImageId` and `ckboxLinkId` attributes for links and images.
882
- */ _initSchema() {
933
+ * Extends the schema to allow the `ckboxImageId` and `ckboxLinkId` attributes for links and images.
934
+ */ _initSchema() {
883
935
  const editor = this.editor;
884
936
  const schema = editor.model.schema;
885
937
  schema.extend('$text', {
@@ -909,8 +961,8 @@ class CKBoxEditing extends Plugin {
909
961
  });
910
962
  }
911
963
  /**
912
- * Configures the upcast and downcast conversions for the `ckboxImageId` and `ckboxLinkId` attributes.
913
- */ _initConversion() {
964
+ * Configures the upcast and downcast conversions for the `ckboxImageId` and `ckboxLinkId` attributes.
965
+ */ _initConversion() {
914
966
  const editor = this.editor;
915
967
  // Convert `ckboxLinkId` => `data-ckbox-resource-id`.
916
968
  editor.conversion.for('downcast').add((dispatcher)=>{
@@ -1031,8 +1083,8 @@ class CKBoxEditing extends Plugin {
1031
1083
  }
1032
1084
  }
1033
1085
  /**
1034
- * Registers post-fixers that add or remove the `ckboxLinkId` and `ckboxImageId` attributes.
1035
- */ _initFixers() {
1086
+ * Registers post-fixers that add or remove the `ckboxLinkId` and `ckboxImageId` attributes.
1087
+ */ _initFixers() {
1036
1088
  const editor = this.editor;
1037
1089
  const model = editor.model;
1038
1090
  const selection = model.document.selection;
@@ -1145,15 +1197,27 @@ class CKBoxEditing extends Plugin {
1145
1197
  return !!window.CKBox;
1146
1198
  }
1147
1199
 
1148
- class CKBox extends Plugin {
1200
+ /**
1201
+ * The CKBox feature, a bridge between the CKEditor 5 WYSIWYG editor and the CKBox file manager and uploader.
1202
+ *
1203
+ * This is a "glue" plugin which enables:
1204
+ *
1205
+ * * {@link module:ckbox/ckboxediting~CKBoxEditing},
1206
+ * * {@link module:ckbox/ckboxui~CKBoxUI},
1207
+ *
1208
+ * See the {@glink features/file-management/ckbox CKBox integration} guide to learn how to configure and use this feature.
1209
+ *
1210
+ * Check out the {@glink features/images/image-upload/image-upload Image upload} guide to learn about other ways to upload
1211
+ * images into CKEditor 5.
1212
+ */ class CKBox extends Plugin {
1149
1213
  /**
1150
- * @inheritDoc
1151
- */ static get pluginName() {
1214
+ * @inheritDoc
1215
+ */ static get pluginName() {
1152
1216
  return 'CKBox';
1153
1217
  }
1154
1218
  /**
1155
- * @inheritDoc
1156
- */ static get requires() {
1219
+ * @inheritDoc
1220
+ */ static get requires() {
1157
1221
  return [
1158
1222
  CKBoxEditing,
1159
1223
  CKBoxUI
@@ -1197,18 +1261,43 @@ function createUrlChecker(allowExternalImagesEditing) {
1197
1261
  return ()=>false;
1198
1262
  }
1199
1263
 
1200
- class CKBoxImageEditCommand extends Command {
1264
+ /**
1265
+ * The CKBox edit image command.
1266
+ *
1267
+ * Opens the CKBox dialog for editing the image.
1268
+ */ class CKBoxImageEditCommand extends Command {
1269
+ /**
1270
+ * The DOM element that acts as a mounting point for the CKBox Edit Image dialog.
1271
+ */ _wrapper = null;
1201
1272
  /**
1202
- * @inheritDoc
1203
- */ refresh() {
1273
+ * The states of image processing in progress.
1274
+ */ _processInProgress = new Set();
1275
+ /**
1276
+ * Determines if the element can be edited.
1277
+ */ _canEdit;
1278
+ /**
1279
+ * A wrapper function to prepare mount options. Ensures that at most one preparation is in-flight.
1280
+ */ _prepareOptions;
1281
+ /**
1282
+ * @inheritDoc
1283
+ */ constructor(editor){
1284
+ super(editor);
1285
+ this.value = false;
1286
+ this._canEdit = createEditabilityChecker(editor.config.get('ckbox.allowExternalImagesEditing'));
1287
+ this._prepareOptions = abortableDebounce((signal, state)=>this._prepareOptionsAbortable(signal, state));
1288
+ this._prepareListeners();
1289
+ }
1290
+ /**
1291
+ * @inheritDoc
1292
+ */ refresh() {
1204
1293
  const editor = this.editor;
1205
1294
  this.value = this._getValue();
1206
1295
  const selectedElement = editor.model.document.selection.getSelectedElement();
1207
1296
  this.isEnabled = !!selectedElement && this._canEdit(selectedElement) && !this._checkIfElementIsBeingProcessed(selectedElement);
1208
1297
  }
1209
1298
  /**
1210
- * Opens the CKBox Image Editor dialog for editing the image.
1211
- */ execute() {
1299
+ * Opens the CKBox Image Editor dialog for editing the image.
1300
+ */ execute() {
1212
1301
  if (this._getValue()) {
1213
1302
  return;
1214
1303
  }
@@ -1235,8 +1324,8 @@ class CKBoxImageEditCommand extends Command {
1235
1324
  });
1236
1325
  }
1237
1326
  /**
1238
- * @inheritDoc
1239
- */ destroy() {
1327
+ * @inheritDoc
1328
+ */ destroy() {
1240
1329
  this._handleImageEditorClose();
1241
1330
  this._prepareOptions.abort();
1242
1331
  for (const state of this._processInProgress.values()){
@@ -1245,13 +1334,13 @@ class CKBoxImageEditCommand extends Command {
1245
1334
  super.destroy();
1246
1335
  }
1247
1336
  /**
1248
- * Indicates if the CKBox Image Editor dialog is already opened.
1249
- */ _getValue() {
1337
+ * Indicates if the CKBox Image Editor dialog is already opened.
1338
+ */ _getValue() {
1250
1339
  return this._wrapper !== null;
1251
1340
  }
1252
1341
  /**
1253
- * Creates the options object for the CKBox Image Editor dialog.
1254
- */ async _prepareOptionsAbortable(signal, state) {
1342
+ * Creates the options object for the CKBox Image Editor dialog.
1343
+ */ async _prepareOptionsAbortable(signal, state) {
1255
1344
  const editor = this.editor;
1256
1345
  const ckboxConfig = editor.config.get('ckbox');
1257
1346
  const ckboxUtils = editor.plugins.get(CKBoxUtils);
@@ -1286,8 +1375,8 @@ class CKBoxImageEditCommand extends Command {
1286
1375
  };
1287
1376
  }
1288
1377
  /**
1289
- * Initializes event lister for an event of removing an image.
1290
- */ _prepareListeners() {
1378
+ * Initializes event lister for an event of removing an image.
1379
+ */ _prepareListeners() {
1291
1380
  // Abort editing processing when the image has been removed.
1292
1381
  this.listenTo(this.editor.model.document, 'change:data', ()=>{
1293
1382
  const processingStates = this._getProcessingStatesOfDeletedImages();
@@ -1297,8 +1386,8 @@ class CKBoxImageEditCommand extends Command {
1297
1386
  });
1298
1387
  }
1299
1388
  /**
1300
- * Gets processing states of images that have been deleted in the mean time.
1301
- */ _getProcessingStatesOfDeletedImages() {
1389
+ * Gets processing states of images that have been deleted in the mean time.
1390
+ */ _getProcessingStatesOfDeletedImages() {
1302
1391
  const states = [];
1303
1392
  for (const state of this._processInProgress.values()){
1304
1393
  if (state.element.root.rootName == '$graveyard') {
@@ -1316,8 +1405,8 @@ class CKBoxImageEditCommand extends Command {
1316
1405
  return false;
1317
1406
  }
1318
1407
  /**
1319
- * Closes the CKBox Image Editor dialog.
1320
- */ _handleImageEditorClose() {
1408
+ * Closes the CKBox Image Editor dialog.
1409
+ */ _handleImageEditorClose() {
1321
1410
  if (!this._wrapper) {
1322
1411
  return;
1323
1412
  }
@@ -1327,9 +1416,9 @@ class CKBoxImageEditCommand extends Command {
1327
1416
  this.refresh();
1328
1417
  }
1329
1418
  /**
1330
- * Save edited image. In case server respond with "success" replace with edited image,
1331
- * otherwise show notification error.
1332
- */ _handleImageEditorSave(state, asset) {
1419
+ * Save edited image. In case server respond with "success" replace with edited image,
1420
+ * otherwise show notification error.
1421
+ */ _handleImageEditorSave(state, asset) {
1333
1422
  const t = this.editor.locale.t;
1334
1423
  const notification = this.editor.plugins.get(Notification);
1335
1424
  const pendingActions = this.editor.plugins.get(PendingActions);
@@ -1359,9 +1448,9 @@ class CKBoxImageEditCommand extends Command {
1359
1448
  });
1360
1449
  }
1361
1450
  /**
1362
- * Get asset's status on server. If server responds with "success" status then
1363
- * image is already proceeded and ready for saving.
1364
- */ async _getAssetStatusFromServer(id, signal) {
1451
+ * Get asset's status on server. If server responds with "success" status then
1452
+ * image is already proceeded and ready for saving.
1453
+ */ async _getAssetStatusFromServer(id, signal) {
1365
1454
  const ckboxUtils = this.editor.plugins.get(CKBoxUtils);
1366
1455
  const url = new URL('assets/' + id, this.editor.config.get('ckbox.serviceOrigin'));
1367
1456
  const response = await sendHttpRequest({
@@ -1372,10 +1461,10 @@ class CKBoxImageEditCommand extends Command {
1372
1461
  const status = response.metadata.metadataProcessingStatus;
1373
1462
  if (!status || status == 'queued') {
1374
1463
  /**
1375
- * Image has not been processed yet.
1376
- *
1377
- * @error ckbox-image-not-processed
1378
- */ throw new CKEditorError('ckbox-image-not-processed');
1464
+ * Image has not been processed yet.
1465
+ *
1466
+ * @error ckbox-image-not-processed
1467
+ */ throw new CKEditorError('ckbox-image-not-processed');
1379
1468
  }
1380
1469
  return {
1381
1470
  data: {
@@ -1384,27 +1473,27 @@ class CKBoxImageEditCommand extends Command {
1384
1473
  };
1385
1474
  }
1386
1475
  /**
1387
- * Waits for an asset to be processed.
1388
- * It retries retrieving asset status from the server in case of failure.
1389
- */ async _waitForAssetProcessed(id, signal) {
1476
+ * Waits for an asset to be processed.
1477
+ * It retries retrieving asset status from the server in case of failure.
1478
+ */ async _waitForAssetProcessed(id, signal) {
1390
1479
  const result = await retry(()=>this._getAssetStatusFromServer(id, signal), {
1391
1480
  signal,
1392
1481
  maxAttempts: 5
1393
1482
  });
1394
1483
  if (result.data.metadata.metadataProcessingStatus != 'success') {
1395
1484
  /**
1396
- * The image processing failed.
1397
- *
1398
- * @error ckbox-image-processing-failed
1399
- */ throw new CKEditorError('ckbox-image-processing-failed');
1485
+ * The image processing failed.
1486
+ *
1487
+ * @error ckbox-image-processing-failed
1488
+ */ throw new CKEditorError('ckbox-image-processing-failed');
1400
1489
  }
1401
1490
  return result;
1402
1491
  }
1403
1492
  /**
1404
- * Shows processing indicator while image is processing.
1405
- *
1406
- * @param asset Data about certain asset.
1407
- */ _showImageProcessingIndicator(element, asset) {
1493
+ * Shows processing indicator while image is processing.
1494
+ *
1495
+ * @param asset Data about certain asset.
1496
+ */ _showImageProcessingIndicator(element, asset) {
1408
1497
  const editor = this.editor;
1409
1498
  editor.editing.view.change((writer)=>{
1410
1499
  const imageElementView = editor.editing.mapper.toViewElement(element);
@@ -1419,8 +1508,8 @@ class CKBoxImageEditCommand extends Command {
1419
1508
  });
1420
1509
  }
1421
1510
  /**
1422
- * Replace the edited image with the new one.
1423
- */ _replaceImage(element, asset) {
1511
+ * Replace the edited image with the new one.
1512
+ */ _replaceImage(element, asset) {
1424
1513
  const editor = this.editor;
1425
1514
  const { imageFallbackUrl, imageSources, imageWidth, imageHeight, imagePlaceholder } = prepareImageAssetAttributes(asset);
1426
1515
  const previousSelectionRanges = Array.from(editor.model.document.selection.getRanges());
@@ -1449,32 +1538,19 @@ class CKBoxImageEditCommand extends Command {
1449
1538
  writer.setSelection(previousSelectionRanges);
1450
1539
  });
1451
1540
  }
1452
- /**
1453
- * @inheritDoc
1454
- */ constructor(editor){
1455
- super(editor);
1456
- /**
1457
- * The DOM element that acts as a mounting point for the CKBox Edit Image dialog.
1458
- */ this._wrapper = null;
1459
- /**
1460
- * The states of image processing in progress.
1461
- */ this._processInProgress = new Set();
1462
- this.value = false;
1463
- this._canEdit = createEditabilityChecker(editor.config.get('ckbox.allowExternalImagesEditing'));
1464
- this._prepareOptions = abortableDebounce((signal, state)=>this._prepareOptionsAbortable(signal, state));
1465
- this._prepareListeners();
1466
- }
1467
1541
  }
1468
1542
 
1469
- class CKBoxImageEditEditing extends Plugin {
1543
+ /**
1544
+ * The CKBox image edit editing plugin.
1545
+ */ class CKBoxImageEditEditing extends Plugin {
1470
1546
  /**
1471
- * @inheritDoc
1472
- */ static get pluginName() {
1547
+ * @inheritDoc
1548
+ */ static get pluginName() {
1473
1549
  return 'CKBoxImageEditEditing';
1474
1550
  }
1475
1551
  /**
1476
- * @inheritDoc
1477
- */ static get requires() {
1552
+ * @inheritDoc
1553
+ */ static get requires() {
1478
1554
  return [
1479
1555
  CKBoxEditing,
1480
1556
  CKBoxUtils,
@@ -1485,8 +1561,8 @@ class CKBoxImageEditEditing extends Plugin {
1485
1561
  ];
1486
1562
  }
1487
1563
  /**
1488
- * @inheritDoc
1489
- */ init() {
1564
+ * @inheritDoc
1565
+ */ init() {
1490
1566
  const { editor } = this;
1491
1567
  editor.commands.add('ckboxImageEdit', new CKBoxImageEditCommand(editor));
1492
1568
  }
@@ -1494,15 +1570,20 @@ class CKBoxImageEditEditing extends Plugin {
1494
1570
 
1495
1571
  var ckboxImageEditIcon = "<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>";
1496
1572
 
1497
- class CKBoxImageEditUI extends Plugin {
1573
+ /**
1574
+ * The UI plugin of the CKBox image edit feature.
1575
+ *
1576
+ * It registers the `'ckboxImageEdit'` UI button in the editor's {@link module:ui/componentfactory~ComponentFactory component factory}
1577
+ * that allows you to open the CKBox dialog and edit the image.
1578
+ */ class CKBoxImageEditUI extends Plugin {
1498
1579
  /**
1499
- * @inheritDoc
1500
- */ static get pluginName() {
1580
+ * @inheritDoc
1581
+ */ static get pluginName() {
1501
1582
  return 'CKBoxImageEditUI';
1502
1583
  }
1503
1584
  /**
1504
- * @inheritDoc
1505
- */ init() {
1585
+ * @inheritDoc
1586
+ */ init() {
1506
1587
  const editor = this.editor;
1507
1588
  editor.ui.componentFactory.add('ckboxImageEdit', (locale)=>{
1508
1589
  const command = editor.commands.get('ckboxImageEdit');
@@ -1525,15 +1606,17 @@ class CKBoxImageEditUI extends Plugin {
1525
1606
  }
1526
1607
  }
1527
1608
 
1528
- class CKBoxImageEdit extends Plugin {
1609
+ /**
1610
+ * The CKBox image edit feature.
1611
+ */ class CKBoxImageEdit extends Plugin {
1529
1612
  /**
1530
- * @inheritDoc
1531
- */ static get pluginName() {
1613
+ * @inheritDoc
1614
+ */ static get pluginName() {
1532
1615
  return 'CKBoxImageEdit';
1533
1616
  }
1534
1617
  /**
1535
- * @inheritDoc
1536
- */ static get requires() {
1618
+ * @inheritDoc
1619
+ */ static get requires() {
1537
1620
  return [
1538
1621
  CKBoxImageEditEditing,
1539
1622
  CKBoxImageEditUI