@ckeditor/ckeditor5-ckbox 0.0.0-nightly-20240605.0 → 0.0.0-nightly-20240606.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/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
|