@ckeditor/ckeditor5-ckbox 41.4.2 → 42.0.0-alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +6 -0
- package/build/ckbox.js +1 -1
- package/dist/index.js +419 -282
- package/dist/index.js.map +1 -1
- package/dist/types/ckboximageedit/ckboximageeditcommand.d.ts +8 -0
- package/dist/types/ckboxui.d.ts +29 -2
- package/package.json +2 -2
- package/src/ckboximageedit/ckboximageeditcommand.d.ts +8 -0
- package/src/ckboximageedit/ckboximageeditcommand.js +11 -1
- package/src/ckboxui.d.ts +29 -2
- package/src/ckboxui.js +82 -36
package/dist/index.js
CHANGED
@@ -5,76 +5,123 @@
|
|
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,
|
8
|
+
import { createElement, toMap, CKEditorError, logError, global, delay, 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
|
-
|
13
|
+
/**
|
14
|
+
* Introduces UI components for the `CKBox` plugin.
|
15
|
+
*
|
16
|
+
* The plugin introduces two UI components to the {@link module:ui/componentfactory~ComponentFactory UI component factory}:
|
17
|
+
*
|
18
|
+
* * the `'ckbox'` toolbar button,
|
19
|
+
* * the `'menuBar:ckbox'` menu bar component, which is by default added to the `'Insert'` menu.
|
20
|
+
*
|
21
|
+
* It also integrates with the `insertImage` toolbar component and `menuBar:insertImage` menu component.
|
22
|
+
*/ class CKBoxUI extends Plugin {
|
14
23
|
/**
|
15
|
-
|
16
|
-
|
24
|
+
* @inheritDoc
|
25
|
+
*/ static get pluginName() {
|
17
26
|
return 'CKBoxUI';
|
18
27
|
}
|
19
28
|
/**
|
20
|
-
|
21
|
-
|
29
|
+
* @inheritDoc
|
30
|
+
*/ afterInit() {
|
22
31
|
const editor = this.editor;
|
23
32
|
// Do not register the `ckbox` button if the command does not exist.
|
24
33
|
// This might happen when CKBox library is not loaded on the page.
|
25
34
|
if (!editor.commands.get('ckbox')) {
|
26
35
|
return;
|
27
36
|
}
|
28
|
-
|
29
|
-
|
30
|
-
componentFactory.add('ckbox', ()=>{
|
31
|
-
const button = this._createButton(ButtonView);
|
32
|
-
button.tooltip = true;
|
33
|
-
return button;
|
34
|
-
});
|
35
|
-
componentFactory.add('menuBar:ckbox', ()=>this._createButton(MenuBarMenuListItemButtonView));
|
37
|
+
editor.ui.componentFactory.add('ckbox', ()=>this._createFileToolbarButton());
|
38
|
+
editor.ui.componentFactory.add('menuBar:ckbox', ()=>this._createFileMenuBarButton());
|
36
39
|
if (editor.plugins.has('ImageInsertUI')) {
|
37
|
-
|
38
|
-
imageInsertUI.registerIntegration({
|
40
|
+
editor.plugins.get('ImageInsertUI').registerIntegration({
|
39
41
|
name: 'assetManager',
|
40
42
|
observable: ()=>editor.commands.get('ckbox'),
|
41
|
-
buttonViewCreator: ()=>
|
42
|
-
|
43
|
-
|
44
|
-
button.bind('label').to(imageInsertUI, 'isImageSelected', (isImageSelected)=>isImageSelected ? t('Replace image with file manager') : t('Insert image with file manager'));
|
45
|
-
return button;
|
46
|
-
},
|
47
|
-
formViewCreator: ()=>{
|
48
|
-
const button = this.editor.ui.componentFactory.create('ckbox');
|
49
|
-
button.icon = icons.imageAssetManager;
|
50
|
-
button.withText = true;
|
51
|
-
button.bind('label').to(imageInsertUI, 'isImageSelected', (isImageSelected)=>isImageSelected ? t('Replace with file manager') : t('Insert with file manager'));
|
52
|
-
button.on('execute', ()=>{
|
53
|
-
imageInsertUI.dropdownView.isOpen = false;
|
54
|
-
});
|
55
|
-
return button;
|
56
|
-
}
|
43
|
+
buttonViewCreator: ()=>this._createImageToolbarButton(),
|
44
|
+
formViewCreator: ()=>this._createImageDropdownButton(),
|
45
|
+
menuBarButtonViewCreator: (isOnly)=>this._createImageMenuBarButton(isOnly ? 'insertOnly' : 'insertNested')
|
57
46
|
});
|
58
47
|
}
|
59
48
|
}
|
60
49
|
/**
|
61
|
-
|
62
|
-
|
50
|
+
* Creates the base for various kinds of the button component provided by this feature.
|
51
|
+
*/ _createButton(ButtonClass) {
|
63
52
|
const editor = this.editor;
|
64
53
|
const locale = editor.locale;
|
65
54
|
const view = new ButtonClass(locale);
|
66
55
|
const command = editor.commands.get('ckbox');
|
67
|
-
|
68
|
-
view.set({
|
69
|
-
label: t('Open file manager'),
|
70
|
-
icon: icons.browseFiles
|
71
|
-
});
|
56
|
+
locale.t;
|
72
57
|
view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');
|
73
58
|
view.on('execute', ()=>{
|
74
59
|
editor.execute('ckbox');
|
75
60
|
});
|
76
61
|
return view;
|
77
62
|
}
|
63
|
+
/**
|
64
|
+
* Creates a simple toolbar button for files management, with an icon and a tooltip.
|
65
|
+
*/ _createFileToolbarButton() {
|
66
|
+
const t = this.editor.locale.t;
|
67
|
+
const button = this._createButton(ButtonView);
|
68
|
+
button.icon = icons.browseFiles;
|
69
|
+
button.label = t('Open file manager');
|
70
|
+
button.tooltip = true;
|
71
|
+
return button;
|
72
|
+
}
|
73
|
+
/**
|
74
|
+
* Creates a simple toolbar button for images management, with an icon and a tooltip.
|
75
|
+
*/ _createImageToolbarButton() {
|
76
|
+
const t = this.editor.locale.t;
|
77
|
+
const imageInsertUI = this.editor.plugins.get('ImageInsertUI');
|
78
|
+
const button = this._createButton(ButtonView);
|
79
|
+
button.icon = icons.imageAssetManager;
|
80
|
+
button.bind('label').to(imageInsertUI, 'isImageSelected', (isImageSelected)=>isImageSelected ? t('Replace image with file manager') : t('Insert image with file manager'));
|
81
|
+
button.tooltip = true;
|
82
|
+
return button;
|
83
|
+
}
|
84
|
+
/**
|
85
|
+
* Creates a button for images management for the dropdown view, with an icon, text and no tooltip.
|
86
|
+
*/ _createImageDropdownButton() {
|
87
|
+
const t = this.editor.locale.t;
|
88
|
+
const imageInsertUI = this.editor.plugins.get('ImageInsertUI');
|
89
|
+
const button = this._createButton(ButtonView);
|
90
|
+
button.icon = icons.imageAssetManager;
|
91
|
+
button.withText = true;
|
92
|
+
button.bind('label').to(imageInsertUI, 'isImageSelected', (isImageSelected)=>isImageSelected ? t('Replace with file manager') : t('Insert with file manager'));
|
93
|
+
button.on('execute', ()=>{
|
94
|
+
imageInsertUI.dropdownView.isOpen = false;
|
95
|
+
});
|
96
|
+
return button;
|
97
|
+
}
|
98
|
+
/**
|
99
|
+
* Creates a button for files management for the menu bar.
|
100
|
+
*/ _createFileMenuBarButton() {
|
101
|
+
const t = this.editor.locale.t;
|
102
|
+
const button = this._createButton(MenuBarMenuListItemButtonView);
|
103
|
+
button.icon = icons.browseFiles;
|
104
|
+
button.withText = true;
|
105
|
+
button.label = t('File');
|
106
|
+
return button;
|
107
|
+
}
|
108
|
+
/**
|
109
|
+
* Creates a button for images management for the menu bar.
|
110
|
+
*/ _createImageMenuBarButton(type) {
|
111
|
+
const t = this.editor.locale.t;
|
112
|
+
const button = this._createButton(MenuBarMenuListItemButtonView);
|
113
|
+
button.icon = icons.imageAssetManager;
|
114
|
+
button.withText = true;
|
115
|
+
switch(type){
|
116
|
+
case 'insertOnly':
|
117
|
+
button.label = t('Image');
|
118
|
+
break;
|
119
|
+
case 'insertNested':
|
120
|
+
button.label = t('With file manager');
|
121
|
+
break;
|
122
|
+
}
|
123
|
+
return button;
|
124
|
+
}
|
78
125
|
}
|
79
126
|
|
80
127
|
/**
|
@@ -235,7 +282,7 @@ const MIME_TO_EXTENSION = {
|
|
235
282
|
* Returns an extension from the given value.
|
236
283
|
*/ function getFileExtension(file) {
|
237
284
|
const fileName = file.name;
|
238
|
-
const extensionRegExp =
|
285
|
+
const extensionRegExp = /\.(?<ext>[^.]+)$/;
|
239
286
|
const match = fileName.match(extensionRegExp);
|
240
287
|
return match.groups.ext.toLowerCase();
|
241
288
|
}
|
@@ -244,29 +291,68 @@ const MIME_TO_EXTENSION = {
|
|
244
291
|
// `CKBoxCommand#_chosenAssets` and it is removed from there automatically after this time. See `CKBoxCommand#_chosenAssets` for more
|
245
292
|
// details.
|
246
293
|
const ASSET_INSERTION_WAIT_TIMEOUT = 1000;
|
247
|
-
|
294
|
+
/**
|
295
|
+
* The CKBox command. It is used by the {@link module:ckbox/ckboxediting~CKBoxEditing CKBox editing feature} to open the CKBox file manager.
|
296
|
+
* The file manager allows inserting an image or a link to a file into the editor content.
|
297
|
+
*
|
298
|
+
* ```ts
|
299
|
+
* editor.execute( 'ckbox' );
|
300
|
+
* ```
|
301
|
+
*
|
302
|
+
* **Note:** This command uses other features to perform the following tasks:
|
303
|
+
* - To insert images it uses the {@link module:image/image/insertimagecommand~InsertImageCommand 'insertImage'} command from the
|
304
|
+
* {@link module:image/image~Image Image feature}.
|
305
|
+
* - To insert links to other files it uses the {@link module:link/linkcommand~LinkCommand 'link'} command from the
|
306
|
+
* {@link module:link/link~Link Link feature}.
|
307
|
+
*/ class CKBoxCommand extends Command {
|
308
|
+
/**
|
309
|
+
* A set of all chosen assets. They are stored temporarily and they are automatically removed 1 second after being chosen.
|
310
|
+
* Chosen assets have to be "remembered" for a while to be able to map the given asset with the element inserted into the model.
|
311
|
+
* This association map is then used to set the ID on the model element.
|
312
|
+
*
|
313
|
+
* All chosen assets are automatically removed after the timeout, because (theoretically) it may happen that they will never be
|
314
|
+
* inserted into the model, even if the {@link module:link/linkcommand~LinkCommand `'link'`} command or the
|
315
|
+
* {@link module:image/image/insertimagecommand~InsertImageCommand `'insertImage'`} command is enabled. Such a case may arise when
|
316
|
+
* another plugin blocks the command execution. Then, in order not to keep the chosen (but not inserted) assets forever, we delete
|
317
|
+
* them automatically to prevent memory leakage. The 1 second timeout is enough to insert the asset into the model and extract the
|
318
|
+
* ID from the chosen asset.
|
319
|
+
*
|
320
|
+
* The assets are stored only if
|
321
|
+
* the {@link module:ckbox/ckboxconfig~CKBoxConfig#ignoreDataId `config.ckbox.ignoreDataId`} option is set to `false` (by default).
|
322
|
+
*
|
323
|
+
* @internal
|
324
|
+
*/ _chosenAssets = new Set();
|
325
|
+
/**
|
326
|
+
* The DOM element that acts as a mounting point for the CKBox dialog.
|
327
|
+
*/ _wrapper = null;
|
248
328
|
/**
|
249
|
-
|
250
|
-
|
329
|
+
* @inheritDoc
|
330
|
+
*/ constructor(editor){
|
331
|
+
super(editor);
|
332
|
+
this._initListeners();
|
333
|
+
}
|
334
|
+
/**
|
335
|
+
* @inheritDoc
|
336
|
+
*/ refresh() {
|
251
337
|
this.value = this._getValue();
|
252
338
|
this.isEnabled = this._checkEnabled();
|
253
339
|
}
|
254
340
|
/**
|
255
|
-
|
256
|
-
|
341
|
+
* @inheritDoc
|
342
|
+
*/ execute() {
|
257
343
|
this.fire('ckbox:open');
|
258
344
|
}
|
259
345
|
/**
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
346
|
+
* Indicates if the CKBox dialog is already opened.
|
347
|
+
*
|
348
|
+
* @protected
|
349
|
+
* @returns {Boolean}
|
350
|
+
*/ _getValue() {
|
265
351
|
return this._wrapper !== null;
|
266
352
|
}
|
267
353
|
/**
|
268
|
-
|
269
|
-
|
354
|
+
* Checks whether the command can be enabled in the current context.
|
355
|
+
*/ _checkEnabled() {
|
270
356
|
const imageCommand = this.editor.commands.get('insertImage');
|
271
357
|
const linkCommand = this.editor.commands.get('link');
|
272
358
|
if (!imageCommand.isEnabled && !linkCommand.isEnabled) {
|
@@ -275,17 +361,17 @@ class CKBoxCommand extends Command {
|
|
275
361
|
return true;
|
276
362
|
}
|
277
363
|
/**
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
364
|
+
* Creates the options object for the CKBox dialog.
|
365
|
+
*
|
366
|
+
* @returns The object with properties:
|
367
|
+
* - theme The theme for CKBox dialog.
|
368
|
+
* - language The language for CKBox dialog.
|
369
|
+
* - tokenUrl The token endpoint URL.
|
370
|
+
* - serviceOrigin The base URL of the API service.
|
371
|
+
* - forceDemoLabel Whether to force "Powered by CKBox" link.
|
372
|
+
* - dialog.onClose The callback function invoked after closing the CKBox dialog.
|
373
|
+
* - assets.onChoose The callback function invoked after choosing the assets.
|
374
|
+
*/ _prepareOptions() {
|
289
375
|
const editor = this.editor;
|
290
376
|
const ckboxConfig = editor.config.get('ckbox');
|
291
377
|
return {
|
@@ -303,8 +389,8 @@ class CKBoxCommand extends Command {
|
|
303
389
|
};
|
304
390
|
}
|
305
391
|
/**
|
306
|
-
|
307
|
-
|
392
|
+
* Initializes various event listeners for the `ckbox:*` events, because all functionality of the `ckbox` command is event-based.
|
393
|
+
*/ _initListeners() {
|
308
394
|
const editor = this.editor;
|
309
395
|
const model = editor.model;
|
310
396
|
const shouldInsertDataId = !editor.config.get('ckbox.ignoreDataId');
|
@@ -373,13 +459,13 @@ class CKBoxCommand extends Command {
|
|
373
459
|
});
|
374
460
|
}
|
375
461
|
/**
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
462
|
+
* Inserts the asset into the model.
|
463
|
+
*
|
464
|
+
* @param asset The asset to be inserted.
|
465
|
+
* @param isLastAsset Indicates if the current asset is the last one from the chosen set.
|
466
|
+
* @param writer An instance of the model writer.
|
467
|
+
* @param isSingleAsset It's true when only one asset is processed.
|
468
|
+
*/ _insertAsset(asset, isLastAsset, writer, isSingleAsset) {
|
383
469
|
const editor = this.editor;
|
384
470
|
const model = editor.model;
|
385
471
|
const selection = model.document.selection;
|
@@ -397,10 +483,10 @@ class CKBoxCommand extends Command {
|
|
397
483
|
}
|
398
484
|
}
|
399
485
|
/**
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
486
|
+
* Inserts the image by calling the `insertImage` command.
|
487
|
+
*
|
488
|
+
* @param asset The asset to be inserted.
|
489
|
+
*/ _insertImage(asset) {
|
404
490
|
const editor = this.editor;
|
405
491
|
const { imageFallbackUrl, imageSources, imageTextAlternative, imageWidth, imageHeight, imagePlaceholder } = asset.attributes;
|
406
492
|
editor.execute('insertImage', {
|
@@ -417,12 +503,12 @@ class CKBoxCommand extends Command {
|
|
417
503
|
});
|
418
504
|
}
|
419
505
|
/**
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
506
|
+
* Inserts the link to the asset by calling the `link` command.
|
507
|
+
*
|
508
|
+
* @param asset The asset to be inserted.
|
509
|
+
* @param writer An instance of the model writer.
|
510
|
+
* @param isSingleAsset It's true when only one asset is processed.
|
511
|
+
*/ _insertLink(asset, writer, isSingleAsset) {
|
426
512
|
const editor = this.editor;
|
427
513
|
const model = editor.model;
|
428
514
|
const selection = model.document.selection;
|
@@ -450,32 +536,6 @@ class CKBoxCommand extends Command {
|
|
450
536
|
}
|
451
537
|
editor.execute('link', linkHref);
|
452
538
|
}
|
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
539
|
}
|
480
540
|
/**
|
481
541
|
* Parses the chosen assets into the internal data format. Filters out chosen assets that are not allowed.
|
@@ -539,22 +599,27 @@ class CKBoxCommand extends Command {
|
|
539
599
|
}
|
540
600
|
|
541
601
|
const DEFAULT_CKBOX_THEME_NAME = 'lark';
|
542
|
-
|
602
|
+
/**
|
603
|
+
* The CKBox utilities plugin.
|
604
|
+
*/ class CKBoxUtils extends Plugin {
|
543
605
|
/**
|
544
|
-
|
545
|
-
|
606
|
+
* CKEditor Cloud Services access token.
|
607
|
+
*/ _token;
|
608
|
+
/**
|
609
|
+
* @inheritDoc
|
610
|
+
*/ static get pluginName() {
|
546
611
|
return 'CKBoxUtils';
|
547
612
|
}
|
548
613
|
/**
|
549
|
-
|
550
|
-
|
614
|
+
* @inheritDoc
|
615
|
+
*/ static get requires() {
|
551
616
|
return [
|
552
617
|
'CloudServices'
|
553
618
|
];
|
554
619
|
}
|
555
620
|
/**
|
556
|
-
|
557
|
-
|
621
|
+
* @inheritDoc
|
622
|
+
*/ async init() {
|
558
623
|
const editor = this.editor;
|
559
624
|
const hasConfiguration = !!editor.config.get('ckbox');
|
560
625
|
const isLibraryLoaded = !!window.CKBox;
|
@@ -576,22 +641,22 @@ class CKBoxUtils extends Plugin {
|
|
576
641
|
const ckboxTokenUrl = editor.config.get('ckbox.tokenUrl');
|
577
642
|
if (!ckboxTokenUrl) {
|
578
643
|
/**
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
644
|
+
* The {@link module:ckbox/ckboxconfig~CKBoxConfig#tokenUrl `config.ckbox.tokenUrl`} or the
|
645
|
+
* {@link module:cloud-services/cloudservicesconfig~CloudServicesConfig#tokenUrl `config.cloudServices.tokenUrl`}
|
646
|
+
* configuration is required for the CKBox plugin.
|
647
|
+
*
|
648
|
+
* ```ts
|
649
|
+
* ClassicEditor.create( document.createElement( 'div' ), {
|
650
|
+
* ckbox: {
|
651
|
+
* tokenUrl: "YOUR_TOKEN_URL"
|
652
|
+
* // ...
|
653
|
+
* }
|
654
|
+
* // ...
|
655
|
+
* } );
|
656
|
+
* ```
|
657
|
+
*
|
658
|
+
* @error ckbox-plugin-missing-token-url
|
659
|
+
*/ throw new CKEditorError('ckbox-plugin-missing-token-url', this);
|
595
660
|
}
|
596
661
|
if (ckboxTokenUrl == cloudServicesTokenUrl) {
|
597
662
|
this._token = cloudServices.token;
|
@@ -600,30 +665,30 @@ class CKBoxUtils extends Plugin {
|
|
600
665
|
}
|
601
666
|
}
|
602
667
|
/**
|
603
|
-
|
604
|
-
|
668
|
+
* Returns a token used by the CKBox plugin for communication with the CKBox service.
|
669
|
+
*/ getToken() {
|
605
670
|
return this._token;
|
606
671
|
}
|
607
672
|
/**
|
608
|
-
|
609
|
-
|
673
|
+
* The ID of workspace to use when uploading an image.
|
674
|
+
*/ getWorkspaceId() {
|
610
675
|
const t = this.editor.t;
|
611
676
|
const cannotAccessDefaultWorkspaceError = t('Cannot access default workspace.');
|
612
677
|
const defaultWorkspaceId = this.editor.config.get('ckbox.defaultUploadWorkspaceId');
|
613
678
|
const workspaceId = getWorkspaceId(this._token, defaultWorkspaceId);
|
614
679
|
if (workspaceId == null) {
|
615
680
|
/**
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
681
|
+
* The user is not authorized to access the workspace defined in the`ckbox.defaultUploadWorkspaceId` configuration.
|
682
|
+
*
|
683
|
+
* @error ckbox-access-default-workspace-error
|
684
|
+
*/ logError('ckbox-access-default-workspace-error');
|
620
685
|
throw cannotAccessDefaultWorkspaceError;
|
621
686
|
}
|
622
687
|
return workspaceId;
|
623
688
|
}
|
624
689
|
/**
|
625
|
-
|
626
|
-
|
690
|
+
* Resolves a promise with an object containing a category with which the uploaded file is associated or an error code.
|
691
|
+
*/ async getCategoryIdForFile(fileOrUrl, options) {
|
627
692
|
const t = this.editor.t;
|
628
693
|
const cannotFindCategoryError = t('Cannot determine a category for the uploaded file.');
|
629
694
|
const defaultCategories = this.editor.config.get('ckbox.defaultUploadCategories');
|
@@ -656,10 +721,10 @@ class CKBoxUtils extends Plugin {
|
|
656
721
|
return category.id;
|
657
722
|
}
|
658
723
|
/**
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
724
|
+
* Resolves a promise with an array containing available categories with which the uploaded file can be associated.
|
725
|
+
*
|
726
|
+
* If the API returns limited results, the method will collect all items.
|
727
|
+
*/ async _getAvailableCategories(options) {
|
663
728
|
const ITEMS_PER_REQUEST = 50;
|
664
729
|
const editor = this.editor;
|
665
730
|
const token = this._token;
|
@@ -680,10 +745,10 @@ class CKBoxUtils extends Plugin {
|
|
680
745
|
} catch {
|
681
746
|
signal.throwIfAborted();
|
682
747
|
/**
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
748
|
+
* Fetching a list of available categories with which an uploaded file can be associated failed.
|
749
|
+
*
|
750
|
+
* @error ckbox-fetch-category-http-error
|
751
|
+
*/ logError('ckbox-fetch-category-http-error');
|
687
752
|
return undefined;
|
688
753
|
}
|
689
754
|
function fetchCategories(offset) {
|
@@ -700,10 +765,18 @@ class CKBoxUtils extends Plugin {
|
|
700
765
|
}
|
701
766
|
}
|
702
767
|
|
703
|
-
|
768
|
+
/**
|
769
|
+
* A plugin that enables file uploads in CKEditor 5 using the CKBox server–side connector.
|
770
|
+
* See the {@glink features/file-management/ckbox CKBox file manager integration} guide to learn how to configure
|
771
|
+
* and use this feature as well as find out more about the full integration with the file manager
|
772
|
+
* provided by the {@link module:ckbox/ckbox~CKBox} plugin.
|
773
|
+
*
|
774
|
+
* Check out the {@glink features/images/image-upload/image-upload Image upload overview} guide to learn about
|
775
|
+
* other ways to upload images into CKEditor 5.
|
776
|
+
*/ class CKBoxUploadAdapter extends Plugin {
|
704
777
|
/**
|
705
|
-
|
706
|
-
|
778
|
+
* @inheritDoc
|
779
|
+
*/ static get requires() {
|
707
780
|
return [
|
708
781
|
'ImageUploadEditing',
|
709
782
|
'ImageUploadProgress',
|
@@ -712,13 +785,13 @@ class CKBoxUploadAdapter extends Plugin {
|
|
712
785
|
];
|
713
786
|
}
|
714
787
|
/**
|
715
|
-
|
716
|
-
|
788
|
+
* @inheritDoc
|
789
|
+
*/ static get pluginName() {
|
717
790
|
return 'CKBoxUploadAdapter';
|
718
791
|
}
|
719
792
|
/**
|
720
|
-
|
721
|
-
|
793
|
+
* @inheritDoc
|
794
|
+
*/ async afterInit() {
|
722
795
|
const editor = this.editor;
|
723
796
|
const hasConfiguration = !!editor.config.get('ckbox');
|
724
797
|
const isLibraryLoaded = !!window.CKBox;
|
@@ -747,10 +820,38 @@ class CKBoxUploadAdapter extends Plugin {
|
|
747
820
|
* Upload adapter for CKBox.
|
748
821
|
*/ class Adapter {
|
749
822
|
/**
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
823
|
+
* FileLoader instance to use during the upload.
|
824
|
+
*/ loader;
|
825
|
+
/**
|
826
|
+
* CKEditor Cloud Services access token.
|
827
|
+
*/ token;
|
828
|
+
/**
|
829
|
+
* The editor instance.
|
830
|
+
*/ editor;
|
831
|
+
/**
|
832
|
+
* The abort controller for aborting asynchronous processes.
|
833
|
+
*/ controller;
|
834
|
+
/**
|
835
|
+
* The base URL where all requests should be sent.
|
836
|
+
*/ serviceOrigin;
|
837
|
+
/**
|
838
|
+
* The reference to CKBoxUtils plugin.
|
839
|
+
*/ ckboxUtils;
|
840
|
+
/**
|
841
|
+
* Creates a new adapter instance.
|
842
|
+
*/ constructor(loader, editor, ckboxUtils){
|
843
|
+
this.loader = loader;
|
844
|
+
this.token = ckboxUtils.getToken();
|
845
|
+
this.ckboxUtils = ckboxUtils;
|
846
|
+
this.editor = editor;
|
847
|
+
this.controller = new AbortController();
|
848
|
+
this.serviceOrigin = editor.config.get('ckbox.serviceOrigin');
|
849
|
+
}
|
850
|
+
/**
|
851
|
+
* Starts the upload process.
|
852
|
+
*
|
853
|
+
* @see module:upload/filerepository~UploadAdapter#upload
|
854
|
+
*/ async upload() {
|
754
855
|
const ckboxUtils = this.ckboxUtils;
|
755
856
|
const t = this.editor.t;
|
756
857
|
const file = await this.loader.file;
|
@@ -788,33 +889,29 @@ class CKBoxUploadAdapter extends Plugin {
|
|
788
889
|
});
|
789
890
|
}
|
790
891
|
/**
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
892
|
+
* Aborts the upload process.
|
893
|
+
*
|
894
|
+
* @see module:upload/filerepository~UploadAdapter#abort
|
895
|
+
*/ abort() {
|
795
896
|
this.controller.abort();
|
796
897
|
}
|
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
898
|
}
|
808
899
|
|
809
|
-
|
900
|
+
/**
|
901
|
+
* The CKBox editing feature. It introduces the {@link module:ckbox/ckboxcommand~CKBoxCommand CKBox command} and
|
902
|
+
* {@link module:ckbox/ckboxuploadadapter~CKBoxUploadAdapter CKBox upload adapter}.
|
903
|
+
*/ class CKBoxEditing extends Plugin {
|
904
|
+
/**
|
905
|
+
* CKEditor Cloud Services access token.
|
906
|
+
*/ _token;
|
810
907
|
/**
|
811
|
-
|
812
|
-
|
908
|
+
* @inheritDoc
|
909
|
+
*/ static get pluginName() {
|
813
910
|
return 'CKBoxEditing';
|
814
911
|
}
|
815
912
|
/**
|
816
|
-
|
817
|
-
|
913
|
+
* @inheritDoc
|
914
|
+
*/ static get requires() {
|
818
915
|
return [
|
819
916
|
'LinkEditing',
|
820
917
|
'PictureEditing',
|
@@ -823,8 +920,8 @@ class CKBoxEditing extends Plugin {
|
|
823
920
|
];
|
824
921
|
}
|
825
922
|
/**
|
826
|
-
|
827
|
-
|
923
|
+
* @inheritDoc
|
924
|
+
*/ init() {
|
828
925
|
const editor = this.editor;
|
829
926
|
if (!this._shouldBeInitialised()) {
|
830
927
|
return;
|
@@ -836,8 +933,8 @@ class CKBoxEditing extends Plugin {
|
|
836
933
|
}
|
837
934
|
}
|
838
935
|
/**
|
839
|
-
|
840
|
-
|
936
|
+
* @inheritDoc
|
937
|
+
*/ afterInit() {
|
841
938
|
const editor = this.editor;
|
842
939
|
if (!this._shouldBeInitialised()) {
|
843
940
|
return;
|
@@ -851,35 +948,35 @@ class CKBoxEditing extends Plugin {
|
|
851
948
|
}
|
852
949
|
}
|
853
950
|
/**
|
854
|
-
|
855
|
-
|
856
|
-
|
951
|
+
* Returns true only when the integrator intentionally wants to use the plugin, i.e. when the `config.ckbox` exists or
|
952
|
+
* the CKBox JavaScript library is loaded.
|
953
|
+
*/ _shouldBeInitialised() {
|
857
954
|
const editor = this.editor;
|
858
955
|
const hasConfiguration = !!editor.config.get('ckbox');
|
859
956
|
return hasConfiguration || isLibraryLoaded();
|
860
957
|
}
|
861
958
|
/**
|
862
|
-
|
863
|
-
|
959
|
+
* Checks if at least one image plugin is loaded.
|
960
|
+
*/ _checkImagePlugins() {
|
864
961
|
const editor = this.editor;
|
865
962
|
if (!editor.plugins.has('ImageBlockEditing') && !editor.plugins.has('ImageInlineEditing')) {
|
866
963
|
/**
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
964
|
+
* The CKBox feature requires one of the following plugins to be loaded to work correctly:
|
965
|
+
*
|
966
|
+
* * {@link module:image/imageblock~ImageBlock},
|
967
|
+
* * {@link module:image/imageinline~ImageInline},
|
968
|
+
* * {@link module:image/image~Image} (loads both `ImageBlock` and `ImageInline`)
|
969
|
+
*
|
970
|
+
* Please make sure your editor configuration is correct.
|
971
|
+
*
|
972
|
+
* @error ckbox-plugin-image-feature-missing
|
973
|
+
* @param {module:core/editor/editor~Editor} editor
|
974
|
+
*/ logError('ckbox-plugin-image-feature-missing', editor);
|
878
975
|
}
|
879
976
|
}
|
880
977
|
/**
|
881
|
-
|
882
|
-
|
978
|
+
* Extends the schema to allow the `ckboxImageId` and `ckboxLinkId` attributes for links and images.
|
979
|
+
*/ _initSchema() {
|
883
980
|
const editor = this.editor;
|
884
981
|
const schema = editor.model.schema;
|
885
982
|
schema.extend('$text', {
|
@@ -909,8 +1006,8 @@ class CKBoxEditing extends Plugin {
|
|
909
1006
|
});
|
910
1007
|
}
|
911
1008
|
/**
|
912
|
-
|
913
|
-
|
1009
|
+
* Configures the upcast and downcast conversions for the `ckboxImageId` and `ckboxLinkId` attributes.
|
1010
|
+
*/ _initConversion() {
|
914
1011
|
const editor = this.editor;
|
915
1012
|
// Convert `ckboxLinkId` => `data-ckbox-resource-id`.
|
916
1013
|
editor.conversion.for('downcast').add((dispatcher)=>{
|
@@ -1031,8 +1128,8 @@ class CKBoxEditing extends Plugin {
|
|
1031
1128
|
}
|
1032
1129
|
}
|
1033
1130
|
/**
|
1034
|
-
|
1035
|
-
|
1131
|
+
* Registers post-fixers that add or remove the `ckboxLinkId` and `ckboxImageId` attributes.
|
1132
|
+
*/ _initFixers() {
|
1036
1133
|
const editor = this.editor;
|
1037
1134
|
const model = editor.model;
|
1038
1135
|
const selection = model.document.selection;
|
@@ -1145,15 +1242,27 @@ class CKBoxEditing extends Plugin {
|
|
1145
1242
|
return !!window.CKBox;
|
1146
1243
|
}
|
1147
1244
|
|
1148
|
-
|
1245
|
+
/**
|
1246
|
+
* The CKBox feature, a bridge between the CKEditor 5 WYSIWYG editor and the CKBox file manager and uploader.
|
1247
|
+
*
|
1248
|
+
* This is a "glue" plugin which enables:
|
1249
|
+
*
|
1250
|
+
* * {@link module:ckbox/ckboxediting~CKBoxEditing},
|
1251
|
+
* * {@link module:ckbox/ckboxui~CKBoxUI},
|
1252
|
+
*
|
1253
|
+
* See the {@glink features/file-management/ckbox CKBox integration} guide to learn how to configure and use this feature.
|
1254
|
+
*
|
1255
|
+
* Check out the {@glink features/images/image-upload/image-upload Image upload} guide to learn about other ways to upload
|
1256
|
+
* images into CKEditor 5.
|
1257
|
+
*/ class CKBox extends Plugin {
|
1149
1258
|
/**
|
1150
|
-
|
1151
|
-
|
1259
|
+
* @inheritDoc
|
1260
|
+
*/ static get pluginName() {
|
1152
1261
|
return 'CKBox';
|
1153
1262
|
}
|
1154
1263
|
/**
|
1155
|
-
|
1156
|
-
|
1264
|
+
* @inheritDoc
|
1265
|
+
*/ static get requires() {
|
1157
1266
|
return [
|
1158
1267
|
CKBoxEditing,
|
1159
1268
|
CKBoxUI
|
@@ -1197,18 +1306,50 @@ function createUrlChecker(allowExternalImagesEditing) {
|
|
1197
1306
|
return ()=>false;
|
1198
1307
|
}
|
1199
1308
|
|
1200
|
-
|
1309
|
+
/**
|
1310
|
+
* The CKBox edit image command.
|
1311
|
+
*
|
1312
|
+
* Opens the CKBox dialog for editing the image.
|
1313
|
+
*/ class CKBoxImageEditCommand extends Command {
|
1314
|
+
/**
|
1315
|
+
* The DOM element that acts as a mounting point for the CKBox Edit Image dialog.
|
1316
|
+
*/ _wrapper = null;
|
1317
|
+
/**
|
1318
|
+
* The states of image processing in progress.
|
1319
|
+
*/ _processInProgress = new Set();
|
1320
|
+
/**
|
1321
|
+
* Determines if the element can be edited.
|
1322
|
+
*/ _canEdit;
|
1323
|
+
/**
|
1324
|
+
* A wrapper function to prepare mount options. Ensures that at most one preparation is in-flight.
|
1325
|
+
*/ _prepareOptions;
|
1326
|
+
/**
|
1327
|
+
* CKBox's onClose function runs before the final cleanup, potentially causing
|
1328
|
+
* page layout changes after it finishes. To address this, we use a setTimeout hack
|
1329
|
+
* to ensure that floating elements on the page maintain their correct position.
|
1330
|
+
*
|
1331
|
+
* See: https://github.com/ckeditor/ckeditor5/issues/16153.
|
1332
|
+
*/ _updateUiDelayed = delay(()=>this.editor.ui.update(), 0);
|
1333
|
+
/**
|
1334
|
+
* @inheritDoc
|
1335
|
+
*/ constructor(editor){
|
1336
|
+
super(editor);
|
1337
|
+
this.value = false;
|
1338
|
+
this._canEdit = createEditabilityChecker(editor.config.get('ckbox.allowExternalImagesEditing'));
|
1339
|
+
this._prepareOptions = abortableDebounce((signal, state)=>this._prepareOptionsAbortable(signal, state));
|
1340
|
+
this._prepareListeners();
|
1341
|
+
}
|
1201
1342
|
/**
|
1202
|
-
|
1203
|
-
|
1343
|
+
* @inheritDoc
|
1344
|
+
*/ refresh() {
|
1204
1345
|
const editor = this.editor;
|
1205
1346
|
this.value = this._getValue();
|
1206
1347
|
const selectedElement = editor.model.document.selection.getSelectedElement();
|
1207
1348
|
this.isEnabled = !!selectedElement && this._canEdit(selectedElement) && !this._checkIfElementIsBeingProcessed(selectedElement);
|
1208
1349
|
}
|
1209
1350
|
/**
|
1210
|
-
|
1211
|
-
|
1351
|
+
* Opens the CKBox Image Editor dialog for editing the image.
|
1352
|
+
*/ execute() {
|
1212
1353
|
if (this._getValue()) {
|
1213
1354
|
return;
|
1214
1355
|
}
|
@@ -1235,23 +1376,24 @@ class CKBoxImageEditCommand extends Command {
|
|
1235
1376
|
});
|
1236
1377
|
}
|
1237
1378
|
/**
|
1238
|
-
|
1239
|
-
|
1379
|
+
* @inheritDoc
|
1380
|
+
*/ destroy() {
|
1240
1381
|
this._handleImageEditorClose();
|
1241
1382
|
this._prepareOptions.abort();
|
1383
|
+
this._updateUiDelayed.cancel();
|
1242
1384
|
for (const state of this._processInProgress.values()){
|
1243
1385
|
state.controller.abort();
|
1244
1386
|
}
|
1245
1387
|
super.destroy();
|
1246
1388
|
}
|
1247
1389
|
/**
|
1248
|
-
|
1249
|
-
|
1390
|
+
* Indicates if the CKBox Image Editor dialog is already opened.
|
1391
|
+
*/ _getValue() {
|
1250
1392
|
return this._wrapper !== null;
|
1251
1393
|
}
|
1252
1394
|
/**
|
1253
|
-
|
1254
|
-
|
1395
|
+
* Creates the options object for the CKBox Image Editor dialog.
|
1396
|
+
*/ async _prepareOptionsAbortable(signal, state) {
|
1255
1397
|
const editor = this.editor;
|
1256
1398
|
const ckboxConfig = editor.config.get('ckbox');
|
1257
1399
|
const ckboxUtils = editor.plugins.get(CKBoxUtils);
|
@@ -1286,8 +1428,8 @@ class CKBoxImageEditCommand extends Command {
|
|
1286
1428
|
};
|
1287
1429
|
}
|
1288
1430
|
/**
|
1289
|
-
|
1290
|
-
|
1431
|
+
* Initializes event lister for an event of removing an image.
|
1432
|
+
*/ _prepareListeners() {
|
1291
1433
|
// Abort editing processing when the image has been removed.
|
1292
1434
|
this.listenTo(this.editor.model.document, 'change:data', ()=>{
|
1293
1435
|
const processingStates = this._getProcessingStatesOfDeletedImages();
|
@@ -1297,8 +1439,8 @@ class CKBoxImageEditCommand extends Command {
|
|
1297
1439
|
});
|
1298
1440
|
}
|
1299
1441
|
/**
|
1300
|
-
|
1301
|
-
|
1442
|
+
* Gets processing states of images that have been deleted in the mean time.
|
1443
|
+
*/ _getProcessingStatesOfDeletedImages() {
|
1302
1444
|
const states = [];
|
1303
1445
|
for (const state of this._processInProgress.values()){
|
1304
1446
|
if (state.element.root.rootName == '$graveyard') {
|
@@ -1316,20 +1458,21 @@ class CKBoxImageEditCommand extends Command {
|
|
1316
1458
|
return false;
|
1317
1459
|
}
|
1318
1460
|
/**
|
1319
|
-
|
1320
|
-
|
1461
|
+
* Closes the CKBox Image Editor dialog.
|
1462
|
+
*/ _handleImageEditorClose() {
|
1321
1463
|
if (!this._wrapper) {
|
1322
1464
|
return;
|
1323
1465
|
}
|
1324
1466
|
this._wrapper.remove();
|
1325
1467
|
this._wrapper = null;
|
1326
1468
|
this.editor.editing.view.focus();
|
1469
|
+
this._updateUiDelayed();
|
1327
1470
|
this.refresh();
|
1328
1471
|
}
|
1329
1472
|
/**
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1473
|
+
* Save edited image. In case server respond with "success" replace with edited image,
|
1474
|
+
* otherwise show notification error.
|
1475
|
+
*/ _handleImageEditorSave(state, asset) {
|
1333
1476
|
const t = this.editor.locale.t;
|
1334
1477
|
const notification = this.editor.plugins.get(Notification);
|
1335
1478
|
const pendingActions = this.editor.plugins.get(PendingActions);
|
@@ -1359,9 +1502,9 @@ class CKBoxImageEditCommand extends Command {
|
|
1359
1502
|
});
|
1360
1503
|
}
|
1361
1504
|
/**
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1505
|
+
* Get asset's status on server. If server responds with "success" status then
|
1506
|
+
* image is already proceeded and ready for saving.
|
1507
|
+
*/ async _getAssetStatusFromServer(id, signal) {
|
1365
1508
|
const ckboxUtils = this.editor.plugins.get(CKBoxUtils);
|
1366
1509
|
const url = new URL('assets/' + id, this.editor.config.get('ckbox.serviceOrigin'));
|
1367
1510
|
const response = await sendHttpRequest({
|
@@ -1372,10 +1515,10 @@ class CKBoxImageEditCommand extends Command {
|
|
1372
1515
|
const status = response.metadata.metadataProcessingStatus;
|
1373
1516
|
if (!status || status == 'queued') {
|
1374
1517
|
/**
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
1378
|
-
|
1518
|
+
* Image has not been processed yet.
|
1519
|
+
*
|
1520
|
+
* @error ckbox-image-not-processed
|
1521
|
+
*/ throw new CKEditorError('ckbox-image-not-processed');
|
1379
1522
|
}
|
1380
1523
|
return {
|
1381
1524
|
data: {
|
@@ -1384,27 +1527,27 @@ class CKBoxImageEditCommand extends Command {
|
|
1384
1527
|
};
|
1385
1528
|
}
|
1386
1529
|
/**
|
1387
|
-
|
1388
|
-
|
1389
|
-
|
1530
|
+
* Waits for an asset to be processed.
|
1531
|
+
* It retries retrieving asset status from the server in case of failure.
|
1532
|
+
*/ async _waitForAssetProcessed(id, signal) {
|
1390
1533
|
const result = await retry(()=>this._getAssetStatusFromServer(id, signal), {
|
1391
1534
|
signal,
|
1392
1535
|
maxAttempts: 5
|
1393
1536
|
});
|
1394
1537
|
if (result.data.metadata.metadataProcessingStatus != 'success') {
|
1395
1538
|
/**
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1539
|
+
* The image processing failed.
|
1540
|
+
*
|
1541
|
+
* @error ckbox-image-processing-failed
|
1542
|
+
*/ throw new CKEditorError('ckbox-image-processing-failed');
|
1400
1543
|
}
|
1401
1544
|
return result;
|
1402
1545
|
}
|
1403
1546
|
/**
|
1404
|
-
|
1405
|
-
|
1406
|
-
|
1407
|
-
|
1547
|
+
* Shows processing indicator while image is processing.
|
1548
|
+
*
|
1549
|
+
* @param asset Data about certain asset.
|
1550
|
+
*/ _showImageProcessingIndicator(element, asset) {
|
1408
1551
|
const editor = this.editor;
|
1409
1552
|
editor.editing.view.change((writer)=>{
|
1410
1553
|
const imageElementView = editor.editing.mapper.toViewElement(element);
|
@@ -1419,8 +1562,8 @@ class CKBoxImageEditCommand extends Command {
|
|
1419
1562
|
});
|
1420
1563
|
}
|
1421
1564
|
/**
|
1422
|
-
|
1423
|
-
|
1565
|
+
* Replace the edited image with the new one.
|
1566
|
+
*/ _replaceImage(element, asset) {
|
1424
1567
|
const editor = this.editor;
|
1425
1568
|
const { imageFallbackUrl, imageSources, imageWidth, imageHeight, imagePlaceholder } = prepareImageAssetAttributes(asset);
|
1426
1569
|
const previousSelectionRanges = Array.from(editor.model.document.selection.getRanges());
|
@@ -1449,32 +1592,19 @@ class CKBoxImageEditCommand extends Command {
|
|
1449
1592
|
writer.setSelection(previousSelectionRanges);
|
1450
1593
|
});
|
1451
1594
|
}
|
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
1595
|
}
|
1468
1596
|
|
1469
|
-
|
1597
|
+
/**
|
1598
|
+
* The CKBox image edit editing plugin.
|
1599
|
+
*/ class CKBoxImageEditEditing extends Plugin {
|
1470
1600
|
/**
|
1471
|
-
|
1472
|
-
|
1601
|
+
* @inheritDoc
|
1602
|
+
*/ static get pluginName() {
|
1473
1603
|
return 'CKBoxImageEditEditing';
|
1474
1604
|
}
|
1475
1605
|
/**
|
1476
|
-
|
1477
|
-
|
1606
|
+
* @inheritDoc
|
1607
|
+
*/ static get requires() {
|
1478
1608
|
return [
|
1479
1609
|
CKBoxEditing,
|
1480
1610
|
CKBoxUtils,
|
@@ -1485,8 +1615,8 @@ class CKBoxImageEditEditing extends Plugin {
|
|
1485
1615
|
];
|
1486
1616
|
}
|
1487
1617
|
/**
|
1488
|
-
|
1489
|
-
|
1618
|
+
* @inheritDoc
|
1619
|
+
*/ init() {
|
1490
1620
|
const { editor } = this;
|
1491
1621
|
editor.commands.add('ckboxImageEdit', new CKBoxImageEditCommand(editor));
|
1492
1622
|
}
|
@@ -1494,15 +1624,20 @@ class CKBoxImageEditEditing extends Plugin {
|
|
1494
1624
|
|
1495
1625
|
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
1626
|
|
1497
|
-
|
1627
|
+
/**
|
1628
|
+
* The UI plugin of the CKBox image edit feature.
|
1629
|
+
*
|
1630
|
+
* It registers the `'ckboxImageEdit'` UI button in the editor's {@link module:ui/componentfactory~ComponentFactory component factory}
|
1631
|
+
* that allows you to open the CKBox dialog and edit the image.
|
1632
|
+
*/ class CKBoxImageEditUI extends Plugin {
|
1498
1633
|
/**
|
1499
|
-
|
1500
|
-
|
1634
|
+
* @inheritDoc
|
1635
|
+
*/ static get pluginName() {
|
1501
1636
|
return 'CKBoxImageEditUI';
|
1502
1637
|
}
|
1503
1638
|
/**
|
1504
|
-
|
1505
|
-
|
1639
|
+
* @inheritDoc
|
1640
|
+
*/ init() {
|
1506
1641
|
const editor = this.editor;
|
1507
1642
|
editor.ui.componentFactory.add('ckboxImageEdit', (locale)=>{
|
1508
1643
|
const command = editor.commands.get('ckboxImageEdit');
|
@@ -1525,15 +1660,17 @@ class CKBoxImageEditUI extends Plugin {
|
|
1525
1660
|
}
|
1526
1661
|
}
|
1527
1662
|
|
1528
|
-
|
1663
|
+
/**
|
1664
|
+
* The CKBox image edit feature.
|
1665
|
+
*/ class CKBoxImageEdit extends Plugin {
|
1529
1666
|
/**
|
1530
|
-
|
1531
|
-
|
1667
|
+
* @inheritDoc
|
1668
|
+
*/ static get pluginName() {
|
1532
1669
|
return 'CKBoxImageEdit';
|
1533
1670
|
}
|
1534
1671
|
/**
|
1535
|
-
|
1536
|
-
|
1672
|
+
* @inheritDoc
|
1673
|
+
*/ static get requires() {
|
1537
1674
|
return [
|
1538
1675
|
CKBoxImageEditEditing,
|
1539
1676
|
CKBoxImageEditUI
|