@ckeditor/ckeditor5-ckbox 38.2.0-alpha.0 → 39.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. package/README.md +0 -1
  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 -0
  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/lang/contexts.json +2 -1
  53. package/lang/translations/ar.po +4 -0
  54. package/lang/translations/az.po +4 -0
  55. package/lang/translations/bg.po +4 -0
  56. package/lang/translations/bn.po +4 -0
  57. package/lang/translations/ca.po +4 -0
  58. package/lang/translations/cs.po +4 -0
  59. package/lang/translations/da.po +4 -0
  60. package/lang/translations/de.po +4 -0
  61. package/lang/translations/el.po +4 -0
  62. package/lang/translations/en-au.po +4 -0
  63. package/lang/translations/en.po +4 -0
  64. package/lang/translations/es-co.po +4 -0
  65. package/lang/translations/es.po +4 -0
  66. package/lang/translations/et.po +4 -0
  67. package/lang/translations/fa.po +4 -0
  68. package/lang/translations/fi.po +4 -0
  69. package/lang/translations/fr.po +4 -0
  70. package/lang/translations/gl.po +4 -0
  71. package/lang/translations/he.po +4 -0
  72. package/lang/translations/hi.po +4 -0
  73. package/lang/translations/hr.po +4 -0
  74. package/lang/translations/hu.po +4 -0
  75. package/lang/translations/id.po +4 -0
  76. package/lang/translations/it.po +4 -0
  77. package/lang/translations/ja.po +4 -0
  78. package/lang/translations/ko.po +4 -0
  79. package/lang/translations/lt.po +4 -0
  80. package/lang/translations/lv.po +4 -0
  81. package/lang/translations/ms.po +4 -0
  82. package/lang/translations/nl.po +4 -0
  83. package/lang/translations/no.po +4 -0
  84. package/lang/translations/pl.po +4 -0
  85. package/lang/translations/pt-br.po +4 -0
  86. package/lang/translations/pt.po +4 -0
  87. package/lang/translations/ro.po +4 -0
  88. package/lang/translations/ru.po +4 -0
  89. package/lang/translations/sk.po +4 -0
  90. package/lang/translations/sq.po +29 -0
  91. package/lang/translations/sr-latn.po +4 -0
  92. package/lang/translations/sr.po +4 -0
  93. package/lang/translations/sv.po +4 -0
  94. package/lang/translations/th.po +4 -0
  95. package/lang/translations/tr.po +4 -0
  96. package/lang/translations/ug.po +4 -0
  97. package/lang/translations/uk.po +4 -0
  98. package/lang/translations/ur.po +4 -0
  99. package/lang/translations/uz.po +4 -0
  100. package/lang/translations/vi.po +4 -0
  101. package/lang/translations/zh-cn.po +4 -0
  102. package/lang/translations/zh.po +4 -0
  103. package/package.json +2 -3
  104. package/src/ckboxcommand.d.ts +0 -1
  105. package/src/ckboxcommand.js +10 -23
  106. package/src/ckboxconfig.d.ts +26 -15
  107. package/src/ckboxediting.js +0 -1
  108. package/src/ckboxuploadadapter.js +27 -29
  109. package/src/utils.d.ts +7 -10
  110. package/src/utils.js +27 -68
@@ -2,7 +2,7 @@
2
2
  * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
- /* globals AbortController, FormData, URL, Image, XMLHttpRequest, window */
5
+ /* globals AbortController, FormData, URL, XMLHttpRequest, window */
6
6
  /**
7
7
  * @module ckbox/ckboxuploadadapter
8
8
  */
@@ -10,7 +10,7 @@ import { Plugin } from 'ckeditor5/src/core';
10
10
  import { FileRepository } from 'ckeditor5/src/upload';
11
11
  import { logError } from 'ckeditor5/src/utils';
12
12
  import CKBoxEditing from './ckboxediting';
13
- import { getImageUrls } from './utils';
13
+ import { getImageUrls, getWorkspaceId } from './utils';
14
14
  /**
15
15
  * A plugin that enables file uploads in CKEditor 5 using the CKBox server–side connector.
16
16
  * See the {@glink features/file-management/ckbox CKBox file manager integration} guide to learn how to configure
@@ -76,7 +76,25 @@ class Adapter {
76
76
  this.editor = editor;
77
77
  this.controller = new AbortController();
78
78
  this.serviceOrigin = editor.config.get('ckbox.serviceOrigin');
79
- this.assetsOrigin = editor.config.get('ckbox.assetsOrigin');
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 workspace defined in `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;
80
98
  }
81
99
  /**
82
100
  * Resolves a promise with an array containing available categories with which the uploaded file can be associated.
@@ -88,6 +106,7 @@ class Adapter {
88
106
  const categoryUrl = new URL('categories', this.serviceOrigin);
89
107
  categoryUrl.searchParams.set('limit', ITEMS_PER_REQUEST.toString());
90
108
  categoryUrl.searchParams.set('offset', offset.toString());
109
+ categoryUrl.searchParams.set('workspaceId', this.getWorkspaceId());
91
110
  return this._sendHttpRequest({ url: categoryUrl })
92
111
  .then(async (data) => {
93
112
  const remainingItems = data.totalCount - (offset + ITEMS_PER_REQUEST);
@@ -125,7 +144,7 @@ class Adapter {
125
144
  // If a user specifies the plugin configuration, find the first category that accepts the uploaded file.
126
145
  if (defaultCategories) {
127
146
  const userCategory = Object.keys(defaultCategories).find(category => {
128
- return defaultCategories[category].includes(extension);
147
+ return defaultCategories[category].find(e => e.toLowerCase() == extension);
129
148
  });
130
149
  // If found, return its ID if the category exists on the server side.
131
150
  if (userCategory) {
@@ -137,7 +156,7 @@ class Adapter {
137
156
  }
138
157
  }
139
158
  // Otherwise, find the first category that accepts the uploaded file and returns its ID.
140
- const category = allCategories.find(category => category.extensions.includes(extension));
159
+ const category = allCategories.find(category => category.extensions.find(e => e.toLowerCase() == extension));
141
160
  if (!category) {
142
161
  return null;
143
162
  }
@@ -158,6 +177,7 @@ class Adapter {
158
177
  }
159
178
  const uploadUrl = new URL('assets', this.serviceOrigin);
160
179
  const formData = new FormData();
180
+ uploadUrl.searchParams.set('workspaceId', this.getWorkspaceId());
161
181
  formData.append('categoryId', category);
162
182
  formData.append('file', file);
163
183
  const requestConfig = {
@@ -174,15 +194,7 @@ class Adapter {
174
194
  };
175
195
  return this._sendHttpRequest(requestConfig)
176
196
  .then(async (data) => {
177
- const width = await this._getImageWidth();
178
- const extension = getFileExtension(file.name);
179
- const imageUrls = getImageUrls({
180
- token: this.token,
181
- id: data.id,
182
- origin: this.assetsOrigin,
183
- width,
184
- extension
185
- });
197
+ const imageUrls = getImageUrls(data.imageUrls);
186
198
  return {
187
199
  ckboxImageId: data.id,
188
200
  default: imageUrls.imageFallbackUrl,
@@ -252,20 +264,6 @@ class Adapter {
252
264
  xhr.send(data);
253
265
  });
254
266
  }
255
- /**
256
- * Resolves a promise with a number representing the width of a given image file.
257
- */
258
- _getImageWidth() {
259
- return new Promise(resolve => {
260
- const image = new Image();
261
- image.onload = () => {
262
- // Let the browser know that it should not keep the reference any longer to avoid memory leeks.
263
- URL.revokeObjectURL(image.src);
264
- resolve(image.width);
265
- };
266
- image.src = this.loader.data;
267
- });
268
- }
269
267
  }
270
268
  /**
271
269
  * Returns an extension from the given value.
@@ -273,5 +271,5 @@ class Adapter {
273
271
  function getFileExtension(value) {
274
272
  const extensionRegExp = /\.(?<ext>[^.]+)$/;
275
273
  const match = value.match(extensionRegExp);
276
- return match.groups.ext;
274
+ return match.groups.ext.toLowerCase();
277
275
  }
package/src/utils.d.ts CHANGED
@@ -6,18 +6,13 @@
6
6
  * @module ckbox/utils
7
7
  */
8
8
  import type { InitializedToken } from '@ckeditor/ckeditor5-cloud-services';
9
+ import type { CKBoxImageUrls } from './ckboxconfig';
9
10
  /**
10
- * Creates URLs for the image:
11
+ * Converts image source set provided by the CKBox into an object containing:
11
12
  * - responsive URLs for the "webp" image format,
12
13
  * - one fallback URL for browsers that do not support the "webp" format.
13
14
  */
14
- export declare function getImageUrls({ token, id, origin, width, extension }: {
15
- token: InitializedToken;
16
- id: string;
17
- origin: string;
18
- width: number;
19
- extension: string;
20
- }): {
15
+ export declare function getImageUrls(imageUrls: CKBoxImageUrls): {
21
16
  imageFallbackUrl: string;
22
17
  imageSources: Array<{
23
18
  srcset: string;
@@ -26,6 +21,8 @@ export declare function getImageUrls({ token, id, origin, width, extension }: {
26
21
  }>;
27
22
  };
28
23
  /**
29
- * Returns an environment id from a token used for communication with the CKBox service.
24
+ * Returns workspace id to use for communication with the CKBox service.
25
+ *
26
+ * @param defaultWorkspaceId The default workspace to use taken from editor config.
30
27
  */
31
- export declare function getEnvironmentId(token: InitializedToken): string;
28
+ export declare function getWorkspaceId(token: InitializedToken, defaultWorkspaceId?: string): string | null;
package/src/utils.js CHANGED
@@ -2,89 +2,48 @@
2
2
  * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
- const IMAGE_BREAKPOINT_MAX_WIDTH = 4000;
6
- const IMAGE_BREAKPOINT_PIXELS_THRESHOLD = 80;
7
- const IMAGE_BREAKPOINT_PERCENTAGE_THRESHOLD = 10;
8
5
  /**
9
- * Creates URLs for the image:
6
+ * Converts image source set provided by the CKBox into an object containing:
10
7
  * - responsive URLs for the "webp" image format,
11
8
  * - one fallback URL for browsers that do not support the "webp" format.
12
9
  */
13
- export function getImageUrls({ token, id, origin, width, extension }) {
14
- const environmentId = getEnvironmentId(token);
15
- const imageBreakpoints = getImageBreakpoints(width);
16
- const imageFallbackExtension = getImageFallbackExtension(extension);
17
- const imageFallbackUrl = getResponsiveImageUrl({ environmentId, id, origin, width, extension: imageFallbackExtension });
18
- const imageResponsiveUrls = imageBreakpoints.map(imageBreakpoint => {
19
- const responsiveImageUrl = getResponsiveImageUrl({ environmentId, id, origin, width: imageBreakpoint, extension: 'webp' });
20
- return `${responsiveImageUrl} ${imageBreakpoint}w`;
21
- });
22
- // Create just one image source definition containing all calculated URLs for each image breakpoint. Additionally, limit this source
23
- // image width by defining two allowed slot sizes:
24
- // - If the viewport width is not greater than the image width, make the image occupy the whole slot.
25
- // - Otherwise, limit the slot width to be equal to the image width, to avoid enlarging the image beyond its width.
26
- //
27
- // This is a kind of a workaround. In a perfect world we could use `sizes="100vw" width="real image width"` on our single `<source>`
28
- // element, but at the time of writing this code the `width` attribute is not supported in the `<source>` element in Firefox yet.
10
+ export function getImageUrls(imageUrls) {
11
+ const responsiveUrls = [];
12
+ let maxWidth = 0;
13
+ for (const key in imageUrls) {
14
+ const width = parseInt(key, 10);
15
+ if (!isNaN(width)) {
16
+ if (width > maxWidth) {
17
+ maxWidth = width;
18
+ }
19
+ responsiveUrls.push(`${imageUrls[key]} ${key}w`);
20
+ }
21
+ }
29
22
  const imageSources = [{
30
- srcset: imageResponsiveUrls.join(','),
31
- sizes: `(max-width: ${width}px) 100vw, ${width}px`,
23
+ srcset: responsiveUrls.join(','),
24
+ sizes: `(max-width: ${maxWidth}px) 100vw, ${maxWidth}px`,
32
25
  type: 'image/webp'
33
26
  }];
34
27
  return {
35
- imageFallbackUrl,
28
+ imageFallbackUrl: imageUrls.default,
36
29
  imageSources
37
30
  };
38
31
  }
39
32
  /**
40
- * Returns an environment id from a token used for communication with the CKBox service.
33
+ * Returns workspace id to use for communication with the CKBox service.
34
+ *
35
+ * @param defaultWorkspaceId The default workspace to use taken from editor config.
41
36
  */
42
- export function getEnvironmentId(token) {
37
+ export function getWorkspaceId(token, defaultWorkspaceId) {
43
38
  const [, binaryTokenPayload] = token.value.split('.');
44
39
  const payload = JSON.parse(atob(binaryTokenPayload));
45
- return payload.aud;
46
- }
47
- /**
48
- * Calculates the image breakpoints for the provided image width in the following way:
49
- *
50
- * 1) The breakpoint threshold (the breakpoint step in the calculations) should be equal to 10% of the image width, but not less than 80
51
- * pixels.
52
- *
53
- * 2) Set the max. allowed image breakpoint (4000px) or the image width (if it is smaller than 4000px) as the first calculated breakpoint.
54
- *
55
- * 3) From the last computed image breakpoint subtract the computed breakpoint threshold, as long as the calculated new breakpoint value is
56
- * greater than the threshold.
57
- */
58
- function getImageBreakpoints(width) {
59
- // Step 1) - calculating the breakpoint threshold.
60
- const imageBreakpointThresholds = [
61
- width * IMAGE_BREAKPOINT_PERCENTAGE_THRESHOLD / 100,
62
- IMAGE_BREAKPOINT_PIXELS_THRESHOLD
63
- ];
64
- const imageBreakpointThreshold = Math.floor(Math.max(...imageBreakpointThresholds));
65
- // Step 2) - set the first breakpoint.
66
- const imageBreakpoints = [Math.min(width, IMAGE_BREAKPOINT_MAX_WIDTH)];
67
- // Step 3) - calculate the next breakpoint as long as it is greater than the breakpoint threshold.
68
- let lastBreakpoint = imageBreakpoints[0];
69
- while (lastBreakpoint - imageBreakpointThreshold >= imageBreakpointThreshold) {
70
- lastBreakpoint -= imageBreakpointThreshold;
71
- imageBreakpoints.unshift(lastBreakpoint);
40
+ const workspaces = (payload.auth && payload.auth.ckbox && payload.auth.ckbox.workspaces) || [payload.aud];
41
+ if (!defaultWorkspaceId) {
42
+ return workspaces[0];
72
43
  }
73
- return imageBreakpoints;
74
- }
75
- /**
76
- * Returns the image extension for the fallback URL.
77
- */
78
- function getImageFallbackExtension(extension) {
79
- if (extension === 'bmp' || extension === 'tiff' || extension === 'jpg') {
80
- return 'jpeg';
44
+ const role = payload.auth && payload.auth.ckbox && payload.auth.ckbox.role;
45
+ if (role == 'superadmin' || workspaces.includes(defaultWorkspaceId)) {
46
+ return defaultWorkspaceId;
81
47
  }
82
- return extension;
83
- }
84
- /**
85
- * Creates the URL for the given image.
86
- */
87
- function getResponsiveImageUrl({ environmentId, id, origin, width, extension }) {
88
- const endpoint = `${environmentId}/assets/${id}/images/${width}.${extension}`;
89
- return new URL(endpoint, origin).toString();
48
+ return null;
90
49
  }