@ckeditor/ckeditor5-ckbox 40.0.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.
- package/LICENSE.md +6 -2
- package/build/ckbox.js +2 -2
- package/build/translations/ar.js +1 -1
- package/build/translations/az.js +1 -1
- package/build/translations/bg.js +1 -1
- package/build/translations/bn.js +1 -1
- package/build/translations/ca.js +1 -1
- package/build/translations/cs.js +1 -1
- package/build/translations/da.js +1 -1
- package/build/translations/de.js +1 -1
- package/build/translations/el.js +1 -1
- package/build/translations/en-au.js +1 -1
- package/build/translations/es-co.js +1 -1
- package/build/translations/es.js +1 -1
- package/build/translations/et.js +1 -1
- package/build/translations/fa.js +1 -1
- package/build/translations/fi.js +1 -1
- package/build/translations/fr.js +1 -1
- package/build/translations/gl.js +1 -1
- package/build/translations/he.js +1 -1
- package/build/translations/hi.js +1 -1
- package/build/translations/hr.js +1 -1
- package/build/translations/hu.js +1 -1
- package/build/translations/id.js +1 -1
- package/build/translations/it.js +1 -1
- package/build/translations/ja.js +1 -1
- package/build/translations/ko.js +1 -1
- package/build/translations/lt.js +1 -1
- package/build/translations/lv.js +1 -1
- package/build/translations/ms.js +1 -1
- package/build/translations/nl.js +1 -1
- package/build/translations/no.js +1 -1
- package/build/translations/pl.js +1 -1
- package/build/translations/pt-br.js +1 -1
- package/build/translations/pt.js +1 -1
- package/build/translations/ro.js +1 -1
- package/build/translations/ru.js +1 -1
- package/build/translations/sk.js +1 -1
- package/build/translations/sq.js +1 -1
- package/build/translations/sr-latn.js +1 -1
- package/build/translations/sr.js +1 -1
- package/build/translations/sv.js +1 -1
- package/build/translations/th.js +1 -1
- package/build/translations/tr.js +1 -1
- package/build/translations/ug.js +1 -1
- package/build/translations/uk.js +1 -1
- package/build/translations/ur.js +1 -1
- package/build/translations/uz.js +1 -1
- package/build/translations/vi.js +1 -1
- package/build/translations/zh-cn.js +1 -1
- package/build/translations/zh.js +1 -1
- package/ckeditor5-metadata.json +17 -0
- package/lang/contexts.json +6 -2
- package/lang/translations/ar.po +18 -2
- package/lang/translations/az.po +18 -2
- package/lang/translations/bg.po +18 -2
- package/lang/translations/bn.po +18 -2
- package/lang/translations/ca.po +18 -2
- package/lang/translations/cs.po +18 -2
- package/lang/translations/da.po +18 -2
- package/lang/translations/de.po +18 -2
- package/lang/translations/el.po +18 -2
- package/lang/translations/en-au.po +18 -2
- package/lang/translations/en.po +18 -2
- package/lang/translations/es-co.po +18 -2
- package/lang/translations/es.po +18 -2
- package/lang/translations/et.po +18 -2
- package/lang/translations/fa.po +18 -2
- package/lang/translations/fi.po +18 -2
- package/lang/translations/fr.po +18 -2
- package/lang/translations/gl.po +18 -2
- package/lang/translations/he.po +18 -2
- package/lang/translations/hi.po +18 -2
- package/lang/translations/hr.po +18 -2
- package/lang/translations/hu.po +18 -2
- package/lang/translations/id.po +18 -2
- package/lang/translations/it.po +18 -2
- package/lang/translations/ja.po +18 -2
- package/lang/translations/ko.po +18 -2
- package/lang/translations/lt.po +18 -2
- package/lang/translations/lv.po +18 -2
- package/lang/translations/ms.po +18 -2
- package/lang/translations/nl.po +18 -2
- package/lang/translations/no.po +18 -2
- package/lang/translations/pl.po +18 -2
- package/lang/translations/pt-br.po +18 -2
- package/lang/translations/pt.po +18 -2
- package/lang/translations/ro.po +18 -2
- package/lang/translations/ru.po +18 -2
- package/lang/translations/sk.po +18 -2
- package/lang/translations/sq.po +18 -2
- package/lang/translations/sr-latn.po +18 -2
- package/lang/translations/sr.po +18 -2
- package/lang/translations/sv.po +18 -2
- package/lang/translations/th.po +18 -2
- package/lang/translations/tr.po +18 -2
- package/lang/translations/ug.po +18 -2
- package/lang/translations/uk.po +18 -2
- package/lang/translations/ur.po +18 -2
- package/lang/translations/uz.po +18 -2
- package/lang/translations/vi.po +18 -2
- package/lang/translations/zh-cn.po +18 -2
- package/lang/translations/zh.po +18 -2
- package/package.json +4 -2
- package/src/augmentation.d.ts +32 -22
- package/src/augmentation.js +5 -5
- package/src/ckbox.d.ts +33 -33
- package/src/ckbox.js +37 -37
- package/src/ckboxcommand.d.ts +114 -110
- package/src/ckboxcommand.js +332 -302
- package/src/ckboxconfig.d.ts +325 -283
- package/src/ckboxconfig.js +5 -5
- package/src/ckboxediting.d.ts +45 -52
- package/src/ckboxediting.js +321 -362
- package/src/ckboximageedit/ckboximageeditcommand.d.ts +97 -0
- package/src/ckboximageedit/ckboximageeditcommand.js +298 -0
- package/src/ckboximageedit/ckboximageeditediting.d.ts +28 -0
- package/src/ckboximageedit/ckboximageeditediting.js +36 -0
- package/src/ckboximageedit/ckboximageeditui.d.ts +24 -0
- package/src/ckboximageedit/ckboximageeditui.js +48 -0
- package/src/ckboximageedit/utils.d.ts +10 -0
- package/src/ckboximageedit/utils.js +48 -0
- package/src/ckboximageedit.d.ts +24 -0
- package/src/ckboximageedit.js +28 -0
- package/src/ckboxui.d.ts +21 -21
- package/src/ckboxui.js +74 -47
- package/src/ckboxuploadadapter.d.ts +33 -38
- package/src/ckboxuploadadapter.js +130 -275
- package/src/ckboxutils.d.ts +50 -0
- package/src/ckboxutils.js +183 -0
- package/src/index.d.ts +17 -13
- package/src/index.js +14 -11
- package/src/utils.d.ts +63 -28
- package/src/utils.js +175 -49
- package/theme/ckboximageedit.css +53 -0
- package/theme/icons/ckbox-image-edit.svg +1 -0
- package/build/ckbox.js.map +0 -1
|
@@ -0,0 +1,50 @@
|
|
|
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/ckboxutils
|
|
7
|
+
*/
|
|
8
|
+
import type { InitializedToken } from '@ckeditor/ckeditor5-cloud-services';
|
|
9
|
+
import { Plugin } from 'ckeditor5/src/core';
|
|
10
|
+
/**
|
|
11
|
+
* The CKBox utilities plugin.
|
|
12
|
+
*/
|
|
13
|
+
export default class CKBoxUtils extends Plugin {
|
|
14
|
+
/**
|
|
15
|
+
* CKEditor Cloud Services access token.
|
|
16
|
+
*/
|
|
17
|
+
private _token;
|
|
18
|
+
/**
|
|
19
|
+
* @inheritDoc
|
|
20
|
+
*/
|
|
21
|
+
static get pluginName(): "CKBoxUtils";
|
|
22
|
+
/**
|
|
23
|
+
* @inheritDoc
|
|
24
|
+
*/
|
|
25
|
+
static get requires(): readonly ["CloudServices"];
|
|
26
|
+
/**
|
|
27
|
+
* @inheritDoc
|
|
28
|
+
*/
|
|
29
|
+
init(): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Returns a token used by the CKBox plugin for communication with the CKBox service.
|
|
32
|
+
*/
|
|
33
|
+
getToken(): InitializedToken;
|
|
34
|
+
/**
|
|
35
|
+
* The ID of workspace to use when uploading an image.
|
|
36
|
+
*/
|
|
37
|
+
getWorkspaceId(): string;
|
|
38
|
+
/**
|
|
39
|
+
* Resolves a promise with an object containing a category with which the uploaded file is associated or an error code.
|
|
40
|
+
*/
|
|
41
|
+
getCategoryIdForFile(fileOrUrl: File | string, options: {
|
|
42
|
+
signal: AbortSignal;
|
|
43
|
+
}): Promise<string>;
|
|
44
|
+
/**
|
|
45
|
+
* Resolves a promise with an array containing available categories with which the uploaded file can be associated.
|
|
46
|
+
*
|
|
47
|
+
* If the API returns limited results, the method will collect all items.
|
|
48
|
+
*/
|
|
49
|
+
private _getAvailableCategories;
|
|
50
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
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 { CKEditorError, logError } from 'ckeditor5/src/utils';
|
|
6
|
+
import { Plugin } from 'ckeditor5/src/core';
|
|
7
|
+
import { convertMimeTypeToExtension, getContentTypeOfUrl, getFileExtension, getWorkspaceId, sendHttpRequest } from './utils';
|
|
8
|
+
const DEFAULT_CKBOX_THEME_NAME = 'lark';
|
|
9
|
+
/**
|
|
10
|
+
* The CKBox utilities plugin.
|
|
11
|
+
*/
|
|
12
|
+
export default class CKBoxUtils extends Plugin {
|
|
13
|
+
/**
|
|
14
|
+
* @inheritDoc
|
|
15
|
+
*/
|
|
16
|
+
static get pluginName() {
|
|
17
|
+
return 'CKBoxUtils';
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* @inheritDoc
|
|
21
|
+
*/
|
|
22
|
+
static get requires() {
|
|
23
|
+
return ['CloudServices'];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* @inheritDoc
|
|
27
|
+
*/
|
|
28
|
+
async init() {
|
|
29
|
+
const editor = this.editor;
|
|
30
|
+
const hasConfiguration = !!editor.config.get('ckbox');
|
|
31
|
+
const isLibraryLoaded = !!window.CKBox;
|
|
32
|
+
// Proceed with plugin initialization only when the integrator intentionally wants to use it, i.e. when the `config.ckbox` exists or
|
|
33
|
+
// the CKBox JavaScript library is loaded.
|
|
34
|
+
if (!hasConfiguration && !isLibraryLoaded) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
editor.config.define('ckbox', {
|
|
38
|
+
serviceOrigin: 'https://api.ckbox.io',
|
|
39
|
+
defaultUploadCategories: null,
|
|
40
|
+
ignoreDataId: false,
|
|
41
|
+
language: editor.locale.uiLanguage,
|
|
42
|
+
theme: DEFAULT_CKBOX_THEME_NAME,
|
|
43
|
+
tokenUrl: editor.config.get('cloudServices.tokenUrl')
|
|
44
|
+
});
|
|
45
|
+
const cloudServices = editor.plugins.get('CloudServices');
|
|
46
|
+
const cloudServicesTokenUrl = editor.config.get('cloudServices.tokenUrl');
|
|
47
|
+
const ckboxTokenUrl = editor.config.get('ckbox.tokenUrl');
|
|
48
|
+
if (!ckboxTokenUrl) {
|
|
49
|
+
/**
|
|
50
|
+
* The {@link module:ckbox/ckboxconfig~CKBoxConfig#tokenUrl `config.ckbox.tokenUrl`} or the
|
|
51
|
+
* {@link module:cloud-services/cloudservicesconfig~CloudServicesConfig#tokenUrl `config.cloudServices.tokenUrl`}
|
|
52
|
+
* configuration is required for the CKBox plugin.
|
|
53
|
+
*
|
|
54
|
+
* ```ts
|
|
55
|
+
* ClassicEditor.create( document.createElement( 'div' ), {
|
|
56
|
+
* ckbox: {
|
|
57
|
+
* tokenUrl: "YOUR_TOKEN_URL"
|
|
58
|
+
* // ...
|
|
59
|
+
* }
|
|
60
|
+
* // ...
|
|
61
|
+
* } );
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @error ckbox-plugin-missing-token-url
|
|
65
|
+
*/
|
|
66
|
+
throw new CKEditorError('ckbox-plugin-missing-token-url', this);
|
|
67
|
+
}
|
|
68
|
+
if (ckboxTokenUrl == cloudServicesTokenUrl) {
|
|
69
|
+
this._token = cloudServices.token;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
this._token = await cloudServices.registerTokenUrl(ckboxTokenUrl);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Returns a token used by the CKBox plugin for communication with the CKBox service.
|
|
77
|
+
*/
|
|
78
|
+
getToken() {
|
|
79
|
+
return this._token;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The ID of workspace to use when uploading an image.
|
|
83
|
+
*/
|
|
84
|
+
getWorkspaceId() {
|
|
85
|
+
const t = this.editor.t;
|
|
86
|
+
const cannotAccessDefaultWorkspaceError = t('Cannot access default workspace.');
|
|
87
|
+
const defaultWorkspaceId = this.editor.config.get('ckbox.defaultUploadWorkspaceId');
|
|
88
|
+
const workspaceId = getWorkspaceId(this._token, defaultWorkspaceId);
|
|
89
|
+
if (workspaceId == null) {
|
|
90
|
+
/**
|
|
91
|
+
* The user is not authorized to access the workspace defined in the`ckbox.defaultUploadWorkspaceId` configuration.
|
|
92
|
+
*
|
|
93
|
+
* @error ckbox-access-default-workspace-error
|
|
94
|
+
*/
|
|
95
|
+
logError('ckbox-access-default-workspace-error');
|
|
96
|
+
throw cannotAccessDefaultWorkspaceError;
|
|
97
|
+
}
|
|
98
|
+
return workspaceId;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Resolves a promise with an object containing a category with which the uploaded file is associated or an error code.
|
|
102
|
+
*/
|
|
103
|
+
async getCategoryIdForFile(fileOrUrl, options) {
|
|
104
|
+
const t = this.editor.t;
|
|
105
|
+
const cannotFindCategoryError = t('Cannot determine a category for the uploaded file.');
|
|
106
|
+
const defaultCategories = this.editor.config.get('ckbox.defaultUploadCategories');
|
|
107
|
+
const allCategoriesPromise = this._getAvailableCategories(options);
|
|
108
|
+
const extension = typeof fileOrUrl == 'string' ?
|
|
109
|
+
convertMimeTypeToExtension(await getContentTypeOfUrl(fileOrUrl, options)) :
|
|
110
|
+
getFileExtension(fileOrUrl);
|
|
111
|
+
const allCategories = await allCategoriesPromise;
|
|
112
|
+
// Couldn't fetch all categories. Perhaps the authorization token is invalid.
|
|
113
|
+
if (!allCategories) {
|
|
114
|
+
throw cannotFindCategoryError;
|
|
115
|
+
}
|
|
116
|
+
// If a user specifies the plugin configuration, find the first category that accepts the uploaded file.
|
|
117
|
+
if (defaultCategories) {
|
|
118
|
+
const userCategory = Object.keys(defaultCategories).find(category => {
|
|
119
|
+
return defaultCategories[category].find(e => e.toLowerCase() == extension);
|
|
120
|
+
});
|
|
121
|
+
// If found, return its ID if the category exists on the server side.
|
|
122
|
+
if (userCategory) {
|
|
123
|
+
const serverCategory = allCategories.find(category => category.id === userCategory || category.name === userCategory);
|
|
124
|
+
if (!serverCategory) {
|
|
125
|
+
throw cannotFindCategoryError;
|
|
126
|
+
}
|
|
127
|
+
return serverCategory.id;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Otherwise, find the first category that accepts the uploaded file and returns its ID.
|
|
131
|
+
const category = allCategories.find(category => category.extensions.find(e => e.toLowerCase() == extension));
|
|
132
|
+
if (!category) {
|
|
133
|
+
throw cannotFindCategoryError;
|
|
134
|
+
}
|
|
135
|
+
return category.id;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Resolves a promise with an array containing available categories with which the uploaded file can be associated.
|
|
139
|
+
*
|
|
140
|
+
* If the API returns limited results, the method will collect all items.
|
|
141
|
+
*/
|
|
142
|
+
async _getAvailableCategories(options) {
|
|
143
|
+
const ITEMS_PER_REQUEST = 50;
|
|
144
|
+
const editor = this.editor;
|
|
145
|
+
const token = this._token;
|
|
146
|
+
const { signal } = options;
|
|
147
|
+
const serviceOrigin = editor.config.get('ckbox.serviceOrigin');
|
|
148
|
+
const workspaceId = this.getWorkspaceId();
|
|
149
|
+
try {
|
|
150
|
+
const result = [];
|
|
151
|
+
let offset = 0;
|
|
152
|
+
let remainingItems;
|
|
153
|
+
do {
|
|
154
|
+
const data = await fetchCategories(offset);
|
|
155
|
+
result.push(...data.items);
|
|
156
|
+
remainingItems = data.totalCount - (offset + ITEMS_PER_REQUEST);
|
|
157
|
+
offset += ITEMS_PER_REQUEST;
|
|
158
|
+
} while (remainingItems > 0);
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
signal.throwIfAborted();
|
|
163
|
+
/**
|
|
164
|
+
* Fetching a list of available categories with which an uploaded file can be associated failed.
|
|
165
|
+
*
|
|
166
|
+
* @error ckbox-fetch-category-http-error
|
|
167
|
+
*/
|
|
168
|
+
logError('ckbox-fetch-category-http-error');
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
function fetchCategories(offset) {
|
|
172
|
+
const categoryUrl = new URL('categories', serviceOrigin);
|
|
173
|
+
categoryUrl.searchParams.set('limit', ITEMS_PER_REQUEST.toString());
|
|
174
|
+
categoryUrl.searchParams.set('offset', offset.toString());
|
|
175
|
+
categoryUrl.searchParams.set('workspaceId', workspaceId);
|
|
176
|
+
return sendHttpRequest({
|
|
177
|
+
url: categoryUrl,
|
|
178
|
+
signal,
|
|
179
|
+
authorization: token.value
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
package/src/index.d.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
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
|
|
7
|
-
*/
|
|
8
|
-
export { default as CKBox } from './ckbox';
|
|
9
|
-
export { default as CKBoxEditing } from './ckboxediting';
|
|
10
|
-
export { default as CKBoxUI } from './ckboxui';
|
|
11
|
-
export
|
|
12
|
-
export
|
|
13
|
-
|
|
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
|
|
7
|
+
*/
|
|
8
|
+
export { default as CKBox } from './ckbox';
|
|
9
|
+
export { default as CKBoxEditing } from './ckboxediting';
|
|
10
|
+
export { default as CKBoxUI } from './ckboxui';
|
|
11
|
+
export { default as CKBoxImageEditEditing } from './ckboximageedit/ckboximageeditediting';
|
|
12
|
+
export { default as CKBoxImageEditUI } from './ckboximageedit/ckboximageeditui';
|
|
13
|
+
export { default as CKBoxImageEdit } from './ckboximageedit';
|
|
14
|
+
export type { default as CKBoxCommand } from './ckboxcommand';
|
|
15
|
+
export type { default as CKBoxImageEditCommand } from './ckboximageedit/ckboximageeditcommand';
|
|
16
|
+
export type { CKBoxConfig } from './ckboxconfig';
|
|
17
|
+
import './augmentation';
|
package/src/index.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
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
|
|
7
|
-
*/
|
|
8
|
-
export { default as CKBox } from './ckbox';
|
|
9
|
-
export { default as CKBoxEditing } from './ckboxediting';
|
|
10
|
-
export { default as CKBoxUI } from './ckboxui';
|
|
11
|
-
|
|
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
|
|
7
|
+
*/
|
|
8
|
+
export { default as CKBox } from './ckbox';
|
|
9
|
+
export { default as CKBoxEditing } from './ckboxediting';
|
|
10
|
+
export { default as CKBoxUI } from './ckboxui';
|
|
11
|
+
export { default as CKBoxImageEditEditing } from './ckboximageedit/ckboximageeditediting';
|
|
12
|
+
export { default as CKBoxImageEditUI } from './ckboximageedit/ckboximageeditui';
|
|
13
|
+
export { default as CKBoxImageEdit } from './ckboximageedit';
|
|
14
|
+
import './augmentation';
|
package/src/utils.d.ts
CHANGED
|
@@ -1,28 +1,63 @@
|
|
|
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/utils
|
|
7
|
-
*/
|
|
8
|
-
import type { InitializedToken } from '@ckeditor/ckeditor5-cloud-services';
|
|
9
|
-
import type { CKBoxImageUrls } from './ckboxconfig';
|
|
10
|
-
/**
|
|
11
|
-
* Converts image source set provided by the CKBox into an object containing:
|
|
12
|
-
* - responsive URLs for the "webp" image format,
|
|
13
|
-
* - one fallback URL for browsers that do not support the "webp" format.
|
|
14
|
-
*/
|
|
15
|
-
export declare function getImageUrls(imageUrls: CKBoxImageUrls): {
|
|
16
|
-
imageFallbackUrl: string;
|
|
17
|
-
imageSources: Array<{
|
|
18
|
-
srcset: string;
|
|
19
|
-
sizes: string;
|
|
20
|
-
type: string;
|
|
21
|
-
}>;
|
|
22
|
-
};
|
|
23
|
-
/**
|
|
24
|
-
* Returns a workspace id to use for communication with the CKBox service.
|
|
25
|
-
*
|
|
26
|
-
* @param defaultWorkspaceId The default workspace to use taken from editor config.
|
|
27
|
-
*/
|
|
28
|
-
export declare function getWorkspaceId(token: InitializedToken, defaultWorkspaceId?: string): string | null;
|
|
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/utils
|
|
7
|
+
*/
|
|
8
|
+
import type { InitializedToken } from '@ckeditor/ckeditor5-cloud-services';
|
|
9
|
+
import type { CKBoxImageUrls } from './ckboxconfig';
|
|
10
|
+
/**
|
|
11
|
+
* Converts image source set provided by the CKBox into an object containing:
|
|
12
|
+
* - responsive URLs for the "webp" image format,
|
|
13
|
+
* - one fallback URL for browsers that do not support the "webp" format.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getImageUrls(imageUrls: CKBoxImageUrls): {
|
|
16
|
+
imageFallbackUrl: string;
|
|
17
|
+
imageSources: Array<{
|
|
18
|
+
srcset: string;
|
|
19
|
+
sizes: string;
|
|
20
|
+
type: string;
|
|
21
|
+
}>;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Returns a workspace id to use for communication with the CKBox service.
|
|
25
|
+
*
|
|
26
|
+
* @param defaultWorkspaceId The default workspace to use taken from editor config.
|
|
27
|
+
*/
|
|
28
|
+
export declare function getWorkspaceId(token: InitializedToken, defaultWorkspaceId?: string): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Generates an image data URL from its `blurhash` representation.
|
|
31
|
+
*/
|
|
32
|
+
export declare function blurHashToDataUrl(hash?: string): string | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Sends the HTTP request.
|
|
35
|
+
*
|
|
36
|
+
* @internal
|
|
37
|
+
* @param config.url the URL where the request will be sent.
|
|
38
|
+
* @param config.method The HTTP method.
|
|
39
|
+
* @param config.data Additional data to send.
|
|
40
|
+
* @param config.onUploadProgress A callback informing about the upload progress.
|
|
41
|
+
*/
|
|
42
|
+
export declare function sendHttpRequest({ url, method, data, onUploadProgress, signal, authorization }: {
|
|
43
|
+
url: URL;
|
|
44
|
+
signal: AbortSignal;
|
|
45
|
+
authorization: string;
|
|
46
|
+
method?: 'GET' | 'POST';
|
|
47
|
+
data?: FormData | null;
|
|
48
|
+
onUploadProgress?: (evt: ProgressEvent) => void;
|
|
49
|
+
}): Promise<any>;
|
|
50
|
+
/**
|
|
51
|
+
* Returns an extension a typical file in the specified `mimeType` format would have.
|
|
52
|
+
*/
|
|
53
|
+
export declare function convertMimeTypeToExtension(mimeType: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Tries to fetch the given `url` and returns 'content-type' of the response.
|
|
56
|
+
*/
|
|
57
|
+
export declare function getContentTypeOfUrl(url: string, options: {
|
|
58
|
+
signal: AbortSignal;
|
|
59
|
+
}): Promise<string>;
|
|
60
|
+
/**
|
|
61
|
+
* Returns an extension from the given value.
|
|
62
|
+
*/
|
|
63
|
+
export declare function getFileExtension(file: File): string;
|
package/src/utils.js
CHANGED
|
@@ -1,49 +1,175 @@
|
|
|
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
|
-
|
|
7
|
-
*
|
|
8
|
-
* -
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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 { decode } from 'blurhash';
|
|
6
|
+
/**
|
|
7
|
+
* Converts image source set provided by the CKBox into an object containing:
|
|
8
|
+
* - responsive URLs for the "webp" image format,
|
|
9
|
+
* - one fallback URL for browsers that do not support the "webp" format.
|
|
10
|
+
*/
|
|
11
|
+
export function getImageUrls(imageUrls) {
|
|
12
|
+
const responsiveUrls = [];
|
|
13
|
+
let maxWidth = 0;
|
|
14
|
+
for (const key in imageUrls) {
|
|
15
|
+
const width = parseInt(key, 10);
|
|
16
|
+
if (!isNaN(width)) {
|
|
17
|
+
if (width > maxWidth) {
|
|
18
|
+
maxWidth = width;
|
|
19
|
+
}
|
|
20
|
+
responsiveUrls.push(`${imageUrls[key]} ${key}w`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const imageSources = [{
|
|
24
|
+
srcset: responsiveUrls.join(','),
|
|
25
|
+
sizes: `(max-width: ${maxWidth}px) 100vw, ${maxWidth}px`,
|
|
26
|
+
type: 'image/webp'
|
|
27
|
+
}];
|
|
28
|
+
return {
|
|
29
|
+
imageFallbackUrl: imageUrls.default,
|
|
30
|
+
imageSources
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Returns a workspace id to use for communication with the CKBox service.
|
|
35
|
+
*
|
|
36
|
+
* @param defaultWorkspaceId The default workspace to use taken from editor config.
|
|
37
|
+
*/
|
|
38
|
+
export function getWorkspaceId(token, defaultWorkspaceId) {
|
|
39
|
+
const [, binaryTokenPayload] = token.value.split('.');
|
|
40
|
+
const payload = JSON.parse(atob(binaryTokenPayload));
|
|
41
|
+
const workspaces = (payload.auth && payload.auth.ckbox && payload.auth.ckbox.workspaces) || [payload.aud];
|
|
42
|
+
if (!defaultWorkspaceId) {
|
|
43
|
+
return workspaces[0];
|
|
44
|
+
}
|
|
45
|
+
const role = payload.auth && payload.auth.ckbox && payload.auth.ckbox.role;
|
|
46
|
+
if (role == 'superadmin' || workspaces.includes(defaultWorkspaceId)) {
|
|
47
|
+
return defaultWorkspaceId;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Default resolution for decoding blurhash values.
|
|
53
|
+
* Relatively small values must be used in order to ensure acceptable performance.
|
|
54
|
+
*/
|
|
55
|
+
const BLUR_RESOLUTION = 32;
|
|
56
|
+
/**
|
|
57
|
+
* Generates an image data URL from its `blurhash` representation.
|
|
58
|
+
*/
|
|
59
|
+
export function blurHashToDataUrl(hash) {
|
|
60
|
+
if (!hash) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const resolutionInPx = `${BLUR_RESOLUTION}px`;
|
|
65
|
+
const canvas = document.createElement('canvas');
|
|
66
|
+
canvas.setAttribute('width', resolutionInPx);
|
|
67
|
+
canvas.setAttribute('height', resolutionInPx);
|
|
68
|
+
const ctx = canvas.getContext('2d');
|
|
69
|
+
/* istanbul ignore next -- @preserve */
|
|
70
|
+
if (!ctx) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const imageData = ctx.createImageData(BLUR_RESOLUTION, BLUR_RESOLUTION);
|
|
74
|
+
const decoded = decode(hash, BLUR_RESOLUTION, BLUR_RESOLUTION);
|
|
75
|
+
imageData.data.set(decoded);
|
|
76
|
+
ctx.putImageData(imageData, 0, 0);
|
|
77
|
+
return canvas.toDataURL();
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Sends the HTTP request.
|
|
85
|
+
*
|
|
86
|
+
* @internal
|
|
87
|
+
* @param config.url the URL where the request will be sent.
|
|
88
|
+
* @param config.method The HTTP method.
|
|
89
|
+
* @param config.data Additional data to send.
|
|
90
|
+
* @param config.onUploadProgress A callback informing about the upload progress.
|
|
91
|
+
*/
|
|
92
|
+
export function sendHttpRequest({ url, method = 'GET', data, onUploadProgress, signal, authorization }) {
|
|
93
|
+
const xhr = new XMLHttpRequest();
|
|
94
|
+
xhr.open(method, url.toString());
|
|
95
|
+
xhr.setRequestHeader('Authorization', authorization);
|
|
96
|
+
xhr.setRequestHeader('CKBox-Version', 'CKEditor 5');
|
|
97
|
+
xhr.responseType = 'json';
|
|
98
|
+
// The callback is attached to the `signal#abort` event.
|
|
99
|
+
const abortCallback = () => {
|
|
100
|
+
xhr.abort();
|
|
101
|
+
};
|
|
102
|
+
return new Promise((resolve, reject) => {
|
|
103
|
+
signal.throwIfAborted();
|
|
104
|
+
signal.addEventListener('abort', abortCallback);
|
|
105
|
+
xhr.addEventListener('loadstart', () => {
|
|
106
|
+
signal.addEventListener('abort', abortCallback);
|
|
107
|
+
});
|
|
108
|
+
xhr.addEventListener('loadend', () => {
|
|
109
|
+
signal.removeEventListener('abort', abortCallback);
|
|
110
|
+
});
|
|
111
|
+
xhr.addEventListener('error', () => {
|
|
112
|
+
reject();
|
|
113
|
+
});
|
|
114
|
+
xhr.addEventListener('abort', () => {
|
|
115
|
+
reject();
|
|
116
|
+
});
|
|
117
|
+
xhr.addEventListener('load', () => {
|
|
118
|
+
const response = xhr.response;
|
|
119
|
+
if (!response || response.statusCode >= 400) {
|
|
120
|
+
return reject(response && response.message);
|
|
121
|
+
}
|
|
122
|
+
resolve(response);
|
|
123
|
+
});
|
|
124
|
+
/* istanbul ignore else -- @preserve */
|
|
125
|
+
if (onUploadProgress) {
|
|
126
|
+
xhr.upload.addEventListener('progress', evt => {
|
|
127
|
+
onUploadProgress(evt);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
// Send the request.
|
|
131
|
+
xhr.send(data);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
const MIME_TO_EXTENSION = {
|
|
135
|
+
'image/gif': 'gif',
|
|
136
|
+
'image/jpeg': 'jpg',
|
|
137
|
+
'image/png': 'png',
|
|
138
|
+
'image/webp': 'webp',
|
|
139
|
+
'image/bmp': 'bmp',
|
|
140
|
+
'image/tiff': 'tiff'
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Returns an extension a typical file in the specified `mimeType` format would have.
|
|
144
|
+
*/
|
|
145
|
+
export function convertMimeTypeToExtension(mimeType) {
|
|
146
|
+
return MIME_TO_EXTENSION[mimeType];
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Tries to fetch the given `url` and returns 'content-type' of the response.
|
|
150
|
+
*/
|
|
151
|
+
export async function getContentTypeOfUrl(url, options) {
|
|
152
|
+
try {
|
|
153
|
+
const response = await fetch(url, {
|
|
154
|
+
method: 'HEAD',
|
|
155
|
+
cache: 'force-cache',
|
|
156
|
+
...options
|
|
157
|
+
});
|
|
158
|
+
if (!response.ok) {
|
|
159
|
+
return '';
|
|
160
|
+
}
|
|
161
|
+
return response.headers.get('content-type') || '';
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return '';
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Returns an extension from the given value.
|
|
169
|
+
*/
|
|
170
|
+
export function getFileExtension(file) {
|
|
171
|
+
const fileName = file.name;
|
|
172
|
+
const extensionRegExp = /\.(?<ext>[^.]+)$/;
|
|
173
|
+
const match = fileName.match(extensionRegExp);
|
|
174
|
+
return match.groups.ext.toLowerCase();
|
|
175
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 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
|
+
:root {
|
|
7
|
+
/* Based on default CKBox theme colors */
|
|
8
|
+
--ck-image-processing-highlight-color: hsl(220, 10%, 98%);
|
|
9
|
+
--ck-image-processing-background-color: hsl(220, 10%, 90%);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.ck.ck-editor__editable {
|
|
13
|
+
& .image {
|
|
14
|
+
&.image-processing {
|
|
15
|
+
position: relative;
|
|
16
|
+
|
|
17
|
+
&:before {
|
|
18
|
+
content: '';
|
|
19
|
+
|
|
20
|
+
position: absolute;
|
|
21
|
+
top: 0;
|
|
22
|
+
left: 0;
|
|
23
|
+
z-index: 1;
|
|
24
|
+
|
|
25
|
+
height: 100%;
|
|
26
|
+
width: 100%;
|
|
27
|
+
|
|
28
|
+
background: linear-gradient(
|
|
29
|
+
90deg,
|
|
30
|
+
var(--ck-image-processing-background-color),
|
|
31
|
+
var(--ck-image-processing-highlight-color),
|
|
32
|
+
var(--ck-image-processing-background-color)
|
|
33
|
+
);
|
|
34
|
+
background-size: 200% 100%;
|
|
35
|
+
|
|
36
|
+
animation: ck-image-processing-animation 2s linear infinite;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
& img {
|
|
40
|
+
height: 100%;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@keyframes ck-image-processing-animation {
|
|
47
|
+
0% {
|
|
48
|
+
background-position: 200% 0;
|
|
49
|
+
}
|
|
50
|
+
100% {
|
|
51
|
+
background-position: -200% 0;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M1.201 1C.538 1 0 1.47 0 2.1v12.86C0 15.603.534 16 1.186 16H6.45l3.647-3.596-3.48-3.254a.694.694 0 0 0-.958-.033L1.5 13.6V2.5h15v4.59a3.477 3.477 0 0 1 1.5.15V2.1c0-.63-.547-1.1-1.2-1.1H1.202Zm11.723 2.805a2.137 2.137 0 0 0-2.045 2.406 2.13 2.13 0 0 0 4.172.277 2.134 2.134 0 0 0-.76-2.244 2.13 2.13 0 0 0-1.367-.44Z"/><path d="M8.1 17.612V20h2.39l7.046-7.046-2.39-2.39L8.1 17.612Zm11.283-6.506a.638.638 0 0 0 .139-.692.603.603 0 0 0-.139-.206L17.892 8.72a.63.63 0 0 0-.898 0l-1.167 1.163 2.391 2.39 1.165-1.167Z"/></svg>
|