@ckeditor/ckeditor5-ckbox 40.1.0 → 40.2.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.
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;