@ckeditor/ckeditor5-ckbox 40.0.0 → 40.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. package/LICENSE.md +6 -2
  2. package/build/ckbox.js +2 -2
  3. package/build/translations/ar.js +1 -1
  4. package/build/translations/az.js +1 -1
  5. package/build/translations/bg.js +1 -1
  6. package/build/translations/bn.js +1 -1
  7. package/build/translations/ca.js +1 -1
  8. package/build/translations/cs.js +1 -1
  9. package/build/translations/da.js +1 -1
  10. package/build/translations/de.js +1 -1
  11. package/build/translations/el.js +1 -1
  12. package/build/translations/en-au.js +1 -1
  13. package/build/translations/es-co.js +1 -1
  14. package/build/translations/es.js +1 -1
  15. package/build/translations/et.js +1 -1
  16. package/build/translations/fa.js +1 -1
  17. package/build/translations/fi.js +1 -1
  18. package/build/translations/fr.js +1 -1
  19. package/build/translations/gl.js +1 -1
  20. package/build/translations/he.js +1 -1
  21. package/build/translations/hi.js +1 -1
  22. package/build/translations/hr.js +1 -1
  23. package/build/translations/hu.js +1 -1
  24. package/build/translations/id.js +1 -1
  25. package/build/translations/it.js +1 -1
  26. package/build/translations/ja.js +1 -1
  27. package/build/translations/ko.js +1 -1
  28. package/build/translations/lt.js +1 -1
  29. package/build/translations/lv.js +1 -1
  30. package/build/translations/ms.js +1 -1
  31. package/build/translations/nl.js +1 -1
  32. package/build/translations/no.js +1 -1
  33. package/build/translations/pl.js +1 -1
  34. package/build/translations/pt-br.js +1 -1
  35. package/build/translations/pt.js +1 -1
  36. package/build/translations/ro.js +1 -1
  37. package/build/translations/ru.js +1 -1
  38. package/build/translations/sk.js +1 -1
  39. package/build/translations/sq.js +1 -1
  40. package/build/translations/sr-latn.js +1 -1
  41. package/build/translations/sr.js +1 -1
  42. package/build/translations/sv.js +1 -1
  43. package/build/translations/th.js +1 -1
  44. package/build/translations/tr.js +1 -1
  45. package/build/translations/ug.js +1 -1
  46. package/build/translations/uk.js +1 -1
  47. package/build/translations/ur.js +1 -1
  48. package/build/translations/uz.js +1 -1
  49. package/build/translations/vi.js +1 -1
  50. package/build/translations/zh-cn.js +1 -1
  51. package/build/translations/zh.js +1 -1
  52. package/ckeditor5-metadata.json +17 -0
  53. package/lang/contexts.json +6 -2
  54. package/lang/translations/ar.po +18 -2
  55. package/lang/translations/az.po +18 -2
  56. package/lang/translations/bg.po +18 -2
  57. package/lang/translations/bn.po +18 -2
  58. package/lang/translations/ca.po +18 -2
  59. package/lang/translations/cs.po +18 -2
  60. package/lang/translations/da.po +18 -2
  61. package/lang/translations/de.po +18 -2
  62. package/lang/translations/el.po +18 -2
  63. package/lang/translations/en-au.po +18 -2
  64. package/lang/translations/en.po +18 -2
  65. package/lang/translations/es-co.po +18 -2
  66. package/lang/translations/es.po +18 -2
  67. package/lang/translations/et.po +18 -2
  68. package/lang/translations/fa.po +18 -2
  69. package/lang/translations/fi.po +18 -2
  70. package/lang/translations/fr.po +18 -2
  71. package/lang/translations/gl.po +18 -2
  72. package/lang/translations/he.po +18 -2
  73. package/lang/translations/hi.po +18 -2
  74. package/lang/translations/hr.po +18 -2
  75. package/lang/translations/hu.po +18 -2
  76. package/lang/translations/id.po +18 -2
  77. package/lang/translations/it.po +18 -2
  78. package/lang/translations/ja.po +18 -2
  79. package/lang/translations/ko.po +18 -2
  80. package/lang/translations/lt.po +18 -2
  81. package/lang/translations/lv.po +18 -2
  82. package/lang/translations/ms.po +18 -2
  83. package/lang/translations/nl.po +18 -2
  84. package/lang/translations/no.po +18 -2
  85. package/lang/translations/pl.po +18 -2
  86. package/lang/translations/pt-br.po +18 -2
  87. package/lang/translations/pt.po +18 -2
  88. package/lang/translations/ro.po +18 -2
  89. package/lang/translations/ru.po +18 -2
  90. package/lang/translations/sk.po +18 -2
  91. package/lang/translations/sq.po +18 -2
  92. package/lang/translations/sr-latn.po +18 -2
  93. package/lang/translations/sr.po +18 -2
  94. package/lang/translations/sv.po +18 -2
  95. package/lang/translations/th.po +18 -2
  96. package/lang/translations/tr.po +18 -2
  97. package/lang/translations/ug.po +18 -2
  98. package/lang/translations/uk.po +18 -2
  99. package/lang/translations/ur.po +18 -2
  100. package/lang/translations/uz.po +18 -2
  101. package/lang/translations/vi.po +18 -2
  102. package/lang/translations/zh-cn.po +18 -2
  103. package/lang/translations/zh.po +18 -2
  104. package/package.json +4 -2
  105. package/src/augmentation.d.ts +32 -22
  106. package/src/augmentation.js +5 -5
  107. package/src/ckbox.d.ts +33 -33
  108. package/src/ckbox.js +37 -37
  109. package/src/ckboxcommand.d.ts +114 -110
  110. package/src/ckboxcommand.js +332 -302
  111. package/src/ckboxconfig.d.ts +325 -283
  112. package/src/ckboxconfig.js +5 -5
  113. package/src/ckboxediting.d.ts +45 -52
  114. package/src/ckboxediting.js +321 -362
  115. package/src/ckboximageedit/ckboximageeditcommand.d.ts +97 -0
  116. package/src/ckboximageedit/ckboximageeditcommand.js +298 -0
  117. package/src/ckboximageedit/ckboximageeditediting.d.ts +28 -0
  118. package/src/ckboximageedit/ckboximageeditediting.js +36 -0
  119. package/src/ckboximageedit/ckboximageeditui.d.ts +24 -0
  120. package/src/ckboximageedit/ckboximageeditui.js +48 -0
  121. package/src/ckboximageedit/utils.d.ts +10 -0
  122. package/src/ckboximageedit/utils.js +48 -0
  123. package/src/ckboximageedit.d.ts +24 -0
  124. package/src/ckboximageedit.js +28 -0
  125. package/src/ckboxui.d.ts +21 -21
  126. package/src/ckboxui.js +74 -47
  127. package/src/ckboxuploadadapter.d.ts +33 -38
  128. package/src/ckboxuploadadapter.js +130 -275
  129. package/src/ckboxutils.d.ts +50 -0
  130. package/src/ckboxutils.js +183 -0
  131. package/src/index.d.ts +17 -13
  132. package/src/index.js +14 -11
  133. package/src/utils.d.ts +63 -28
  134. package/src/utils.js +175 -49
  135. package/theme/ckboximageedit.css +53 -0
  136. package/theme/icons/ckbox-image-edit.svg +1 -0
  137. package/build/ckbox.js.map +0 -1
package/src/ckboxui.d.ts CHANGED
@@ -1,21 +1,21 @@
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/ckboxui
7
- */
8
- import { Plugin } from 'ckeditor5/src/core';
9
- /**
10
- * The CKBoxUI plugin. It introduces the `'ckbox'` toolbar button.
11
- */
12
- export default class CKBoxUI extends Plugin {
13
- /**
14
- * @inheritDoc
15
- */
16
- static get pluginName(): "CKBoxUI";
17
- /**
18
- * @inheritDoc
19
- */
20
- afterInit(): void;
21
- }
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/ckboxui
7
+ */
8
+ import { Plugin } from 'ckeditor5/src/core';
9
+ /**
10
+ * The CKBoxUI plugin. It introduces the `'ckbox'` toolbar button.
11
+ */
12
+ export default class CKBoxUI extends Plugin {
13
+ /**
14
+ * @inheritDoc
15
+ */
16
+ static get pluginName(): "CKBoxUI";
17
+ /**
18
+ * @inheritDoc
19
+ */
20
+ afterInit(): void;
21
+ }
package/src/ckboxui.js CHANGED
@@ -1,47 +1,74 @@
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/ckboxui
7
- */
8
- import { Plugin } from 'ckeditor5/src/core';
9
- import { ButtonView } from 'ckeditor5/src/ui';
10
- import browseFilesIcon from '../theme/icons/browse-files.svg';
11
- /**
12
- * The CKBoxUI plugin. It introduces the `'ckbox'` toolbar button.
13
- */
14
- export default class CKBoxUI extends Plugin {
15
- /**
16
- * @inheritDoc
17
- */
18
- static get pluginName() {
19
- return 'CKBoxUI';
20
- }
21
- /**
22
- * @inheritDoc
23
- */
24
- afterInit() {
25
- const editor = this.editor;
26
- const command = editor.commands.get('ckbox');
27
- // Do not register the `ckbox` button if the command does not exist.
28
- if (!command) {
29
- return;
30
- }
31
- const t = editor.t;
32
- const componentFactory = editor.ui.componentFactory;
33
- componentFactory.add('ckbox', locale => {
34
- const button = new ButtonView(locale);
35
- button.set({
36
- label: t('Open file manager'),
37
- icon: browseFilesIcon,
38
- tooltip: true
39
- });
40
- button.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');
41
- button.on('execute', () => {
42
- editor.execute('ckbox');
43
- });
44
- return button;
45
- });
46
- }
47
- }
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/ckboxui
7
+ */
8
+ import { icons, Plugin } from 'ckeditor5/src/core';
9
+ import { ButtonView } from 'ckeditor5/src/ui';
10
+ import browseFilesIcon from '../theme/icons/browse-files.svg';
11
+ /**
12
+ * The CKBoxUI plugin. It introduces the `'ckbox'` toolbar button.
13
+ */
14
+ export default class CKBoxUI extends Plugin {
15
+ /**
16
+ * @inheritDoc
17
+ */
18
+ static get pluginName() {
19
+ return 'CKBoxUI';
20
+ }
21
+ /**
22
+ * @inheritDoc
23
+ */
24
+ afterInit() {
25
+ const editor = this.editor;
26
+ const command = editor.commands.get('ckbox');
27
+ // Do not register the `ckbox` button if the command does not exist.
28
+ if (!command) {
29
+ return;
30
+ }
31
+ const t = editor.t;
32
+ const componentFactory = editor.ui.componentFactory;
33
+ componentFactory.add('ckbox', locale => {
34
+ const button = new ButtonView(locale);
35
+ button.set({
36
+ label: t('Open file manager'),
37
+ icon: browseFilesIcon,
38
+ tooltip: true
39
+ });
40
+ button.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');
41
+ button.on('execute', () => {
42
+ editor.execute('ckbox');
43
+ });
44
+ return button;
45
+ });
46
+ if (editor.plugins.has('ImageInsertUI')) {
47
+ const imageInsertUI = editor.plugins.get('ImageInsertUI');
48
+ imageInsertUI.registerIntegration({
49
+ name: 'assetManager',
50
+ observable: command,
51
+ buttonViewCreator: () => {
52
+ const button = this.editor.ui.componentFactory.create('ckbox');
53
+ button.icon = icons.imageAssetManager;
54
+ button.bind('label').to(imageInsertUI, 'isImageSelected', isImageSelected => isImageSelected ?
55
+ t('Replace image with file manager') :
56
+ t('Insert image with file manager'));
57
+ return button;
58
+ },
59
+ formViewCreator: () => {
60
+ const button = this.editor.ui.componentFactory.create('ckbox');
61
+ button.icon = icons.imageAssetManager;
62
+ button.withText = true;
63
+ button.bind('label').to(imageInsertUI, 'isImageSelected', isImageSelected => isImageSelected ?
64
+ t('Replace with file manager') :
65
+ t('Insert with file manager'));
66
+ button.on('execute', () => {
67
+ imageInsertUI.dropdownView.isOpen = false;
68
+ });
69
+ return button;
70
+ }
71
+ });
72
+ }
73
+ }
74
+ }
@@ -1,38 +1,33 @@
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/ckboxuploadadapter
7
- */
8
- import { Plugin } from 'ckeditor5/src/core';
9
- import { FileRepository } from 'ckeditor5/src/upload';
10
- import CKBoxEditing from './ckboxediting';
11
- /**
12
- * A plugin that enables file uploads in CKEditor 5 using the CKBox server–side connector.
13
- * See the {@glink features/file-management/ckbox CKBox file manager integration} guide to learn how to configure
14
- * and use this feature as well as find out more about the full integration with the file manager
15
- * provided by the {@link module:ckbox/ckbox~CKBox} plugin.
16
- *
17
- * Check out the {@glink features/images/image-upload/image-upload Image upload overview} guide to learn about
18
- * other ways to upload images into CKEditor 5.
19
- */
20
- export default class CKBoxUploadAdapter extends Plugin {
21
- /**
22
- * @inheritDoc
23
- */
24
- static get requires(): readonly ["ImageUploadEditing", "ImageUploadProgress", typeof FileRepository, typeof CKBoxEditing];
25
- /**
26
- * @inheritDoc
27
- */
28
- static get pluginName(): "CKBoxUploadAdapter";
29
- /**
30
- * @inheritDoc
31
- */
32
- afterInit(): Promise<void>;
33
- }
34
- export interface AvailableCategory {
35
- id: string;
36
- name: string;
37
- extensions: Array<string>;
38
- }
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/ckboxuploadadapter
7
+ */
8
+ import { Plugin } from 'ckeditor5/src/core';
9
+ import { FileRepository } from 'ckeditor5/src/upload';
10
+ import CKBoxEditing from './ckboxediting';
11
+ /**
12
+ * A plugin that enables file uploads in CKEditor 5 using the CKBox server–side connector.
13
+ * See the {@glink features/file-management/ckbox CKBox file manager integration} guide to learn how to configure
14
+ * and use this feature as well as find out more about the full integration with the file manager
15
+ * provided by the {@link module:ckbox/ckbox~CKBox} plugin.
16
+ *
17
+ * Check out the {@glink features/images/image-upload/image-upload Image upload overview} guide to learn about
18
+ * other ways to upload images into CKEditor 5.
19
+ */
20
+ export default class CKBoxUploadAdapter extends Plugin {
21
+ /**
22
+ * @inheritDoc
23
+ */
24
+ static get requires(): readonly ["ImageUploadEditing", "ImageUploadProgress", typeof FileRepository, typeof CKBoxEditing];
25
+ /**
26
+ * @inheritDoc
27
+ */
28
+ static get pluginName(): "CKBoxUploadAdapter";
29
+ /**
30
+ * @inheritDoc
31
+ */
32
+ afterInit(): Promise<void>;
33
+ }
@@ -1,275 +1,130 @@
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 AbortController, FormData, URL, XMLHttpRequest, window */
6
- /**
7
- * @module ckbox/ckboxuploadadapter
8
- */
9
- import { Plugin } from 'ckeditor5/src/core';
10
- import { FileRepository } from 'ckeditor5/src/upload';
11
- import { logError } from 'ckeditor5/src/utils';
12
- import CKBoxEditing from './ckboxediting';
13
- import { getImageUrls, getWorkspaceId } from './utils';
14
- /**
15
- * A plugin that enables file uploads in CKEditor 5 using the CKBox server–side connector.
16
- * See the {@glink features/file-management/ckbox CKBox file manager integration} guide to learn how to configure
17
- * and use this feature as well as find out more about the full integration with the file manager
18
- * provided by the {@link module:ckbox/ckbox~CKBox} plugin.
19
- *
20
- * Check out the {@glink features/images/image-upload/image-upload Image upload overview} guide to learn about
21
- * other ways to upload images into CKEditor 5.
22
- */
23
- export default class CKBoxUploadAdapter extends Plugin {
24
- /**
25
- * @inheritDoc
26
- */
27
- static get requires() {
28
- return ['ImageUploadEditing', 'ImageUploadProgress', FileRepository, CKBoxEditing];
29
- }
30
- /**
31
- * @inheritDoc
32
- */
33
- static get pluginName() {
34
- return 'CKBoxUploadAdapter';
35
- }
36
- /**
37
- * @inheritDoc
38
- */
39
- async afterInit() {
40
- const editor = this.editor;
41
- const hasConfiguration = !!editor.config.get('ckbox');
42
- const isLibraryLoaded = !!window.CKBox;
43
- // Editor supports only one upload adapter. Register the CKBox upload adapter (and potentially overwrite other one) only when the
44
- // integrator intentionally wants to use the CKBox plugin, i.e. when the `config.ckbox` exists or the CKBox JavaScript library is
45
- // loaded.
46
- if (!hasConfiguration && !isLibraryLoaded) {
47
- return;
48
- }
49
- const fileRepository = editor.plugins.get(FileRepository);
50
- const ckboxEditing = editor.plugins.get(CKBoxEditing);
51
- fileRepository.createUploadAdapter = loader => {
52
- return new Adapter(loader, ckboxEditing.getToken(), editor);
53
- };
54
- const shouldInsertDataId = !editor.config.get('ckbox.ignoreDataId');
55
- const imageUploadEditing = editor.plugins.get('ImageUploadEditing');
56
- // Mark uploaded assets with the `ckboxImageId` attribute. Its value represents an ID in CKBox.
57
- if (shouldInsertDataId) {
58
- imageUploadEditing.on('uploadComplete', (evt, { imageElement, data }) => {
59
- editor.model.change(writer => {
60
- writer.setAttribute('ckboxImageId', data.ckboxImageId, imageElement);
61
- });
62
- });
63
- }
64
- }
65
- }
66
- /**
67
- * Upload adapter for CKBox.
68
- */
69
- class Adapter {
70
- /**
71
- * Creates a new adapter instance.
72
- */
73
- constructor(loader, token, editor) {
74
- this.loader = loader;
75
- this.token = token;
76
- this.editor = editor;
77
- this.controller = new AbortController();
78
- this.serviceOrigin = editor.config.get('ckbox.serviceOrigin');
79
- }
80
- /**
81
- * The ID of workspace to use.
82
- */
83
- getWorkspaceId() {
84
- const t = this.editor.t;
85
- const cannotAccessDefaultWorkspaceError = t('Cannot access default workspace.');
86
- const defaultWorkspaceId = this.editor.config.get('ckbox.defaultUploadWorkspaceId');
87
- const workspaceId = getWorkspaceId(this.token, defaultWorkspaceId);
88
- if (workspaceId == null) {
89
- /**
90
- * The user is not authorized to access the workspace defined in the`ckbox.defaultUploadWorkspaceId` configuration.
91
- *
92
- * @error ckbox-access-default-workspace-error
93
- */
94
- logError('ckbox-access-default-workspace-error');
95
- throw cannotAccessDefaultWorkspaceError;
96
- }
97
- return workspaceId;
98
- }
99
- /**
100
- * Resolves a promise with an array containing available categories with which the uploaded file can be associated.
101
- *
102
- * If the API returns limited results, the method will collect all items.
103
- */
104
- async getAvailableCategories(offset = 0) {
105
- const ITEMS_PER_REQUEST = 50;
106
- const categoryUrl = new URL('categories', this.serviceOrigin);
107
- categoryUrl.searchParams.set('limit', ITEMS_PER_REQUEST.toString());
108
- categoryUrl.searchParams.set('offset', offset.toString());
109
- categoryUrl.searchParams.set('workspaceId', this.getWorkspaceId());
110
- return this._sendHttpRequest({ url: categoryUrl })
111
- .then(async (data) => {
112
- const remainingItems = data.totalCount - (offset + ITEMS_PER_REQUEST);
113
- if (remainingItems > 0) {
114
- const offsetItems = await this.getAvailableCategories(offset + ITEMS_PER_REQUEST);
115
- return [
116
- ...data.items,
117
- ...offsetItems
118
- ];
119
- }
120
- return data.items;
121
- })
122
- .catch(() => {
123
- this.controller.signal.throwIfAborted();
124
- /**
125
- * Fetching a list of available categories with which an uploaded file can be associated failed.
126
- *
127
- * @error ckbox-fetch-category-http-error
128
- */
129
- logError('ckbox-fetch-category-http-error');
130
- });
131
- }
132
- /**
133
- * Resolves a promise with an object containing a category with which the uploaded file is associated or an error code.
134
- */
135
- async getCategoryIdForFile(file) {
136
- const extension = getFileExtension(file.name);
137
- const allCategories = await this.getAvailableCategories();
138
- // Couldn't fetch all categories. Perhaps the authorization token is invalid.
139
- if (!allCategories) {
140
- return null;
141
- }
142
- // The plugin allows defining to which category the uploaded file should be assigned.
143
- const defaultCategories = this.editor.config.get('ckbox.defaultUploadCategories');
144
- // If a user specifies the plugin configuration, find the first category that accepts the uploaded file.
145
- if (defaultCategories) {
146
- const userCategory = Object.keys(defaultCategories).find(category => {
147
- return defaultCategories[category].find(e => e.toLowerCase() == extension);
148
- });
149
- // If found, return its ID if the category exists on the server side.
150
- if (userCategory) {
151
- const serverCategory = allCategories.find(category => category.id === userCategory || category.name === userCategory);
152
- if (!serverCategory) {
153
- return null;
154
- }
155
- return serverCategory.id;
156
- }
157
- }
158
- // Otherwise, find the first category that accepts the uploaded file and returns its ID.
159
- const category = allCategories.find(category => category.extensions.find(e => e.toLowerCase() == extension));
160
- if (!category) {
161
- return null;
162
- }
163
- return category.id;
164
- }
165
- /**
166
- * Starts the upload process.
167
- *
168
- * @see module:upload/filerepository~UploadAdapter#upload
169
- */
170
- async upload() {
171
- const t = this.editor.t;
172
- const cannotFindCategoryError = t('Cannot determine a category for the uploaded file.');
173
- const file = (await this.loader.file);
174
- const category = await this.getCategoryIdForFile(file);
175
- if (!category) {
176
- return Promise.reject(cannotFindCategoryError);
177
- }
178
- const uploadUrl = new URL('assets', this.serviceOrigin);
179
- const formData = new FormData();
180
- uploadUrl.searchParams.set('workspaceId', this.getWorkspaceId());
181
- formData.append('categoryId', category);
182
- formData.append('file', file);
183
- const requestConfig = {
184
- method: 'POST',
185
- url: uploadUrl,
186
- data: formData,
187
- onUploadProgress: (evt) => {
188
- /* istanbul ignore else -- @preserve */
189
- if (evt.lengthComputable) {
190
- this.loader.uploadTotal = evt.total;
191
- this.loader.uploaded = evt.loaded;
192
- }
193
- }
194
- };
195
- return this._sendHttpRequest(requestConfig)
196
- .then(async (data) => {
197
- const imageUrls = getImageUrls(data.imageUrls);
198
- return {
199
- ckboxImageId: data.id,
200
- default: imageUrls.imageFallbackUrl,
201
- sources: imageUrls.imageSources
202
- };
203
- })
204
- .catch(() => {
205
- const genericError = t('Cannot upload file:') + ` ${file.name}.`;
206
- return Promise.reject(genericError);
207
- });
208
- }
209
- /**
210
- * Aborts the upload process.
211
- *
212
- * @see module:upload/filerepository~UploadAdapter#abort
213
- */
214
- abort() {
215
- this.controller.abort();
216
- }
217
- /**
218
- * Sends the HTTP request.
219
- *
220
- * @param config.url the URL where the request will be sent.
221
- * @param config.method The HTTP method.
222
- * @param config.data Additional data to send.
223
- * @param config.onUploadProgress A callback informing about the upload progress.
224
- */
225
- _sendHttpRequest({ url, method = 'GET', data, onUploadProgress }) {
226
- const signal = this.controller.signal;
227
- const xhr = new XMLHttpRequest();
228
- xhr.open(method, url.toString(), true);
229
- xhr.setRequestHeader('Authorization', this.token.value);
230
- xhr.setRequestHeader('CKBox-Version', 'CKEditor 5');
231
- xhr.responseType = 'json';
232
- // The callback is attached to the `signal#abort` event.
233
- const abortCallback = () => {
234
- xhr.abort();
235
- };
236
- return new Promise((resolve, reject) => {
237
- signal.addEventListener('abort', abortCallback);
238
- xhr.addEventListener('loadstart', () => {
239
- signal.addEventListener('abort', abortCallback);
240
- });
241
- xhr.addEventListener('loadend', () => {
242
- signal.removeEventListener('abort', abortCallback);
243
- });
244
- xhr.addEventListener('error', () => {
245
- reject();
246
- });
247
- xhr.addEventListener('abort', () => {
248
- reject();
249
- });
250
- xhr.addEventListener('load', async () => {
251
- const response = xhr.response;
252
- if (!response || response.statusCode >= 400) {
253
- return reject(response && response.message);
254
- }
255
- return resolve(response);
256
- });
257
- /* istanbul ignore else -- @preserve */
258
- if (onUploadProgress) {
259
- xhr.upload.addEventListener('progress', evt => {
260
- onUploadProgress(evt);
261
- });
262
- }
263
- // Send the request.
264
- xhr.send(data);
265
- });
266
- }
267
- }
268
- /**
269
- * Returns an extension from the given value.
270
- */
271
- function getFileExtension(value) {
272
- const extensionRegExp = /\.(?<ext>[^.]+)$/;
273
- const match = value.match(extensionRegExp);
274
- return match.groups.ext.toLowerCase();
275
- }
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 AbortController, FormData, URL, window */
6
+ /**
7
+ * @module ckbox/ckboxuploadadapter
8
+ */
9
+ import { Plugin } from 'ckeditor5/src/core';
10
+ import { FileRepository } from 'ckeditor5/src/upload';
11
+ import CKBoxEditing from './ckboxediting';
12
+ import { getImageUrls, sendHttpRequest } from './utils';
13
+ import CKBoxUtils from './ckboxutils';
14
+ /**
15
+ * A plugin that enables file uploads in CKEditor 5 using the CKBox server–side connector.
16
+ * See the {@glink features/file-management/ckbox CKBox file manager integration} guide to learn how to configure
17
+ * and use this feature as well as find out more about the full integration with the file manager
18
+ * provided by the {@link module:ckbox/ckbox~CKBox} plugin.
19
+ *
20
+ * Check out the {@glink features/images/image-upload/image-upload Image upload overview} guide to learn about
21
+ * other ways to upload images into CKEditor 5.
22
+ */
23
+ export default class CKBoxUploadAdapter extends Plugin {
24
+ /**
25
+ * @inheritDoc
26
+ */
27
+ static get requires() {
28
+ return ['ImageUploadEditing', 'ImageUploadProgress', FileRepository, CKBoxEditing];
29
+ }
30
+ /**
31
+ * @inheritDoc
32
+ */
33
+ static get pluginName() {
34
+ return 'CKBoxUploadAdapter';
35
+ }
36
+ /**
37
+ * @inheritDoc
38
+ */
39
+ async afterInit() {
40
+ const editor = this.editor;
41
+ const hasConfiguration = !!editor.config.get('ckbox');
42
+ const isLibraryLoaded = !!window.CKBox;
43
+ // Editor supports only one upload adapter. Register the CKBox upload adapter (and potentially overwrite other one) only when the
44
+ // integrator intentionally wants to use the CKBox plugin, i.e. when the `config.ckbox` exists or the CKBox JavaScript library is
45
+ // loaded.
46
+ if (!hasConfiguration && !isLibraryLoaded) {
47
+ return;
48
+ }
49
+ const fileRepository = editor.plugins.get(FileRepository);
50
+ const ckboxUtils = editor.plugins.get(CKBoxUtils);
51
+ fileRepository.createUploadAdapter = loader => new Adapter(loader, editor, ckboxUtils);
52
+ const shouldInsertDataId = !editor.config.get('ckbox.ignoreDataId');
53
+ const imageUploadEditing = editor.plugins.get('ImageUploadEditing');
54
+ // Mark uploaded assets with the `ckboxImageId` attribute. Its value represents an ID in CKBox.
55
+ if (shouldInsertDataId) {
56
+ imageUploadEditing.on('uploadComplete', (evt, { imageElement, data }) => {
57
+ editor.model.change(writer => {
58
+ writer.setAttribute('ckboxImageId', data.ckboxImageId, imageElement);
59
+ });
60
+ });
61
+ }
62
+ }
63
+ }
64
+ /**
65
+ * Upload adapter for CKBox.
66
+ */
67
+ class Adapter {
68
+ /**
69
+ * Creates a new adapter instance.
70
+ */
71
+ constructor(loader, editor, ckboxUtils) {
72
+ this.loader = loader;
73
+ this.token = ckboxUtils.getToken();
74
+ this.ckboxUtils = ckboxUtils;
75
+ this.editor = editor;
76
+ this.controller = new AbortController();
77
+ this.serviceOrigin = editor.config.get('ckbox.serviceOrigin');
78
+ }
79
+ /**
80
+ * Starts the upload process.
81
+ *
82
+ * @see module:upload/filerepository~UploadAdapter#upload
83
+ */
84
+ async upload() {
85
+ const ckboxUtils = this.ckboxUtils;
86
+ const t = this.editor.t;
87
+ const file = (await this.loader.file);
88
+ const category = await ckboxUtils.getCategoryIdForFile(file, { signal: this.controller.signal });
89
+ const uploadUrl = new URL('assets', this.serviceOrigin);
90
+ const formData = new FormData();
91
+ uploadUrl.searchParams.set('workspaceId', ckboxUtils.getWorkspaceId());
92
+ formData.append('categoryId', category);
93
+ formData.append('file', file);
94
+ const requestConfig = {
95
+ method: 'POST',
96
+ url: uploadUrl,
97
+ data: formData,
98
+ onUploadProgress: (evt) => {
99
+ /* istanbul ignore else -- @preserve */
100
+ if (evt.lengthComputable) {
101
+ this.loader.uploadTotal = evt.total;
102
+ this.loader.uploaded = evt.loaded;
103
+ }
104
+ },
105
+ signal: this.controller.signal,
106
+ authorization: this.token.value
107
+ };
108
+ return sendHttpRequest(requestConfig)
109
+ .then(async (data) => {
110
+ const imageUrls = getImageUrls(data.imageUrls);
111
+ return {
112
+ ckboxImageId: data.id,
113
+ default: imageUrls.imageFallbackUrl,
114
+ sources: imageUrls.imageSources
115
+ };
116
+ })
117
+ .catch(() => {
118
+ const genericError = t('Cannot upload file:') + ` ${file.name}.`;
119
+ return Promise.reject(genericError);
120
+ });
121
+ }
122
+ /**
123
+ * Aborts the upload process.
124
+ *
125
+ * @see module:upload/filerepository~UploadAdapter#abort
126
+ */
127
+ abort() {
128
+ this.controller.abort();
129
+ }
130
+ }