@ckeditor/ckeditor5-ckbox 40.1.0 → 40.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. package/build/ckbox.js +2 -2
  2. package/build/translations/ar.js +1 -1
  3. package/build/translations/az.js +1 -1
  4. package/build/translations/bg.js +1 -1
  5. package/build/translations/bn.js +1 -1
  6. package/build/translations/ca.js +1 -1
  7. package/build/translations/cs.js +1 -1
  8. package/build/translations/da.js +1 -1
  9. package/build/translations/de.js +1 -1
  10. package/build/translations/el.js +1 -1
  11. package/build/translations/en-au.js +1 -1
  12. package/build/translations/es-co.js +1 -1
  13. package/build/translations/es.js +1 -1
  14. package/build/translations/et.js +1 -1
  15. package/build/translations/fa.js +1 -1
  16. package/build/translations/fi.js +1 -1
  17. package/build/translations/fr.js +1 -1
  18. package/build/translations/gl.js +1 -1
  19. package/build/translations/he.js +1 -1
  20. package/build/translations/hi.js +1 -1
  21. package/build/translations/hr.js +1 -1
  22. package/build/translations/hu.js +1 -1
  23. package/build/translations/id.js +1 -1
  24. package/build/translations/it.js +1 -1
  25. package/build/translations/ja.js +1 -1
  26. package/build/translations/ko.js +1 -1
  27. package/build/translations/lt.js +1 -1
  28. package/build/translations/lv.js +1 -1
  29. package/build/translations/ms.js +1 -1
  30. package/build/translations/nl.js +1 -1
  31. package/build/translations/no.js +1 -1
  32. package/build/translations/pl.js +1 -1
  33. package/build/translations/pt-br.js +1 -1
  34. package/build/translations/pt.js +1 -1
  35. package/build/translations/ro.js +1 -1
  36. package/build/translations/ru.js +1 -1
  37. package/build/translations/sk.js +1 -1
  38. package/build/translations/sq.js +1 -1
  39. package/build/translations/sr-latn.js +1 -1
  40. package/build/translations/sr.js +1 -1
  41. package/build/translations/sv.js +1 -1
  42. package/build/translations/th.js +1 -1
  43. package/build/translations/tr.js +1 -1
  44. package/build/translations/ug.js +1 -1
  45. package/build/translations/uk.js +1 -1
  46. package/build/translations/ur.js +1 -1
  47. package/build/translations/uz.js +1 -1
  48. package/build/translations/vi.js +1 -1
  49. package/build/translations/zh-cn.js +1 -1
  50. package/build/translations/zh.js +1 -1
  51. package/ckeditor5-metadata.json +17 -0
  52. package/lang/contexts.json +6 -2
  53. package/lang/translations/ar.po +18 -2
  54. package/lang/translations/az.po +18 -2
  55. package/lang/translations/bg.po +18 -2
  56. package/lang/translations/bn.po +18 -2
  57. package/lang/translations/ca.po +18 -2
  58. package/lang/translations/cs.po +18 -2
  59. package/lang/translations/da.po +18 -2
  60. package/lang/translations/de.po +18 -2
  61. package/lang/translations/el.po +18 -2
  62. package/lang/translations/en-au.po +18 -2
  63. package/lang/translations/en.po +18 -2
  64. package/lang/translations/es-co.po +18 -2
  65. package/lang/translations/es.po +18 -2
  66. package/lang/translations/et.po +18 -2
  67. package/lang/translations/fa.po +18 -2
  68. package/lang/translations/fi.po +18 -2
  69. package/lang/translations/fr.po +18 -2
  70. package/lang/translations/gl.po +18 -2
  71. package/lang/translations/he.po +18 -2
  72. package/lang/translations/hi.po +18 -2
  73. package/lang/translations/hr.po +18 -2
  74. package/lang/translations/hu.po +18 -2
  75. package/lang/translations/id.po +18 -2
  76. package/lang/translations/it.po +18 -2
  77. package/lang/translations/ja.po +18 -2
  78. package/lang/translations/ko.po +18 -2
  79. package/lang/translations/lt.po +18 -2
  80. package/lang/translations/lv.po +18 -2
  81. package/lang/translations/ms.po +18 -2
  82. package/lang/translations/nl.po +18 -2
  83. package/lang/translations/no.po +18 -2
  84. package/lang/translations/pl.po +18 -2
  85. package/lang/translations/pt-br.po +18 -2
  86. package/lang/translations/pt.po +18 -2
  87. package/lang/translations/ro.po +18 -2
  88. package/lang/translations/ru.po +18 -2
  89. package/lang/translations/sk.po +18 -2
  90. package/lang/translations/sq.po +18 -2
  91. package/lang/translations/sr-latn.po +18 -2
  92. package/lang/translations/sr.po +18 -2
  93. package/lang/translations/sv.po +18 -2
  94. package/lang/translations/th.po +18 -2
  95. package/lang/translations/tr.po +18 -2
  96. package/lang/translations/ug.po +18 -2
  97. package/lang/translations/uk.po +18 -2
  98. package/lang/translations/ur.po +18 -2
  99. package/lang/translations/uz.po +18 -2
  100. package/lang/translations/vi.po +18 -2
  101. package/lang/translations/zh-cn.po +18 -2
  102. package/lang/translations/zh.po +18 -2
  103. package/package.json +4 -3
  104. package/src/augmentation.d.ts +11 -1
  105. package/src/ckboxcommand.d.ts +8 -6
  106. package/src/ckboxcommand.js +5 -1
  107. package/src/ckboxconfig.d.ts +26 -0
  108. package/src/ckboxediting.d.ts +5 -12
  109. package/src/ckboxediting.js +7 -55
  110. package/src/ckboximageedit/ckboximageeditcommand.d.ts +97 -0
  111. package/src/ckboximageedit/ckboximageeditcommand.js +298 -0
  112. package/src/ckboximageedit/ckboximageeditediting.d.ts +28 -0
  113. package/src/ckboximageedit/ckboximageeditediting.js +36 -0
  114. package/src/ckboximageedit/ckboximageeditui.d.ts +24 -0
  115. package/src/ckboximageedit/ckboximageeditui.js +48 -0
  116. package/src/ckboximageedit/utils.d.ts +10 -0
  117. package/src/ckboximageedit/utils.js +48 -0
  118. package/src/ckboximageedit.d.ts +24 -0
  119. package/src/ckboximageedit.js +28 -0
  120. package/src/ckboxui.js +28 -1
  121. package/src/ckboxuploadadapter.d.ts +0 -5
  122. package/src/ckboxuploadadapter.js +15 -160
  123. package/src/ckboxutils.d.ts +50 -0
  124. package/src/ckboxutils.js +183 -0
  125. package/src/index.d.ts +4 -0
  126. package/src/index.js +3 -0
  127. package/src/utils.d.ts +31 -0
  128. package/src/utils.js +93 -0
  129. package/theme/ckboximageedit.css +53 -0
  130. package/theme/icons/ckbox-image-edit.svg +1 -0
@@ -4,10 +4,10 @@
4
4
  */
5
5
  import { Plugin } from 'ckeditor5/src/core';
6
6
  import { Range } from 'ckeditor5/src/engine';
7
- import { CKEditorError, logError } from 'ckeditor5/src/utils';
7
+ import { logError } from 'ckeditor5/src/utils';
8
8
  import CKBoxCommand from './ckboxcommand';
9
9
  import CKBoxUploadAdapter from './ckboxuploadadapter';
10
- const DEFAULT_CKBOX_THEME_NAME = 'lark';
10
+ import CKBoxUtils from './ckboxutils';
11
11
  /**
12
12
  * The CKBox editing feature. It introduces the {@link module:ckbox/ckboxcommand~CKBoxCommand CKBox command} and
13
13
  * {@link module:ckbox/ckboxuploadadapter~CKBoxUploadAdapter CKBox upload adapter}.
@@ -23,12 +23,12 @@ export default class CKBoxEditing extends Plugin {
23
23
  * @inheritDoc
24
24
  */
25
25
  static get requires() {
26
- return ['CloudServices', 'LinkEditing', 'PictureEditing', CKBoxUploadAdapter];
26
+ return ['LinkEditing', 'PictureEditing', CKBoxUploadAdapter, CKBoxUtils];
27
27
  }
28
28
  /**
29
29
  * @inheritDoc
30
30
  */
31
- async init() {
31
+ init() {
32
32
  const editor = this.editor;
33
33
  const hasConfiguration = !!editor.config.get('ckbox');
34
34
  const isLibraryLoaded = !!window.CKBox;
@@ -37,20 +37,7 @@ export default class CKBoxEditing extends Plugin {
37
37
  if (!hasConfiguration && !isLibraryLoaded) {
38
38
  return;
39
39
  }
40
- this._initConfig();
41
- const cloudServicesCore = editor.plugins.get('CloudServicesCore');
42
- const ckboxTokenUrl = editor.config.get('ckbox.tokenUrl');
43
- const cloudServicesTokenUrl = editor.config.get('cloudServices.tokenUrl');
44
- // To avoid fetching the same token twice we need to compare the `ckbox.tokenUrl` and `cloudServices.tokenUrl` values.
45
- // If they are equal, it's enough to take the token generated by the `CloudServices` plugin.
46
- if (ckboxTokenUrl === cloudServicesTokenUrl) {
47
- const cloudServices = editor.plugins.get('CloudServices');
48
- this._token = cloudServices.token;
49
- }
50
- // Otherwise, create a new token manually.
51
- else {
52
- this._token = await cloudServicesCore.createToken(ckboxTokenUrl).init();
53
- }
40
+ this._checkImagePlugins();
54
41
  // Extending the schema, registering converters and applying fixers only make sense if the configuration option to assign
55
42
  // the assets ID with the model elements is enabled.
56
43
  if (!editor.config.get('ckbox.ignoreDataId')) {
@@ -64,45 +51,10 @@ export default class CKBoxEditing extends Plugin {
64
51
  }
65
52
  }
66
53
  /**
67
- * Returns a token used by the CKBox plugin for communication with the CKBox service.
68
- */
69
- getToken() {
70
- return this._token;
71
- }
72
- /**
73
- * Initializes the `ckbox` editor configuration.
54
+ * Checks if at least one image plugin is loaded.
74
55
  */
75
- _initConfig() {
56
+ _checkImagePlugins() {
76
57
  const editor = this.editor;
77
- editor.config.define('ckbox', {
78
- serviceOrigin: 'https://api.ckbox.io',
79
- defaultUploadCategories: null,
80
- ignoreDataId: false,
81
- language: editor.locale.uiLanguage,
82
- theme: DEFAULT_CKBOX_THEME_NAME,
83
- tokenUrl: editor.config.get('cloudServices.tokenUrl')
84
- });
85
- const tokenUrl = editor.config.get('ckbox.tokenUrl');
86
- if (!tokenUrl) {
87
- /**
88
- * The {@link module:ckbox/ckboxconfig~CKBoxConfig#tokenUrl `config.ckbox.tokenUrl`} or the
89
- * {@link module:cloud-services/cloudservicesconfig~CloudServicesConfig#tokenUrl `config.cloudServices.tokenUrl`}
90
- * configuration is required for the CKBox plugin.
91
- *
92
- * ```ts
93
- * ClassicEditor.create( document.createElement( 'div' ), {
94
- * ckbox: {
95
- * tokenUrl: "YOUR_TOKEN_URL"
96
- * // ...
97
- * }
98
- * // ...
99
- * } );
100
- * ```
101
- *
102
- * @error ckbox-plugin-missing-token-url
103
- */
104
- throw new CKEditorError('ckbox-plugin-missing-token-url', this);
105
- }
106
58
  if (!editor.plugins.has('ImageBlockEditing') && !editor.plugins.has('ImageInlineEditing')) {
107
59
  /**
108
60
  * The CKBox feature requires one of the following plugins to be loaded to work correctly:
@@ -0,0 +1,97 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module ckbox/ckboximageedit/ckboximageeditcommand
7
+ */
8
+ import { Command, type Editor } from 'ckeditor5/src/core';
9
+ /**
10
+ * The CKBox edit image command.
11
+ *
12
+ * Opens the CKBox dialog for editing the image.
13
+ */
14
+ export default class CKBoxImageEditCommand extends Command {
15
+ /**
16
+ * Flag indicating whether the command is active, i.e. dialog is open.
17
+ */
18
+ value: boolean;
19
+ /**
20
+ * The DOM element that acts as a mounting point for the CKBox Edit Image dialog.
21
+ */
22
+ private _wrapper;
23
+ /**
24
+ * The states of image processing in progress.
25
+ */
26
+ private _processInProgress;
27
+ /**
28
+ * Determines if the element can be edited.
29
+ */
30
+ private _canEdit;
31
+ /**
32
+ * A wrapper function to prepare mount options. Ensures that at most one preparation is in-flight.
33
+ */
34
+ private _prepareOptions;
35
+ /**
36
+ * @inheritDoc
37
+ */
38
+ constructor(editor: Editor);
39
+ /**
40
+ * @inheritDoc
41
+ */
42
+ refresh(): void;
43
+ /**
44
+ * Opens the CKBox Image Editor dialog for editing the image.
45
+ */
46
+ execute(): void;
47
+ /**
48
+ * @inheritDoc
49
+ */
50
+ destroy(): void;
51
+ /**
52
+ * Indicates if the CKBox Image Editor dialog is already opened.
53
+ */
54
+ private _getValue;
55
+ /**
56
+ * Creates the options object for the CKBox Image Editor dialog.
57
+ */
58
+ private _prepareOptionsAbortable;
59
+ /**
60
+ * Initializes event lister for an event of removing an image.
61
+ */
62
+ private _prepareListeners;
63
+ /**
64
+ * Gets processing states of images that have been deleted in the mean time.
65
+ */
66
+ private _getProcessingStatesOfDeletedImages;
67
+ private _checkIfElementIsBeingProcessed;
68
+ /**
69
+ * Closes the CKBox Image Editor dialog.
70
+ */
71
+ private _handleImageEditorClose;
72
+ /**
73
+ * Save edited image. In case server respond with "success" replace with edited image,
74
+ * otherwise show notification error.
75
+ */
76
+ private _handleImageEditorSave;
77
+ /**
78
+ * Get asset's status on server. If server responds with "success" status then
79
+ * image is already proceeded and ready for saving.
80
+ */
81
+ private _getAssetStatusFromServer;
82
+ /**
83
+ * Waits for an asset to be processed.
84
+ * It retries retrieving asset status from the server in case of failure.
85
+ */
86
+ private _waitForAssetProcessed;
87
+ /**
88
+ * Shows processing indicator while image is processing.
89
+ *
90
+ * @param asset Data about certain asset.
91
+ */
92
+ private _showImageProcessingIndicator;
93
+ /**
94
+ * Replace the edited image with the new one.
95
+ */
96
+ private _replaceImage;
97
+ }
@@ -0,0 +1,298 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /* globals document, console, AbortController, URL, window */
6
+ /**
7
+ * @module ckbox/ckboximageedit/ckboximageeditcommand
8
+ */
9
+ import { Command, PendingActions } from 'ckeditor5/src/core';
10
+ import { CKEditorError, abortableDebounce, createElement, retry } from 'ckeditor5/src/utils';
11
+ import { Notification } from 'ckeditor5/src/ui';
12
+ import { isEqual } from 'lodash-es';
13
+ import { sendHttpRequest } from '../utils';
14
+ import { prepareImageAssetAttributes } from '../ckboxcommand';
15
+ import { createEditabilityChecker } from './utils';
16
+ import CKBoxUtils from '../ckboxutils';
17
+ /**
18
+ * The CKBox edit image command.
19
+ *
20
+ * Opens the CKBox dialog for editing the image.
21
+ */
22
+ export default class CKBoxImageEditCommand extends Command {
23
+ /**
24
+ * @inheritDoc
25
+ */
26
+ constructor(editor) {
27
+ super(editor);
28
+ /**
29
+ * The DOM element that acts as a mounting point for the CKBox Edit Image dialog.
30
+ */
31
+ this._wrapper = null;
32
+ /**
33
+ * The states of image processing in progress.
34
+ */
35
+ this._processInProgress = new Set();
36
+ this.value = false;
37
+ this._canEdit = createEditabilityChecker(editor.config.get('ckbox.allowExternalImagesEditing'));
38
+ this._prepareOptions = abortableDebounce((signal, state) => this._prepareOptionsAbortable(signal, state));
39
+ this._prepareListeners();
40
+ }
41
+ /**
42
+ * @inheritDoc
43
+ */
44
+ refresh() {
45
+ const editor = this.editor;
46
+ this.value = this._getValue();
47
+ const selectedElement = editor.model.document.selection.getSelectedElement();
48
+ this.isEnabled =
49
+ !!selectedElement &&
50
+ this._canEdit(selectedElement) &&
51
+ !this._checkIfElementIsBeingProcessed(selectedElement);
52
+ }
53
+ /**
54
+ * Opens the CKBox Image Editor dialog for editing the image.
55
+ */
56
+ execute() {
57
+ if (this._getValue()) {
58
+ return;
59
+ }
60
+ const wrapper = createElement(document, 'div', { class: 'ck ckbox-wrapper' });
61
+ this._wrapper = wrapper;
62
+ this.value = true;
63
+ document.body.appendChild(this._wrapper);
64
+ const imageElement = this.editor.model.document.selection.getSelectedElement();
65
+ const processingState = {
66
+ element: imageElement,
67
+ controller: new AbortController()
68
+ };
69
+ this._prepareOptions(processingState).then(options => window.CKBox.mountImageEditor(wrapper, options), error => {
70
+ const editor = this.editor;
71
+ const t = editor.t;
72
+ const notification = editor.plugins.get(Notification);
73
+ notification.showWarning(t('Failed to determine category of edited image.'), {
74
+ namespace: 'ckbox'
75
+ });
76
+ console.error(error);
77
+ this._handleImageEditorClose();
78
+ });
79
+ }
80
+ /**
81
+ * @inheritDoc
82
+ */
83
+ destroy() {
84
+ this._handleImageEditorClose();
85
+ this._prepareOptions.abort();
86
+ for (const state of this._processInProgress.values()) {
87
+ state.controller.abort();
88
+ }
89
+ super.destroy();
90
+ }
91
+ /**
92
+ * Indicates if the CKBox Image Editor dialog is already opened.
93
+ */
94
+ _getValue() {
95
+ return this._wrapper !== null;
96
+ }
97
+ /**
98
+ * Creates the options object for the CKBox Image Editor dialog.
99
+ */
100
+ async _prepareOptionsAbortable(signal, state) {
101
+ const editor = this.editor;
102
+ const ckboxConfig = editor.config.get('ckbox');
103
+ const ckboxUtils = editor.plugins.get(CKBoxUtils);
104
+ const { element } = state;
105
+ let imageMountOptions;
106
+ const ckboxImageId = element.getAttribute('ckboxImageId');
107
+ if (ckboxImageId) {
108
+ imageMountOptions = {
109
+ assetId: ckboxImageId
110
+ };
111
+ }
112
+ else {
113
+ const imageUrl = element.getAttribute('src');
114
+ const uploadCategoryId = await ckboxUtils.getCategoryIdForFile(imageUrl, { signal });
115
+ imageMountOptions = {
116
+ imageUrl,
117
+ uploadCategoryId
118
+ };
119
+ }
120
+ return {
121
+ ...imageMountOptions,
122
+ imageEditing: {
123
+ allowOverwrite: false
124
+ },
125
+ tokenUrl: ckboxConfig.tokenUrl,
126
+ onClose: () => this._handleImageEditorClose(),
127
+ onSave: (asset) => this._handleImageEditorSave(state, asset)
128
+ };
129
+ }
130
+ /**
131
+ * Initializes event lister for an event of removing an image.
132
+ */
133
+ _prepareListeners() {
134
+ // Abort editing processing when the image has been removed.
135
+ this.listenTo(this.editor.model.document, 'change:data', () => {
136
+ const processingStates = this._getProcessingStatesOfDeletedImages();
137
+ processingStates.forEach(processingState => {
138
+ processingState.controller.abort();
139
+ });
140
+ });
141
+ }
142
+ /**
143
+ * Gets processing states of images that have been deleted in the mean time.
144
+ */
145
+ _getProcessingStatesOfDeletedImages() {
146
+ const states = [];
147
+ for (const state of this._processInProgress.values()) {
148
+ if (state.element.root.rootName == '$graveyard') {
149
+ states.push(state);
150
+ }
151
+ }
152
+ return states;
153
+ }
154
+ _checkIfElementIsBeingProcessed(selectedElement) {
155
+ for (const { element } of this._processInProgress) {
156
+ if (isEqual(element, selectedElement)) {
157
+ return true;
158
+ }
159
+ }
160
+ return false;
161
+ }
162
+ /**
163
+ * Closes the CKBox Image Editor dialog.
164
+ */
165
+ _handleImageEditorClose() {
166
+ if (!this._wrapper) {
167
+ return;
168
+ }
169
+ this._wrapper.remove();
170
+ this._wrapper = null;
171
+ this.editor.editing.view.focus();
172
+ this.refresh();
173
+ }
174
+ /**
175
+ * Save edited image. In case server respond with "success" replace with edited image,
176
+ * otherwise show notification error.
177
+ */
178
+ _handleImageEditorSave(state, asset) {
179
+ const t = this.editor.locale.t;
180
+ const notification = this.editor.plugins.get(Notification);
181
+ const pendingActions = this.editor.plugins.get(PendingActions);
182
+ const action = pendingActions.add(t('Processing the edited image.'));
183
+ this._processInProgress.add(state);
184
+ this._showImageProcessingIndicator(state.element, asset);
185
+ this.refresh();
186
+ this._waitForAssetProcessed(asset.data.id, state.controller.signal)
187
+ .then(asset => {
188
+ this._replaceImage(state.element, asset);
189
+ }, error => {
190
+ // Remove processing indicator. It was added only to ViewElement.
191
+ this.editor.editing.reconvertItem(state.element);
192
+ if (state.controller.signal.aborted) {
193
+ return;
194
+ }
195
+ if (!error || error instanceof CKEditorError) {
196
+ notification.showWarning(t('Server failed to process the image.'), {
197
+ namespace: 'ckbox'
198
+ });
199
+ }
200
+ else {
201
+ console.error(error);
202
+ }
203
+ }).finally(() => {
204
+ this._processInProgress.delete(state);
205
+ pendingActions.remove(action);
206
+ this.refresh();
207
+ });
208
+ }
209
+ /**
210
+ * Get asset's status on server. If server responds with "success" status then
211
+ * image is already proceeded and ready for saving.
212
+ */
213
+ async _getAssetStatusFromServer(id, signal) {
214
+ const ckboxUtils = this.editor.plugins.get(CKBoxUtils);
215
+ const url = new URL('assets/' + id, this.editor.config.get('ckbox.serviceOrigin'));
216
+ const response = await sendHttpRequest({
217
+ url,
218
+ signal,
219
+ authorization: ckboxUtils.getToken().value
220
+ });
221
+ const status = response.metadata.metadataProcessingStatus;
222
+ if (!status || status == 'queued') {
223
+ /**
224
+ * Image has not been processed yet.
225
+ *
226
+ * @error ckbox-image-not-processed
227
+ */
228
+ throw new CKEditorError('ckbox-image-not-processed');
229
+ }
230
+ return { data: { ...response } };
231
+ }
232
+ /**
233
+ * Waits for an asset to be processed.
234
+ * It retries retrieving asset status from the server in case of failure.
235
+ */
236
+ async _waitForAssetProcessed(id, signal) {
237
+ const result = await retry(() => this._getAssetStatusFromServer(id, signal), {
238
+ signal,
239
+ maxAttempts: 5
240
+ });
241
+ if (result.data.metadata.metadataProcessingStatus != 'success') {
242
+ /**
243
+ * The image processing failed.
244
+ *
245
+ * @error ckbox-image-processing-failed
246
+ */
247
+ throw new CKEditorError('ckbox-image-processing-failed');
248
+ }
249
+ return result;
250
+ }
251
+ /**
252
+ * Shows processing indicator while image is processing.
253
+ *
254
+ * @param asset Data about certain asset.
255
+ */
256
+ _showImageProcessingIndicator(element, asset) {
257
+ const editor = this.editor;
258
+ editor.editing.view.change(writer => {
259
+ const imageElementView = editor.editing.mapper.toViewElement(element);
260
+ const imageUtils = this.editor.plugins.get('ImageUtils');
261
+ const img = imageUtils.findViewImgElement(imageElementView);
262
+ writer.removeStyle('aspect-ratio', img);
263
+ writer.setAttribute('width', asset.data.metadata.width, img);
264
+ writer.setAttribute('height', asset.data.metadata.height, img);
265
+ writer.setStyle('width', `${asset.data.metadata.width}px`, img);
266
+ writer.setStyle('height', `${asset.data.metadata.height}px`, img);
267
+ writer.addClass('image-processing', imageElementView);
268
+ });
269
+ }
270
+ /**
271
+ * Replace the edited image with the new one.
272
+ */
273
+ _replaceImage(element, asset) {
274
+ const editor = this.editor;
275
+ const { imageFallbackUrl, imageSources, imageWidth, imageHeight, imagePlaceholder } = prepareImageAssetAttributes(asset);
276
+ const previousSelectionRanges = Array.from(editor.model.document.selection.getRanges());
277
+ editor.model.change(writer => {
278
+ writer.setSelection(element, 'on');
279
+ editor.execute('insertImage', {
280
+ source: {
281
+ src: imageFallbackUrl,
282
+ sources: imageSources,
283
+ width: imageWidth,
284
+ height: imageHeight,
285
+ ...(imagePlaceholder ? { placeholder: imagePlaceholder } : null),
286
+ ...(element.hasAttribute('alt') ? { alt: element.getAttribute('alt') } : null)
287
+ }
288
+ });
289
+ const previousChildren = element.getChildren();
290
+ element = editor.model.document.selection.getSelectedElement();
291
+ for (const child of previousChildren) {
292
+ writer.append(writer.cloneElement(child), element);
293
+ }
294
+ writer.setAttribute('ckboxImageId', asset.data.id, element);
295
+ writer.setSelection(previousSelectionRanges);
296
+ });
297
+ }
298
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module ckbox/ckboximageedit/ckboximageeditediting
7
+ */
8
+ import { PendingActions, Plugin } from 'ckeditor5/src/core';
9
+ import { Notification } from 'ckeditor5/src/ui';
10
+ import CKBoxEditing from '../ckboxediting';
11
+ import CKBoxUtils from '../ckboxutils';
12
+ /**
13
+ * The CKBox image edit editing plugin.
14
+ */
15
+ export default class CKBoxImageEditEditing extends Plugin {
16
+ /**
17
+ * @inheritDoc
18
+ */
19
+ static get pluginName(): "CKBoxImageEditEditing";
20
+ /**
21
+ * @inheritDoc
22
+ */
23
+ static get requires(): readonly [typeof CKBoxEditing, typeof CKBoxUtils, typeof PendingActions, typeof Notification, "ImageUtils", "ImageEditing"];
24
+ /**
25
+ * @inheritDoc
26
+ */
27
+ init(): void;
28
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module ckbox/ckboximageedit/ckboximageeditediting
7
+ */
8
+ import { PendingActions, Plugin } from 'ckeditor5/src/core';
9
+ import { Notification } from 'ckeditor5/src/ui';
10
+ import CKBoxImageEditCommand from './ckboximageeditcommand';
11
+ import CKBoxEditing from '../ckboxediting';
12
+ import CKBoxUtils from '../ckboxutils';
13
+ /**
14
+ * The CKBox image edit editing plugin.
15
+ */
16
+ export default class CKBoxImageEditEditing extends Plugin {
17
+ /**
18
+ * @inheritDoc
19
+ */
20
+ static get pluginName() {
21
+ return 'CKBoxImageEditEditing';
22
+ }
23
+ /**
24
+ * @inheritDoc
25
+ */
26
+ static get requires() {
27
+ return [CKBoxEditing, CKBoxUtils, PendingActions, Notification, 'ImageUtils', 'ImageEditing'];
28
+ }
29
+ /**
30
+ * @inheritDoc
31
+ */
32
+ init() {
33
+ const { editor } = this;
34
+ editor.commands.add('ckboxImageEdit', new CKBoxImageEditCommand(editor));
35
+ }
36
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module ckbox/ckboximageedit/ckboximageeditui
7
+ */
8
+ import { Plugin } from 'ckeditor5/src/core';
9
+ /**
10
+ * The UI plugin of the CKBox image edit feature.
11
+ *
12
+ * It registers the `'ckboxImageEdit'` UI button in the editor's {@link module:ui/componentfactory~ComponentFactory component factory}
13
+ * that allows you to open the CKBox dialog and edit the image.
14
+ */
15
+ export default class CKBoxImageEditUI extends Plugin {
16
+ /**
17
+ * @inheritDoc
18
+ */
19
+ static get pluginName(): "CKBoxImageEditUI";
20
+ /**
21
+ * @inheritDoc
22
+ */
23
+ init(): void;
24
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module ckbox/ckboximageedit/ckboximageeditui
7
+ */
8
+ import { Plugin } from 'ckeditor5/src/core';
9
+ import { ButtonView } from 'ckeditor5/src/ui';
10
+ import ckboxImageEditIcon from '../../theme/icons/ckbox-image-edit.svg';
11
+ /**
12
+ * The UI plugin of the CKBox image edit feature.
13
+ *
14
+ * It registers the `'ckboxImageEdit'` UI button in the editor's {@link module:ui/componentfactory~ComponentFactory component factory}
15
+ * that allows you to open the CKBox dialog and edit the image.
16
+ */
17
+ export default class CKBoxImageEditUI extends Plugin {
18
+ /**
19
+ * @inheritDoc
20
+ */
21
+ static get pluginName() {
22
+ return 'CKBoxImageEditUI';
23
+ }
24
+ /**
25
+ * @inheritDoc
26
+ */
27
+ init() {
28
+ const editor = this.editor;
29
+ editor.ui.componentFactory.add('ckboxImageEdit', locale => {
30
+ const command = editor.commands.get('ckboxImageEdit');
31
+ const view = new ButtonView(locale);
32
+ const t = locale.t;
33
+ view.set({
34
+ label: t('Edit image'),
35
+ icon: ckboxImageEditIcon,
36
+ tooltip: true
37
+ });
38
+ view.bind('isOn').to(command, 'value', command, 'isEnabled', (value, isEnabled) => value && isEnabled);
39
+ view.bind('isEnabled').to(command);
40
+ // Execute the command.
41
+ this.listenTo(view, 'execute', () => {
42
+ editor.execute('ckboxImageEdit');
43
+ editor.editing.view.focus();
44
+ });
45
+ return view;
46
+ });
47
+ }
48
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ import type { Element } from 'ckeditor5/src/engine';
6
+ import type { CKBoxConfig } from '../ckboxconfig';
7
+ /**
8
+ * @internal
9
+ */
10
+ export declare function createEditabilityChecker(allowExternalImagesEditing: CKBoxConfig['allowExternalImagesEditing']): (element: Element) => boolean;