@ckeditor/ckeditor5-ckbox 0.0.0-nightly-20241219.0 → 0.0.0-nightly-20241219.2
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 +294 -267
- package/dist/index.js.map +1 -1
- package/package.json +14 -11
package/dist/index.js
CHANGED
@@ -21,18 +21,18 @@ import { isEqual } from 'lodash-es';
|
|
21
21
|
* It also integrates with the `insertImage` toolbar component and `menuBar:insertImage` menu component.
|
22
22
|
*/ class CKBoxUI extends Plugin {
|
23
23
|
/**
|
24
|
-
|
25
|
-
|
24
|
+
* @inheritDoc
|
25
|
+
*/ static get pluginName() {
|
26
26
|
return 'CKBoxUI';
|
27
27
|
}
|
28
28
|
/**
|
29
|
-
|
30
|
-
|
29
|
+
* @inheritDoc
|
30
|
+
*/ static get isOfficialPlugin() {
|
31
31
|
return true;
|
32
32
|
}
|
33
33
|
/**
|
34
|
-
|
35
|
-
|
34
|
+
* @inheritDoc
|
35
|
+
*/ afterInit() {
|
36
36
|
const editor = this.editor;
|
37
37
|
// Do not register the `ckbox` button if the command does not exist.
|
38
38
|
// This might happen when CKBox library is not loaded on the page.
|
@@ -52,8 +52,8 @@ import { isEqual } from 'lodash-es';
|
|
52
52
|
}
|
53
53
|
}
|
54
54
|
/**
|
55
|
-
|
56
|
-
|
55
|
+
* Creates the base for various kinds of the button component provided by this feature.
|
56
|
+
*/ _createButton(ButtonClass) {
|
57
57
|
const editor = this.editor;
|
58
58
|
const locale = editor.locale;
|
59
59
|
const view = new ButtonClass(locale);
|
@@ -65,8 +65,8 @@ import { isEqual } from 'lodash-es';
|
|
65
65
|
return view;
|
66
66
|
}
|
67
67
|
/**
|
68
|
-
|
69
|
-
|
68
|
+
* Creates a simple toolbar button for files management, with an icon and a tooltip.
|
69
|
+
*/ _createFileToolbarButton() {
|
70
70
|
const t = this.editor.locale.t;
|
71
71
|
const button = this._createButton(ButtonView);
|
72
72
|
button.icon = icons.browseFiles;
|
@@ -75,8 +75,8 @@ import { isEqual } from 'lodash-es';
|
|
75
75
|
return button;
|
76
76
|
}
|
77
77
|
/**
|
78
|
-
|
79
|
-
|
78
|
+
* Creates a simple toolbar button for images management, with an icon and a tooltip.
|
79
|
+
*/ _createImageToolbarButton() {
|
80
80
|
const t = this.editor.locale.t;
|
81
81
|
const imageInsertUI = this.editor.plugins.get('ImageInsertUI');
|
82
82
|
const button = this._createButton(ButtonView);
|
@@ -86,8 +86,8 @@ import { isEqual } from 'lodash-es';
|
|
86
86
|
return button;
|
87
87
|
}
|
88
88
|
/**
|
89
|
-
|
90
|
-
|
89
|
+
* Creates a button for images management for the dropdown view, with an icon, text and no tooltip.
|
90
|
+
*/ _createImageDropdownButton() {
|
91
91
|
const t = this.editor.locale.t;
|
92
92
|
const imageInsertUI = this.editor.plugins.get('ImageInsertUI');
|
93
93
|
const button = this._createButton(ButtonView);
|
@@ -100,8 +100,8 @@ import { isEqual } from 'lodash-es';
|
|
100
100
|
return button;
|
101
101
|
}
|
102
102
|
/**
|
103
|
-
|
104
|
-
|
103
|
+
* Creates a button for files management for the menu bar.
|
104
|
+
*/ _createFileMenuBarButton() {
|
105
105
|
const t = this.editor.locale.t;
|
106
106
|
const button = this._createButton(MenuBarMenuListItemButtonView);
|
107
107
|
button.icon = icons.browseFiles;
|
@@ -110,8 +110,8 @@ import { isEqual } from 'lodash-es';
|
|
110
110
|
return button;
|
111
111
|
}
|
112
112
|
/**
|
113
|
-
|
114
|
-
|
113
|
+
* Creates a button for images management for the menu bar.
|
114
|
+
*/ _createImageMenuBarButton(type) {
|
115
115
|
// Use t() stored in a variable with a different name to reuse existing translations from another package.
|
116
116
|
const translateVariableKey = this.editor.locale.t;
|
117
117
|
const t = this.editor.locale.t;
|
@@ -312,53 +312,53 @@ const ASSET_INSERTION_WAIT_TIMEOUT = 1000;
|
|
312
312
|
* {@link module:link/link~Link Link feature}.
|
313
313
|
*/ class CKBoxCommand extends Command {
|
314
314
|
/**
|
315
|
-
|
316
|
-
|
315
|
+
* A set of all chosen assets. They are stored temporarily and they are automatically removed 1 second after being chosen.
|
316
|
+
* Chosen assets have to be "remembered" for a while to be able to map the given asset with the element inserted into the model.
|
317
|
+
* This association map is then used to set the ID on the model element.
|
318
|
+
*
|
319
|
+
* All chosen assets are automatically removed after the timeout, because (theoretically) it may happen that they will never be
|
320
|
+
* inserted into the model, even if the {@link module:link/linkcommand~LinkCommand `'link'`} command or the
|
321
|
+
* {@link module:image/image/insertimagecommand~InsertImageCommand `'insertImage'`} command is enabled. Such a case may arise when
|
322
|
+
* another plugin blocks the command execution. Then, in order not to keep the chosen (but not inserted) assets forever, we delete
|
323
|
+
* them automatically to prevent memory leakage. The 1 second timeout is enough to insert the asset into the model and extract the
|
324
|
+
* ID from the chosen asset.
|
325
|
+
*
|
326
|
+
* The assets are stored only if
|
327
|
+
* the {@link module:ckbox/ckboxconfig~CKBoxConfig#ignoreDataId `config.ckbox.ignoreDataId`} option is set to `false` (by default).
|
328
|
+
*
|
329
|
+
* @internal
|
330
|
+
*/ _chosenAssets = new Set();
|
331
|
+
/**
|
332
|
+
* The DOM element that acts as a mounting point for the CKBox dialog.
|
333
|
+
*/ _wrapper = null;
|
334
|
+
/**
|
335
|
+
* @inheritDoc
|
336
|
+
*/ constructor(editor){
|
317
337
|
super(editor);
|
318
|
-
/**
|
319
|
-
* A set of all chosen assets. They are stored temporarily and they are automatically removed 1 second after being chosen.
|
320
|
-
* Chosen assets have to be "remembered" for a while to be able to map the given asset with the element inserted into the model.
|
321
|
-
* This association map is then used to set the ID on the model element.
|
322
|
-
*
|
323
|
-
* All chosen assets are automatically removed after the timeout, because (theoretically) it may happen that they will never be
|
324
|
-
* inserted into the model, even if the {@link module:link/linkcommand~LinkCommand `'link'`} command or the
|
325
|
-
* {@link module:image/image/insertimagecommand~InsertImageCommand `'insertImage'`} command is enabled. Such a case may arise when
|
326
|
-
* another plugin blocks the command execution. Then, in order not to keep the chosen (but not inserted) assets forever, we delete
|
327
|
-
* them automatically to prevent memory leakage. The 1 second timeout is enough to insert the asset into the model and extract the
|
328
|
-
* ID from the chosen asset.
|
329
|
-
*
|
330
|
-
* The assets are stored only if
|
331
|
-
* the {@link module:ckbox/ckboxconfig~CKBoxConfig#ignoreDataId `config.ckbox.ignoreDataId`} option is set to `false` (by default).
|
332
|
-
*
|
333
|
-
* @internal
|
334
|
-
*/ this._chosenAssets = new Set();
|
335
|
-
/**
|
336
|
-
* The DOM element that acts as a mounting point for the CKBox dialog.
|
337
|
-
*/ this._wrapper = null;
|
338
338
|
this._initListeners();
|
339
339
|
}
|
340
340
|
/**
|
341
|
-
|
342
|
-
|
341
|
+
* @inheritDoc
|
342
|
+
*/ refresh() {
|
343
343
|
this.value = this._getValue();
|
344
344
|
this.isEnabled = this._checkEnabled();
|
345
345
|
}
|
346
346
|
/**
|
347
|
-
|
348
|
-
|
347
|
+
* @inheritDoc
|
348
|
+
*/ execute() {
|
349
349
|
this.fire('ckbox:open');
|
350
350
|
}
|
351
351
|
/**
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
352
|
+
* Indicates if the CKBox dialog is already opened.
|
353
|
+
*
|
354
|
+
* @protected
|
355
|
+
* @returns {Boolean}
|
356
|
+
*/ _getValue() {
|
357
357
|
return this._wrapper !== null;
|
358
358
|
}
|
359
359
|
/**
|
360
|
-
|
361
|
-
|
360
|
+
* Checks whether the command can be enabled in the current context.
|
361
|
+
*/ _checkEnabled() {
|
362
362
|
const imageCommand = this.editor.commands.get('insertImage');
|
363
363
|
const linkCommand = this.editor.commands.get('link');
|
364
364
|
if (!imageCommand.isEnabled && !linkCommand.isEnabled) {
|
@@ -367,29 +367,29 @@ const ASSET_INSERTION_WAIT_TIMEOUT = 1000;
|
|
367
367
|
return true;
|
368
368
|
}
|
369
369
|
/**
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
370
|
+
* Creates the options object for the CKBox dialog.
|
371
|
+
*
|
372
|
+
* @returns The object with properties:
|
373
|
+
* - theme The theme for CKBox dialog.
|
374
|
+
* - language The language for CKBox dialog.
|
375
|
+
* - tokenUrl The token endpoint URL.
|
376
|
+
* - serviceOrigin The base URL of the API service.
|
377
|
+
* - forceDemoLabel Whether to force "Powered by CKBox" link.
|
378
|
+
* - assets.onChoose The callback function invoked after choosing the assets.
|
379
|
+
* - dialog.onClose The callback function invoked after closing the CKBox dialog.
|
380
|
+
* - dialog.width The dialog width in pixels.
|
381
|
+
* - dialog.height The dialog height in pixels.
|
382
|
+
* - categories.icons Allows setting custom icons for categories.
|
383
|
+
* - view.openLastView Sets if the last view visited by the user will be reopened
|
384
|
+
* on the next startup.
|
385
|
+
* - view.startupFolderId Sets the ID of the folder that will be opened on startup.
|
386
|
+
* - view.startupCategoryId Sets the ID of the category that will be opened on startup.
|
387
|
+
* - view.hideMaximizeButton Sets whether to hide the ‘Maximize’ button.
|
388
|
+
* - view.componentsHideTimeout Sets timeout after which upload components are hidden
|
389
|
+
* after completed upload.
|
390
|
+
* - view.dialogMinimizeTimeout Sets timeout after which upload dialog is minimized
|
391
|
+
* after completed upload.
|
392
|
+
*/ _prepareOptions() {
|
393
393
|
const editor = this.editor;
|
394
394
|
const ckboxConfig = editor.config.get('ckbox');
|
395
395
|
const dialog = ckboxConfig.dialog;
|
@@ -427,8 +427,8 @@ const ASSET_INSERTION_WAIT_TIMEOUT = 1000;
|
|
427
427
|
};
|
428
428
|
}
|
429
429
|
/**
|
430
|
-
|
431
|
-
|
430
|
+
* Initializes various event listeners for the `ckbox:*` events, because all functionality of the `ckbox` command is event-based.
|
431
|
+
*/ _initListeners() {
|
432
432
|
const editor = this.editor;
|
433
433
|
const model = editor.model;
|
434
434
|
const shouldInsertDataId = !editor.config.get('ckbox.ignoreDataId');
|
@@ -497,13 +497,13 @@ const ASSET_INSERTION_WAIT_TIMEOUT = 1000;
|
|
497
497
|
});
|
498
498
|
}
|
499
499
|
/**
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
500
|
+
* Inserts the asset into the model.
|
501
|
+
*
|
502
|
+
* @param asset The asset to be inserted.
|
503
|
+
* @param isLastAsset Indicates if the current asset is the last one from the chosen set.
|
504
|
+
* @param writer An instance of the model writer.
|
505
|
+
* @param isSingleAsset It's true when only one asset is processed.
|
506
|
+
*/ _insertAsset(asset, isLastAsset, writer, isSingleAsset) {
|
507
507
|
const editor = this.editor;
|
508
508
|
const model = editor.model;
|
509
509
|
const selection = model.document.selection;
|
@@ -521,10 +521,10 @@ const ASSET_INSERTION_WAIT_TIMEOUT = 1000;
|
|
521
521
|
}
|
522
522
|
}
|
523
523
|
/**
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
524
|
+
* Inserts the image by calling the `insertImage` command.
|
525
|
+
*
|
526
|
+
* @param asset The asset to be inserted.
|
527
|
+
*/ _insertImage(asset) {
|
528
528
|
const editor = this.editor;
|
529
529
|
const { imageFallbackUrl, imageSources, imageTextAlternative, imageWidth, imageHeight, imagePlaceholder } = asset.attributes;
|
530
530
|
editor.execute('insertImage', {
|
@@ -541,12 +541,12 @@ const ASSET_INSERTION_WAIT_TIMEOUT = 1000;
|
|
541
541
|
});
|
542
542
|
}
|
543
543
|
/**
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
544
|
+
* Inserts the link to the asset by calling the `link` command.
|
545
|
+
*
|
546
|
+
* @param asset The asset to be inserted.
|
547
|
+
* @param writer An instance of the model writer.
|
548
|
+
* @param isSingleAsset It's true when only one asset is processed.
|
549
|
+
*/ _insertLink(asset, writer, isSingleAsset) {
|
550
550
|
const editor = this.editor;
|
551
551
|
const model = editor.model;
|
552
552
|
const selection = model.document.selection;
|
@@ -641,25 +641,28 @@ const DEFAULT_CKBOX_THEME_NAME = 'lark';
|
|
641
641
|
* The CKBox utilities plugin.
|
642
642
|
*/ class CKBoxUtils extends Plugin {
|
643
643
|
/**
|
644
|
-
|
645
|
-
|
644
|
+
* CKEditor Cloud Services access token.
|
645
|
+
*/ _token;
|
646
|
+
/**
|
647
|
+
* @inheritDoc
|
648
|
+
*/ static get pluginName() {
|
646
649
|
return 'CKBoxUtils';
|
647
650
|
}
|
648
651
|
/**
|
649
|
-
|
650
|
-
|
652
|
+
* @inheritDoc
|
653
|
+
*/ static get isOfficialPlugin() {
|
651
654
|
return true;
|
652
655
|
}
|
653
656
|
/**
|
654
|
-
|
655
|
-
|
657
|
+
* @inheritDoc
|
658
|
+
*/ static get requires() {
|
656
659
|
return [
|
657
660
|
'CloudServices'
|
658
661
|
];
|
659
662
|
}
|
660
663
|
/**
|
661
|
-
|
662
|
-
|
664
|
+
* @inheritDoc
|
665
|
+
*/ init() {
|
663
666
|
const editor = this.editor;
|
664
667
|
const hasConfiguration = !!editor.config.get('ckbox');
|
665
668
|
const isLibraryLoaded = !!window.CKBox;
|
@@ -681,22 +684,22 @@ const DEFAULT_CKBOX_THEME_NAME = 'lark';
|
|
681
684
|
const ckboxTokenUrl = editor.config.get('ckbox.tokenUrl');
|
682
685
|
if (!ckboxTokenUrl) {
|
683
686
|
/**
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
687
|
+
* The {@link module:ckbox/ckboxconfig~CKBoxConfig#tokenUrl `config.ckbox.tokenUrl`} or the
|
688
|
+
* {@link module:cloud-services/cloudservicesconfig~CloudServicesConfig#tokenUrl `config.cloudServices.tokenUrl`}
|
689
|
+
* configuration is required for the CKBox plugin.
|
690
|
+
*
|
691
|
+
* ```ts
|
692
|
+
* ClassicEditor.create( document.createElement( 'div' ), {
|
693
|
+
* ckbox: {
|
694
|
+
* tokenUrl: "YOUR_TOKEN_URL"
|
695
|
+
* // ...
|
696
|
+
* }
|
697
|
+
* // ...
|
698
|
+
* } );
|
699
|
+
* ```
|
700
|
+
*
|
701
|
+
* @error ckbox-plugin-missing-token-url
|
702
|
+
*/ throw new CKEditorError('ckbox-plugin-missing-token-url', this);
|
700
703
|
}
|
701
704
|
if (ckboxTokenUrl == cloudServicesTokenUrl) {
|
702
705
|
this._token = Promise.resolve(cloudServices.token);
|
@@ -705,30 +708,30 @@ const DEFAULT_CKBOX_THEME_NAME = 'lark';
|
|
705
708
|
}
|
706
709
|
}
|
707
710
|
/**
|
708
|
-
|
709
|
-
|
711
|
+
* Returns a token used by the CKBox plugin for communication with the CKBox service.
|
712
|
+
*/ getToken() {
|
710
713
|
return this._token;
|
711
714
|
}
|
712
715
|
/**
|
713
|
-
|
714
|
-
|
716
|
+
* The ID of workspace to use when uploading an image.
|
717
|
+
*/ async getWorkspaceId() {
|
715
718
|
const t = this.editor.t;
|
716
719
|
const cannotAccessDefaultWorkspaceError = t('Cannot access default workspace.');
|
717
720
|
const defaultWorkspaceId = this.editor.config.get('ckbox.defaultUploadWorkspaceId');
|
718
721
|
const workspaceId = getWorkspaceId(await this._token, defaultWorkspaceId);
|
719
722
|
if (workspaceId == null) {
|
720
723
|
/**
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
724
|
+
* The user is not authorized to access the workspace defined in the`ckbox.defaultUploadWorkspaceId` configuration.
|
725
|
+
*
|
726
|
+
* @error ckbox-access-default-workspace-error
|
727
|
+
*/ logError('ckbox-access-default-workspace-error');
|
725
728
|
throw cannotAccessDefaultWorkspaceError;
|
726
729
|
}
|
727
730
|
return workspaceId;
|
728
731
|
}
|
729
732
|
/**
|
730
|
-
|
731
|
-
|
733
|
+
* Resolves a promise with an object containing a category with which the uploaded file is associated or an error code.
|
734
|
+
*/ async getCategoryIdForFile(fileOrUrl, options) {
|
732
735
|
const t = this.editor.t;
|
733
736
|
const cannotFindCategoryError = t('Cannot determine a category for the uploaded file.');
|
734
737
|
const defaultCategories = this.editor.config.get('ckbox.defaultUploadCategories');
|
@@ -761,10 +764,10 @@ const DEFAULT_CKBOX_THEME_NAME = 'lark';
|
|
761
764
|
return category.id;
|
762
765
|
}
|
763
766
|
/**
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
767
|
+
* Resolves a promise with an array containing available categories with which the uploaded file can be associated.
|
768
|
+
*
|
769
|
+
* If the API returns limited results, the method will collect all items.
|
770
|
+
*/ async _getAvailableCategories(options) {
|
768
771
|
const ITEMS_PER_REQUEST = 50;
|
769
772
|
const editor = this.editor;
|
770
773
|
const token = this._token;
|
@@ -785,10 +788,10 @@ const DEFAULT_CKBOX_THEME_NAME = 'lark';
|
|
785
788
|
} catch {
|
786
789
|
signal.throwIfAborted();
|
787
790
|
/**
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
791
|
+
* Fetching a list of available categories with which an uploaded file can be associated failed.
|
792
|
+
*
|
793
|
+
* @error ckbox-fetch-category-http-error
|
794
|
+
*/ logError('ckbox-fetch-category-http-error');
|
792
795
|
return undefined;
|
793
796
|
}
|
794
797
|
async function fetchCategories(offset) {
|
@@ -815,8 +818,8 @@ const DEFAULT_CKBOX_THEME_NAME = 'lark';
|
|
815
818
|
* other ways to upload images into CKEditor 5.
|
816
819
|
*/ class CKBoxUploadAdapter extends Plugin {
|
817
820
|
/**
|
818
|
-
|
819
|
-
|
821
|
+
* @inheritDoc
|
822
|
+
*/ static get requires() {
|
820
823
|
return [
|
821
824
|
'ImageUploadEditing',
|
822
825
|
'ImageUploadProgress',
|
@@ -825,18 +828,18 @@ const DEFAULT_CKBOX_THEME_NAME = 'lark';
|
|
825
828
|
];
|
826
829
|
}
|
827
830
|
/**
|
828
|
-
|
829
|
-
|
831
|
+
* @inheritDoc
|
832
|
+
*/ static get pluginName() {
|
830
833
|
return 'CKBoxUploadAdapter';
|
831
834
|
}
|
832
835
|
/**
|
833
|
-
|
834
|
-
|
836
|
+
* @inheritDoc
|
837
|
+
*/ static get isOfficialPlugin() {
|
835
838
|
return true;
|
836
839
|
}
|
837
840
|
/**
|
838
|
-
|
839
|
-
|
841
|
+
* @inheritDoc
|
842
|
+
*/ async afterInit() {
|
840
843
|
const editor = this.editor;
|
841
844
|
const hasConfiguration = !!editor.config.get('ckbox');
|
842
845
|
const isLibraryLoaded = !!window.CKBox;
|
@@ -865,8 +868,26 @@ const DEFAULT_CKBOX_THEME_NAME = 'lark';
|
|
865
868
|
* Upload adapter for CKBox.
|
866
869
|
*/ class Adapter {
|
867
870
|
/**
|
868
|
-
|
869
|
-
|
871
|
+
* FileLoader instance to use during the upload.
|
872
|
+
*/ loader;
|
873
|
+
/**
|
874
|
+
* CKEditor Cloud Services access token.
|
875
|
+
*/ token;
|
876
|
+
/**
|
877
|
+
* The editor instance.
|
878
|
+
*/ editor;
|
879
|
+
/**
|
880
|
+
* The abort controller for aborting asynchronous processes.
|
881
|
+
*/ controller;
|
882
|
+
/**
|
883
|
+
* The base URL where all requests should be sent.
|
884
|
+
*/ serviceOrigin;
|
885
|
+
/**
|
886
|
+
* The reference to CKBoxUtils plugin.
|
887
|
+
*/ ckboxUtils;
|
888
|
+
/**
|
889
|
+
* Creates a new adapter instance.
|
890
|
+
*/ constructor(loader, editor, ckboxUtils){
|
870
891
|
this.loader = loader;
|
871
892
|
this.token = ckboxUtils.getToken();
|
872
893
|
this.ckboxUtils = ckboxUtils;
|
@@ -875,10 +896,10 @@ const DEFAULT_CKBOX_THEME_NAME = 'lark';
|
|
875
896
|
this.serviceOrigin = editor.config.get('ckbox.serviceOrigin');
|
876
897
|
}
|
877
898
|
/**
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
899
|
+
* Starts the upload process.
|
900
|
+
*
|
901
|
+
* @see module:upload/filerepository~UploadAdapter#upload
|
902
|
+
*/ async upload() {
|
882
903
|
const ckboxUtils = this.ckboxUtils;
|
883
904
|
const t = this.editor.t;
|
884
905
|
const file = await this.loader.file;
|
@@ -916,10 +937,10 @@ const DEFAULT_CKBOX_THEME_NAME = 'lark';
|
|
916
937
|
});
|
917
938
|
}
|
918
939
|
/**
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
940
|
+
* Aborts the upload process.
|
941
|
+
*
|
942
|
+
* @see module:upload/filerepository~UploadAdapter#abort
|
943
|
+
*/ abort() {
|
923
944
|
this.controller.abort();
|
924
945
|
}
|
925
946
|
}
|
@@ -930,18 +951,18 @@ const COMMAND_FORCE_DISABLE_ID = 'NoPermission';
|
|
930
951
|
* {@link module:ckbox/ckboxuploadadapter~CKBoxUploadAdapter CKBox upload adapter}.
|
931
952
|
*/ class CKBoxEditing extends Plugin {
|
932
953
|
/**
|
933
|
-
|
934
|
-
|
954
|
+
* @inheritDoc
|
955
|
+
*/ static get pluginName() {
|
935
956
|
return 'CKBoxEditing';
|
936
957
|
}
|
937
958
|
/**
|
938
|
-
|
939
|
-
|
959
|
+
* @inheritDoc
|
960
|
+
*/ static get isOfficialPlugin() {
|
940
961
|
return true;
|
941
962
|
}
|
942
963
|
/**
|
943
|
-
|
944
|
-
|
964
|
+
* @inheritDoc
|
965
|
+
*/ static get requires() {
|
945
966
|
return [
|
946
967
|
'LinkEditing',
|
947
968
|
'PictureEditing',
|
@@ -950,8 +971,8 @@ const COMMAND_FORCE_DISABLE_ID = 'NoPermission';
|
|
950
971
|
];
|
951
972
|
}
|
952
973
|
/**
|
953
|
-
|
954
|
-
|
974
|
+
* @inheritDoc
|
975
|
+
*/ init() {
|
955
976
|
const editor = this.editor;
|
956
977
|
if (!this._shouldBeInitialised()) {
|
957
978
|
return;
|
@@ -969,8 +990,8 @@ const COMMAND_FORCE_DISABLE_ID = 'NoPermission';
|
|
969
990
|
});
|
970
991
|
}
|
971
992
|
/**
|
972
|
-
|
973
|
-
|
993
|
+
* @inheritDoc
|
994
|
+
*/ afterInit() {
|
974
995
|
const editor = this.editor;
|
975
996
|
if (!this._shouldBeInitialised()) {
|
976
997
|
return;
|
@@ -984,16 +1005,16 @@ const COMMAND_FORCE_DISABLE_ID = 'NoPermission';
|
|
984
1005
|
}
|
985
1006
|
}
|
986
1007
|
/**
|
987
|
-
|
988
|
-
|
989
|
-
|
1008
|
+
* Returns true only when the integrator intentionally wants to use the plugin, i.e. when the `config.ckbox` exists or
|
1009
|
+
* the CKBox JavaScript library is loaded.
|
1010
|
+
*/ _shouldBeInitialised() {
|
990
1011
|
const editor = this.editor;
|
991
1012
|
const hasConfiguration = !!editor.config.get('ckbox');
|
992
1013
|
return hasConfiguration || isLibraryLoaded();
|
993
1014
|
}
|
994
1015
|
/**
|
995
|
-
|
996
|
-
|
1016
|
+
* Blocks `uploadImage` and `ckboxImageEdit` commands.
|
1017
|
+
*/ _blockImageCommands() {
|
997
1018
|
const editor = this.editor;
|
998
1019
|
const uploadImageCommand = editor.commands.get('uploadImage');
|
999
1020
|
const imageEditingCommand = editor.commands.get('ckboxImageEdit');
|
@@ -1006,27 +1027,27 @@ const COMMAND_FORCE_DISABLE_ID = 'NoPermission';
|
|
1006
1027
|
}
|
1007
1028
|
}
|
1008
1029
|
/**
|
1009
|
-
|
1010
|
-
|
1030
|
+
* Checks if at least one image plugin is loaded.
|
1031
|
+
*/ _checkImagePlugins() {
|
1011
1032
|
const editor = this.editor;
|
1012
1033
|
if (!editor.plugins.has('ImageBlockEditing') && !editor.plugins.has('ImageInlineEditing')) {
|
1013
1034
|
/**
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1035
|
+
* The CKBox feature requires one of the following plugins to be loaded to work correctly:
|
1036
|
+
*
|
1037
|
+
* * {@link module:image/imageblock~ImageBlock},
|
1038
|
+
* * {@link module:image/imageinline~ImageInline},
|
1039
|
+
* * {@link module:image/image~Image} (loads both `ImageBlock` and `ImageInline`)
|
1040
|
+
*
|
1041
|
+
* Please make sure your editor configuration is correct.
|
1042
|
+
*
|
1043
|
+
* @error ckbox-plugin-image-feature-missing
|
1044
|
+
* @param {module:core/editor/editor~Editor} editor
|
1045
|
+
*/ logError('ckbox-plugin-image-feature-missing', editor);
|
1025
1046
|
}
|
1026
1047
|
}
|
1027
1048
|
/**
|
1028
|
-
|
1029
|
-
|
1049
|
+
* Extends the schema to allow the `ckboxImageId` and `ckboxLinkId` attributes for links and images.
|
1050
|
+
*/ _initSchema() {
|
1030
1051
|
const editor = this.editor;
|
1031
1052
|
const schema = editor.model.schema;
|
1032
1053
|
schema.extend('$text', {
|
@@ -1056,8 +1077,8 @@ const COMMAND_FORCE_DISABLE_ID = 'NoPermission';
|
|
1056
1077
|
}, 'ckboxLinkId');
|
1057
1078
|
}
|
1058
1079
|
/**
|
1059
|
-
|
1060
|
-
|
1080
|
+
* Configures the upcast and downcast conversions for the `ckboxImageId` and `ckboxLinkId` attributes.
|
1081
|
+
*/ _initConversion() {
|
1061
1082
|
const editor = this.editor;
|
1062
1083
|
// Convert `ckboxLinkId` => `data-ckbox-resource-id`.
|
1063
1084
|
editor.conversion.for('downcast').add((dispatcher)=>{
|
@@ -1178,8 +1199,8 @@ const COMMAND_FORCE_DISABLE_ID = 'NoPermission';
|
|
1178
1199
|
}
|
1179
1200
|
}
|
1180
1201
|
/**
|
1181
|
-
|
1182
|
-
|
1202
|
+
* Registers post-fixers that add or remove the `ckboxLinkId` and `ckboxImageId` attributes.
|
1203
|
+
*/ _initFixers() {
|
1183
1204
|
const editor = this.editor;
|
1184
1205
|
const model = editor.model;
|
1185
1206
|
const selection = model.document.selection;
|
@@ -1320,18 +1341,18 @@ const COMMAND_FORCE_DISABLE_ID = 'NoPermission';
|
|
1320
1341
|
* images into CKEditor 5.
|
1321
1342
|
*/ class CKBox extends Plugin {
|
1322
1343
|
/**
|
1323
|
-
|
1324
|
-
|
1344
|
+
* @inheritDoc
|
1345
|
+
*/ static get pluginName() {
|
1325
1346
|
return 'CKBox';
|
1326
1347
|
}
|
1327
1348
|
/**
|
1328
|
-
|
1329
|
-
|
1349
|
+
* @inheritDoc
|
1350
|
+
*/ static get isOfficialPlugin() {
|
1330
1351
|
return true;
|
1331
1352
|
}
|
1332
1353
|
/**
|
1333
|
-
|
1334
|
-
|
1354
|
+
* @inheritDoc
|
1355
|
+
*/ static get requires() {
|
1335
1356
|
return [
|
1336
1357
|
CKBoxEditing,
|
1337
1358
|
CKBoxUI
|
@@ -1381,38 +1402,44 @@ function createUrlChecker(allowExternalImagesEditing) {
|
|
1381
1402
|
* Opens the CKBox dialog for editing the image.
|
1382
1403
|
*/ class CKBoxImageEditCommand extends Command {
|
1383
1404
|
/**
|
1384
|
-
|
1385
|
-
|
1405
|
+
* The DOM element that acts as a mounting point for the CKBox Edit Image dialog.
|
1406
|
+
*/ _wrapper = null;
|
1407
|
+
/**
|
1408
|
+
* The states of image processing in progress.
|
1409
|
+
*/ _processInProgress = new Set();
|
1410
|
+
/**
|
1411
|
+
* Determines if the element can be edited.
|
1412
|
+
*/ _canEdit;
|
1413
|
+
/**
|
1414
|
+
* A wrapper function to prepare mount options. Ensures that at most one preparation is in-flight.
|
1415
|
+
*/ _prepareOptions;
|
1416
|
+
/**
|
1417
|
+
* CKBox's onClose function runs before the final cleanup, potentially causing
|
1418
|
+
* page layout changes after it finishes. To address this, we use a setTimeout hack
|
1419
|
+
* to ensure that floating elements on the page maintain their correct position.
|
1420
|
+
*
|
1421
|
+
* See: https://github.com/ckeditor/ckeditor5/issues/16153.
|
1422
|
+
*/ _updateUiDelayed = delay(()=>this.editor.ui.update(), 0);
|
1423
|
+
/**
|
1424
|
+
* @inheritDoc
|
1425
|
+
*/ constructor(editor){
|
1386
1426
|
super(editor);
|
1387
|
-
/**
|
1388
|
-
* The DOM element that acts as a mounting point for the CKBox Edit Image dialog.
|
1389
|
-
*/ this._wrapper = null;
|
1390
|
-
/**
|
1391
|
-
* The states of image processing in progress.
|
1392
|
-
*/ this._processInProgress = new Set();
|
1393
|
-
/**
|
1394
|
-
* CKBox's onClose function runs before the final cleanup, potentially causing
|
1395
|
-
* page layout changes after it finishes. To address this, we use a setTimeout hack
|
1396
|
-
* to ensure that floating elements on the page maintain their correct position.
|
1397
|
-
*
|
1398
|
-
* See: https://github.com/ckeditor/ckeditor5/issues/16153.
|
1399
|
-
*/ this._updateUiDelayed = delay(()=>this.editor.ui.update(), 0);
|
1400
1427
|
this.value = false;
|
1401
1428
|
this._canEdit = createEditabilityChecker(editor.config.get('ckbox.allowExternalImagesEditing'));
|
1402
1429
|
this._prepareOptions = abortableDebounce((signal, state)=>this._prepareOptionsAbortable(signal, state));
|
1403
1430
|
this._prepareListeners();
|
1404
1431
|
}
|
1405
1432
|
/**
|
1406
|
-
|
1407
|
-
|
1433
|
+
* @inheritDoc
|
1434
|
+
*/ refresh() {
|
1408
1435
|
const editor = this.editor;
|
1409
1436
|
this.value = this._getValue();
|
1410
1437
|
const selectedElement = editor.model.document.selection.getSelectedElement();
|
1411
1438
|
this.isEnabled = !!selectedElement && this._canEdit(selectedElement) && !this._checkIfElementIsBeingProcessed(selectedElement);
|
1412
1439
|
}
|
1413
1440
|
/**
|
1414
|
-
|
1415
|
-
|
1441
|
+
* Opens the CKBox Image Editor dialog for editing the image.
|
1442
|
+
*/ execute() {
|
1416
1443
|
if (this._getValue()) {
|
1417
1444
|
return;
|
1418
1445
|
}
|
@@ -1439,8 +1466,8 @@ function createUrlChecker(allowExternalImagesEditing) {
|
|
1439
1466
|
});
|
1440
1467
|
}
|
1441
1468
|
/**
|
1442
|
-
|
1443
|
-
|
1469
|
+
* @inheritDoc
|
1470
|
+
*/ destroy() {
|
1444
1471
|
this._handleImageEditorClose();
|
1445
1472
|
this._prepareOptions.abort();
|
1446
1473
|
this._updateUiDelayed.cancel();
|
@@ -1450,13 +1477,13 @@ function createUrlChecker(allowExternalImagesEditing) {
|
|
1450
1477
|
super.destroy();
|
1451
1478
|
}
|
1452
1479
|
/**
|
1453
|
-
|
1454
|
-
|
1480
|
+
* Indicates if the CKBox Image Editor dialog is already opened.
|
1481
|
+
*/ _getValue() {
|
1455
1482
|
return this._wrapper !== null;
|
1456
1483
|
}
|
1457
1484
|
/**
|
1458
|
-
|
1459
|
-
|
1485
|
+
* Creates the options object for the CKBox Image Editor dialog.
|
1486
|
+
*/ async _prepareOptionsAbortable(signal, state) {
|
1460
1487
|
const editor = this.editor;
|
1461
1488
|
const ckboxConfig = editor.config.get('ckbox');
|
1462
1489
|
const ckboxUtils = editor.plugins.get(CKBoxUtils);
|
@@ -1491,8 +1518,8 @@ function createUrlChecker(allowExternalImagesEditing) {
|
|
1491
1518
|
};
|
1492
1519
|
}
|
1493
1520
|
/**
|
1494
|
-
|
1495
|
-
|
1521
|
+
* Initializes event lister for an event of removing an image.
|
1522
|
+
*/ _prepareListeners() {
|
1496
1523
|
// Abort editing processing when the image has been removed.
|
1497
1524
|
this.listenTo(this.editor.model.document, 'change:data', ()=>{
|
1498
1525
|
const processingStates = this._getProcessingStatesOfDeletedImages();
|
@@ -1502,8 +1529,8 @@ function createUrlChecker(allowExternalImagesEditing) {
|
|
1502
1529
|
});
|
1503
1530
|
}
|
1504
1531
|
/**
|
1505
|
-
|
1506
|
-
|
1532
|
+
* Gets processing states of images that have been deleted in the mean time.
|
1533
|
+
*/ _getProcessingStatesOfDeletedImages() {
|
1507
1534
|
const states = [];
|
1508
1535
|
for (const state of this._processInProgress.values()){
|
1509
1536
|
if (state.element.root.rootName == '$graveyard') {
|
@@ -1521,8 +1548,8 @@ function createUrlChecker(allowExternalImagesEditing) {
|
|
1521
1548
|
return false;
|
1522
1549
|
}
|
1523
1550
|
/**
|
1524
|
-
|
1525
|
-
|
1551
|
+
* Closes the CKBox Image Editor dialog.
|
1552
|
+
*/ _handleImageEditorClose() {
|
1526
1553
|
if (!this._wrapper) {
|
1527
1554
|
return;
|
1528
1555
|
}
|
@@ -1533,9 +1560,9 @@ function createUrlChecker(allowExternalImagesEditing) {
|
|
1533
1560
|
this.refresh();
|
1534
1561
|
}
|
1535
1562
|
/**
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1563
|
+
* Save edited image. In case server respond with "success" replace with edited image,
|
1564
|
+
* otherwise show notification error.
|
1565
|
+
*/ _handleImageEditorSave(state, asset) {
|
1539
1566
|
const t = this.editor.locale.t;
|
1540
1567
|
const notification = this.editor.plugins.get(Notification);
|
1541
1568
|
const pendingActions = this.editor.plugins.get(PendingActions);
|
@@ -1565,9 +1592,9 @@ function createUrlChecker(allowExternalImagesEditing) {
|
|
1565
1592
|
});
|
1566
1593
|
}
|
1567
1594
|
/**
|
1568
|
-
|
1569
|
-
|
1570
|
-
|
1595
|
+
* Get asset's status on server. If server responds with "success" status then
|
1596
|
+
* image is already proceeded and ready for saving.
|
1597
|
+
*/ async _getAssetStatusFromServer(id, signal) {
|
1571
1598
|
const ckboxUtils = this.editor.plugins.get(CKBoxUtils);
|
1572
1599
|
const url = new URL('assets/' + id, this.editor.config.get('ckbox.serviceOrigin'));
|
1573
1600
|
const response = await sendHttpRequest({
|
@@ -1578,10 +1605,10 @@ function createUrlChecker(allowExternalImagesEditing) {
|
|
1578
1605
|
const status = response.metadata.metadataProcessingStatus;
|
1579
1606
|
if (!status || status == 'queued') {
|
1580
1607
|
/**
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1608
|
+
* Image has not been processed yet.
|
1609
|
+
*
|
1610
|
+
* @error ckbox-image-not-processed
|
1611
|
+
*/ throw new CKEditorError('ckbox-image-not-processed');
|
1585
1612
|
}
|
1586
1613
|
return {
|
1587
1614
|
data: {
|
@@ -1590,27 +1617,27 @@ function createUrlChecker(allowExternalImagesEditing) {
|
|
1590
1617
|
};
|
1591
1618
|
}
|
1592
1619
|
/**
|
1593
|
-
|
1594
|
-
|
1595
|
-
|
1620
|
+
* Waits for an asset to be processed.
|
1621
|
+
* It retries retrieving asset status from the server in case of failure.
|
1622
|
+
*/ async _waitForAssetProcessed(id, signal) {
|
1596
1623
|
const result = await retry(()=>this._getAssetStatusFromServer(id, signal), {
|
1597
1624
|
signal,
|
1598
1625
|
maxAttempts: 5
|
1599
1626
|
});
|
1600
1627
|
if (result.data.metadata.metadataProcessingStatus != 'success') {
|
1601
1628
|
/**
|
1602
|
-
|
1603
|
-
|
1604
|
-
|
1605
|
-
|
1629
|
+
* The image processing failed.
|
1630
|
+
*
|
1631
|
+
* @error ckbox-image-processing-failed
|
1632
|
+
*/ throw new CKEditorError('ckbox-image-processing-failed');
|
1606
1633
|
}
|
1607
1634
|
return result;
|
1608
1635
|
}
|
1609
1636
|
/**
|
1610
|
-
|
1611
|
-
|
1612
|
-
|
1613
|
-
|
1637
|
+
* Shows processing indicator while image is processing.
|
1638
|
+
*
|
1639
|
+
* @param asset Data about certain asset.
|
1640
|
+
*/ _showImageProcessingIndicator(element, asset) {
|
1614
1641
|
const editor = this.editor;
|
1615
1642
|
editor.editing.view.change((writer)=>{
|
1616
1643
|
const imageElementView = editor.editing.mapper.toViewElement(element);
|
@@ -1625,8 +1652,8 @@ function createUrlChecker(allowExternalImagesEditing) {
|
|
1625
1652
|
});
|
1626
1653
|
}
|
1627
1654
|
/**
|
1628
|
-
|
1629
|
-
|
1655
|
+
* Replace the edited image with the new one.
|
1656
|
+
*/ _replaceImage(element, asset) {
|
1630
1657
|
const editor = this.editor;
|
1631
1658
|
const { imageFallbackUrl, imageSources, imageWidth, imageHeight, imagePlaceholder } = prepareImageAssetAttributes(asset);
|
1632
1659
|
const previousSelectionRanges = Array.from(editor.model.document.selection.getRanges());
|
@@ -1662,18 +1689,18 @@ function createUrlChecker(allowExternalImagesEditing) {
|
|
1662
1689
|
* The CKBox image edit editing plugin.
|
1663
1690
|
*/ class CKBoxImageEditEditing extends Plugin {
|
1664
1691
|
/**
|
1665
|
-
|
1666
|
-
|
1692
|
+
* @inheritDoc
|
1693
|
+
*/ static get pluginName() {
|
1667
1694
|
return 'CKBoxImageEditEditing';
|
1668
1695
|
}
|
1669
1696
|
/**
|
1670
|
-
|
1671
|
-
|
1697
|
+
* @inheritDoc
|
1698
|
+
*/ static get isOfficialPlugin() {
|
1672
1699
|
return true;
|
1673
1700
|
}
|
1674
1701
|
/**
|
1675
|
-
|
1676
|
-
|
1702
|
+
* @inheritDoc
|
1703
|
+
*/ static get requires() {
|
1677
1704
|
return [
|
1678
1705
|
CKBoxEditing,
|
1679
1706
|
CKBoxUtils,
|
@@ -1684,8 +1711,8 @@ function createUrlChecker(allowExternalImagesEditing) {
|
|
1684
1711
|
];
|
1685
1712
|
}
|
1686
1713
|
/**
|
1687
|
-
|
1688
|
-
|
1714
|
+
* @inheritDoc
|
1715
|
+
*/ init() {
|
1689
1716
|
const { editor } = this;
|
1690
1717
|
editor.commands.add('ckboxImageEdit', new CKBoxImageEditCommand(editor));
|
1691
1718
|
}
|
@@ -1700,18 +1727,18 @@ var ckboxImageEditIcon = "<svg viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2
|
|
1700
1727
|
* that allows you to open the CKBox dialog and edit the image.
|
1701
1728
|
*/ class CKBoxImageEditUI extends Plugin {
|
1702
1729
|
/**
|
1703
|
-
|
1704
|
-
|
1730
|
+
* @inheritDoc
|
1731
|
+
*/ static get pluginName() {
|
1705
1732
|
return 'CKBoxImageEditUI';
|
1706
1733
|
}
|
1707
1734
|
/**
|
1708
|
-
|
1709
|
-
|
1735
|
+
* @inheritDoc
|
1736
|
+
*/ static get isOfficialPlugin() {
|
1710
1737
|
return true;
|
1711
1738
|
}
|
1712
1739
|
/**
|
1713
|
-
|
1714
|
-
|
1740
|
+
* @inheritDoc
|
1741
|
+
*/ init() {
|
1715
1742
|
const editor = this.editor;
|
1716
1743
|
editor.ui.componentFactory.add('ckboxImageEdit', (locale)=>{
|
1717
1744
|
const command = editor.commands.get('ckboxImageEdit');
|
@@ -1739,18 +1766,18 @@ var ckboxImageEditIcon = "<svg viewBox=\"0 0 20 20\" xmlns=\"http://www.w3.org/2
|
|
1739
1766
|
* The CKBox image edit feature.
|
1740
1767
|
*/ class CKBoxImageEdit extends Plugin {
|
1741
1768
|
/**
|
1742
|
-
|
1743
|
-
|
1769
|
+
* @inheritDoc
|
1770
|
+
*/ static get pluginName() {
|
1744
1771
|
return 'CKBoxImageEdit';
|
1745
1772
|
}
|
1746
1773
|
/**
|
1747
|
-
|
1748
|
-
|
1774
|
+
* @inheritDoc
|
1775
|
+
*/ static get isOfficialPlugin() {
|
1749
1776
|
return true;
|
1750
1777
|
}
|
1751
1778
|
/**
|
1752
|
-
|
1753
|
-
|
1779
|
+
* @inheritDoc
|
1780
|
+
*/ static get requires() {
|
1754
1781
|
return [
|
1755
1782
|
CKBoxImageEditEditing,
|
1756
1783
|
CKBoxImageEditUI
|