@ckeditor/ckeditor5-cloud-services 36.0.1 → 37.0.0-alpha.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.
@@ -0,0 +1,94 @@
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 cloud-services/uploadgateway/fileuploader
7
+ */
8
+ import type { UploadResponse } from 'ckeditor5/src/upload';
9
+ import type { InitializedToken } from '../token/token';
10
+ declare const FileUploader_base: {
11
+ new (): import("ckeditor5/src/utils").Emitter;
12
+ prototype: import("ckeditor5/src/utils").Emitter;
13
+ };
14
+ /**
15
+ * FileUploader class used to upload single file.
16
+ */
17
+ export default class FileUploader extends FileUploader_base {
18
+ /**
19
+ * A file that is being uploaded.
20
+ */
21
+ readonly file: Blob;
22
+ xhr?: XMLHttpRequest;
23
+ /**
24
+ * CKEditor Cloud Services access token.
25
+ */
26
+ private readonly _token;
27
+ /**
28
+ * CKEditor Cloud Services API address.
29
+ */
30
+ private readonly _apiAddress;
31
+ /**
32
+ * Creates `FileUploader` instance.
33
+ *
34
+ * @param fileOrData A blob object or a data string encoded with Base64.
35
+ * @param token Token used for authentication.
36
+ * @param apiAddress API address.
37
+ */
38
+ constructor(fileOrData: string | Blob, token: InitializedToken, apiAddress: string);
39
+ /**
40
+ * Registers callback on `progress` event.
41
+ */
42
+ onProgress(callback: (status: {
43
+ total: number;
44
+ uploaded: number;
45
+ }) => void): this;
46
+ /**
47
+ * Registers callback on `error` event. Event is called once when error occurs.
48
+ */
49
+ onError(callback: (error: string) => void): this;
50
+ /**
51
+ * Aborts upload process.
52
+ */
53
+ abort(): void;
54
+ /**
55
+ * Sends XHR request to API.
56
+ */
57
+ send(): Promise<UploadResponse>;
58
+ /**
59
+ * Prepares XHR request.
60
+ */
61
+ private _prepareRequest;
62
+ /**
63
+ * Attaches listeners to the XHR.
64
+ */
65
+ private _attachXHRListeners;
66
+ /**
67
+ * Sends XHR request.
68
+ */
69
+ private _sendRequest;
70
+ }
71
+ /**
72
+ * Fired when error occurs.
73
+ *
74
+ * @eventName error
75
+ * @param error Error message
76
+ */
77
+ export type FileUploaderErrorEvent = {
78
+ name: 'error';
79
+ args: [error: string];
80
+ };
81
+ /**
82
+ * Fired on upload progress.
83
+ *
84
+ * @eventName progress
85
+ * @param status Total and uploaded status
86
+ */
87
+ export type FileUploaderProgressErrorEvent = {
88
+ name: 'progress';
89
+ args: [status: {
90
+ total: number;
91
+ uploaded: number;
92
+ }];
93
+ };
94
+ export {};
@@ -2,288 +2,182 @@
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
-
6
- /**
7
- * @module cloud-services/uploadgateway/fileuploader
8
- */
9
-
10
- /* globals XMLHttpRequest, FormData, Blob, atob */
11
-
12
- import { mix, EmitterMixin, CKEditorError } from 'ckeditor5/src/utils';
13
-
5
+ import { EmitterMixin, CKEditorError } from 'ckeditor5/src/utils';
14
6
  const BASE64_HEADER_REG_EXP = /^data:(\S*?);base64,/;
15
-
16
7
  /**
17
8
  * FileUploader class used to upload single file.
18
9
  */
19
- export default class FileUploader {
20
- /**
21
- * Creates `FileUploader` instance.
22
- *
23
- * @param {Blob|String} fileOrData A blob object or a data string encoded with Base64.
24
- * @param {module:cloud-services/token~Token} token Token used for authentication.
25
- * @param {String} apiAddress API address.
26
- */
27
- constructor( fileOrData, token, apiAddress ) {
28
- if ( !fileOrData ) {
29
- /**
30
- * File must be provided as the first argument.
31
- *
32
- * @error fileuploader-missing-file
33
- */
34
- throw new CKEditorError( 'fileuploader-missing-file', null );
35
- }
36
-
37
- if ( !token ) {
38
- /**
39
- * Token must be provided as the second argument.
40
- *
41
- * @error fileuploader-missing-token
42
- */
43
- throw new CKEditorError( 'fileuploader-missing-token', null );
44
- }
45
-
46
- if ( !apiAddress ) {
47
- /**
48
- * Api address must be provided as the third argument.
49
- *
50
- * @error fileuploader-missing-api-address
51
- */
52
- throw new CKEditorError( 'fileuploader-missing-api-address', null );
53
- }
54
-
55
- /**
56
- * A file that is being uploaded.
57
- *
58
- * @type {Blob}
59
- */
60
- this.file = _isBase64( fileOrData ) ? _base64ToBlob( fileOrData ) : fileOrData;
61
-
62
- /**
63
- * CKEditor Cloud Services access token.
64
- *
65
- * @type {module:cloud-services/token~Token}
66
- * @private
67
- */
68
- this._token = token;
69
-
70
- /**
71
- * CKEditor Cloud Services API address.
72
- *
73
- * @type {String}
74
- * @private
75
- */
76
- this._apiAddress = apiAddress;
77
- }
78
-
79
- /**
80
- * Registers callback on `progress` event.
81
- *
82
- * @chainable
83
- * @param {Function} callback
84
- * @returns {module:cloud-services/uploadgateway/fileuploader~FileUploader}
85
- */
86
- onProgress( callback ) {
87
- this.on( 'progress', ( event, data ) => callback( data ) );
88
-
89
- return this;
90
- }
91
-
92
- /**
93
- * Registers callback on `error` event. Event is called once when error occurs.
94
- *
95
- * @chainable
96
- * @param {Function} callback
97
- * @returns {module:cloud-services/uploadgateway/fileuploader~FileUploader}
98
- */
99
- onError( callback ) {
100
- this.once( 'error', ( event, data ) => callback( data ) );
101
-
102
- return this;
103
- }
104
-
105
- /**
106
- * Aborts upload process.
107
- */
108
- abort() {
109
- this.xhr.abort();
110
- }
111
-
112
- /**
113
- * Sends XHR request to API.
114
- *
115
- * @chainable
116
- * @returns {Promise.<Object>}
117
- */
118
- send() {
119
- this._prepareRequest();
120
- this._attachXHRListeners();
121
-
122
- return this._sendRequest();
123
- }
124
-
125
- /**
126
- * Prepares XHR request.
127
- *
128
- * @private
129
- */
130
- _prepareRequest() {
131
- const xhr = new XMLHttpRequest();
132
-
133
- xhr.open( 'POST', this._apiAddress );
134
- xhr.setRequestHeader( 'Authorization', this._token.value );
135
- xhr.responseType = 'json';
136
-
137
- this.xhr = xhr;
138
- }
139
-
140
- /**
141
- * Attaches listeners to the XHR.
142
- *
143
- * @private
144
- */
145
- _attachXHRListeners() {
146
- const that = this;
147
- const xhr = this.xhr;
148
-
149
- xhr.addEventListener( 'error', onError( 'Network Error' ) );
150
- xhr.addEventListener( 'abort', onError( 'Abort' ) );
151
-
152
- /* istanbul ignore else */
153
- if ( xhr.upload ) {
154
- xhr.upload.addEventListener( 'progress', event => {
155
- if ( event.lengthComputable ) {
156
- this.fire( 'progress', {
157
- total: event.total,
158
- uploaded: event.loaded
159
- } );
160
- }
161
- } );
162
- }
163
-
164
- xhr.addEventListener( 'load', () => {
165
- const statusCode = xhr.status;
166
- const xhrResponse = xhr.response;
167
-
168
- if ( statusCode < 200 || statusCode > 299 ) {
169
- return this.fire( 'error', xhrResponse.message || xhrResponse.error );
170
- }
171
- } );
172
-
173
- function onError( message ) {
174
- return () => that.fire( 'error', message );
175
- }
176
- }
177
-
178
- /**
179
- * Sends XHR request.
180
- *
181
- * @private
182
- */
183
- _sendRequest() {
184
- const formData = new FormData();
185
- const xhr = this.xhr;
186
-
187
- formData.append( 'file', this.file );
188
-
189
- return new Promise( ( resolve, reject ) => {
190
- xhr.addEventListener( 'load', () => {
191
- const statusCode = xhr.status;
192
- const xhrResponse = xhr.response;
193
-
194
- if ( statusCode < 200 || statusCode > 299 ) {
195
- if ( xhrResponse.message ) {
196
- /**
197
- * Uploading file failed.
198
- *
199
- * @error fileuploader-uploading-data-failed
200
- */
201
- return reject( new CKEditorError(
202
- 'fileuploader-uploading-data-failed',
203
- this,
204
- { message: xhrResponse.message }
205
- ) );
206
- }
207
-
208
- return reject( xhrResponse.error );
209
- }
210
-
211
- return resolve( xhrResponse );
212
- } );
213
-
214
- xhr.addEventListener( 'error', () => reject( new Error( 'Network Error' ) ) );
215
- xhr.addEventListener( 'abort', () => reject( new Error( 'Abort' ) ) );
216
-
217
- xhr.send( formData );
218
- } );
219
- }
220
-
221
- /**
222
- * Fired when error occurs.
223
- *
224
- * @event error
225
- * @param {String} error Error message
226
- */
227
-
228
- /**
229
- * Fired on upload progress.
230
- *
231
- * @event progress
232
- * @param {Object} status Total and uploaded status
233
- */
10
+ export default class FileUploader extends EmitterMixin() {
11
+ /**
12
+ * Creates `FileUploader` instance.
13
+ *
14
+ * @param fileOrData A blob object or a data string encoded with Base64.
15
+ * @param token Token used for authentication.
16
+ * @param apiAddress API address.
17
+ */
18
+ constructor(fileOrData, token, apiAddress) {
19
+ super();
20
+ if (!fileOrData) {
21
+ /**
22
+ * File must be provided as the first argument.
23
+ *
24
+ * @error fileuploader-missing-file
25
+ */
26
+ throw new CKEditorError('fileuploader-missing-file', null);
27
+ }
28
+ if (!token) {
29
+ /**
30
+ * Token must be provided as the second argument.
31
+ *
32
+ * @error fileuploader-missing-token
33
+ */
34
+ throw new CKEditorError('fileuploader-missing-token', null);
35
+ }
36
+ if (!apiAddress) {
37
+ /**
38
+ * Api address must be provided as the third argument.
39
+ *
40
+ * @error fileuploader-missing-api-address
41
+ */
42
+ throw new CKEditorError('fileuploader-missing-api-address', null);
43
+ }
44
+ this.file = _isBase64(fileOrData) ? _base64ToBlob(fileOrData) : fileOrData;
45
+ this._token = token;
46
+ this._apiAddress = apiAddress;
47
+ }
48
+ /**
49
+ * Registers callback on `progress` event.
50
+ */
51
+ onProgress(callback) {
52
+ this.on('progress', (event, data) => callback(data));
53
+ return this;
54
+ }
55
+ /**
56
+ * Registers callback on `error` event. Event is called once when error occurs.
57
+ */
58
+ onError(callback) {
59
+ this.once('error', (event, data) => callback(data));
60
+ return this;
61
+ }
62
+ /**
63
+ * Aborts upload process.
64
+ */
65
+ abort() {
66
+ this.xhr.abort();
67
+ }
68
+ /**
69
+ * Sends XHR request to API.
70
+ */
71
+ send() {
72
+ this._prepareRequest();
73
+ this._attachXHRListeners();
74
+ return this._sendRequest();
75
+ }
76
+ /**
77
+ * Prepares XHR request.
78
+ */
79
+ _prepareRequest() {
80
+ const xhr = new XMLHttpRequest();
81
+ xhr.open('POST', this._apiAddress);
82
+ xhr.setRequestHeader('Authorization', this._token.value);
83
+ xhr.responseType = 'json';
84
+ this.xhr = xhr;
85
+ }
86
+ /**
87
+ * Attaches listeners to the XHR.
88
+ */
89
+ _attachXHRListeners() {
90
+ const xhr = this.xhr;
91
+ const onError = (message) => {
92
+ return () => this.fire('error', message);
93
+ };
94
+ xhr.addEventListener('error', onError('Network Error'));
95
+ xhr.addEventListener('abort', onError('Abort'));
96
+ /* istanbul ignore else */
97
+ if (xhr.upload) {
98
+ xhr.upload.addEventListener('progress', event => {
99
+ if (event.lengthComputable) {
100
+ this.fire('progress', {
101
+ total: event.total,
102
+ uploaded: event.loaded
103
+ });
104
+ }
105
+ });
106
+ }
107
+ xhr.addEventListener('load', () => {
108
+ const statusCode = xhr.status;
109
+ const xhrResponse = xhr.response;
110
+ if (statusCode < 200 || statusCode > 299) {
111
+ return this.fire('error', xhrResponse.message || xhrResponse.error);
112
+ }
113
+ });
114
+ }
115
+ /**
116
+ * Sends XHR request.
117
+ */
118
+ _sendRequest() {
119
+ const formData = new FormData();
120
+ const xhr = this.xhr;
121
+ formData.append('file', this.file);
122
+ return new Promise((resolve, reject) => {
123
+ xhr.addEventListener('load', () => {
124
+ const statusCode = xhr.status;
125
+ const xhrResponse = xhr.response;
126
+ if (statusCode < 200 || statusCode > 299) {
127
+ if (xhrResponse.message) {
128
+ /**
129
+ * Uploading file failed.
130
+ *
131
+ * @error fileuploader-uploading-data-failed
132
+ */
133
+ return reject(new CKEditorError('fileuploader-uploading-data-failed', this, { message: xhrResponse.message }));
134
+ }
135
+ return reject(xhrResponse.error);
136
+ }
137
+ return resolve(xhrResponse);
138
+ });
139
+ xhr.addEventListener('error', () => reject(new Error('Network Error')));
140
+ xhr.addEventListener('abort', () => reject(new Error('Abort')));
141
+ xhr.send(formData);
142
+ });
143
+ }
234
144
  }
235
-
236
- mix( FileUploader, EmitterMixin );
237
-
238
145
  /**
239
146
  * Transforms Base64 string data into file.
240
147
  *
241
- * @param {String} base64 String data.
242
- * @param {Number} [sliceSize=512]
243
- * @returns {Blob}
244
- * @private
148
+ * @param base64 String data.
245
149
  */
246
- function _base64ToBlob( base64, sliceSize = 512 ) {
247
- try {
248
- const contentType = base64.match( BASE64_HEADER_REG_EXP )[ 1 ];
249
- const base64Data = atob( base64.replace( BASE64_HEADER_REG_EXP, '' ) );
250
-
251
- const byteArrays = [];
252
-
253
- for ( let offset = 0; offset < base64Data.length; offset += sliceSize ) {
254
- const slice = base64Data.slice( offset, offset + sliceSize );
255
- const byteNumbers = new Array( slice.length );
256
-
257
- for ( let i = 0; i < slice.length; i++ ) {
258
- byteNumbers[ i ] = slice.charCodeAt( i );
259
- }
260
-
261
- byteArrays.push( new Uint8Array( byteNumbers ) );
262
- }
263
-
264
- return new Blob( byteArrays, { type: contentType } );
265
- } catch ( error ) {
266
- /**
267
- * Problem with decoding Base64 image data.
268
- *
269
- * @error fileuploader-decoding-image-data-error
270
- */
271
- throw new CKEditorError( 'fileuploader-decoding-image-data-error', null );
272
- }
150
+ function _base64ToBlob(base64, sliceSize = 512) {
151
+ try {
152
+ const contentType = base64.match(BASE64_HEADER_REG_EXP)[1];
153
+ const base64Data = atob(base64.replace(BASE64_HEADER_REG_EXP, ''));
154
+ const byteArrays = [];
155
+ for (let offset = 0; offset < base64Data.length; offset += sliceSize) {
156
+ const slice = base64Data.slice(offset, offset + sliceSize);
157
+ const byteNumbers = new Array(slice.length);
158
+ for (let i = 0; i < slice.length; i++) {
159
+ byteNumbers[i] = slice.charCodeAt(i);
160
+ }
161
+ byteArrays.push(new Uint8Array(byteNumbers));
162
+ }
163
+ return new Blob(byteArrays, { type: contentType });
164
+ }
165
+ catch (error) {
166
+ /**
167
+ * Problem with decoding Base64 image data.
168
+ *
169
+ * @error fileuploader-decoding-image-data-error
170
+ */
171
+ throw new CKEditorError('fileuploader-decoding-image-data-error', null);
172
+ }
273
173
  }
274
-
275
174
  /**
276
175
  * Checks that string is Base64.
277
- *
278
- * @param {String} string
279
- * @returns {Boolean}
280
- * @private
281
176
  */
282
- function _isBase64( string ) {
283
- if ( typeof string !== 'string' ) {
284
- return false;
285
- }
286
-
287
- const match = string.match( BASE64_HEADER_REG_EXP );
288
- return !!( match && match.length );
177
+ function _isBase64(string) {
178
+ if (typeof string !== 'string') {
179
+ return false;
180
+ }
181
+ const match = string.match(BASE64_HEADER_REG_EXP);
182
+ return !!(match && match.length);
289
183
  }
@@ -0,0 +1,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 cloud-services/uploadgateway/uploadgateway
7
+ */
8
+ import FileUploader from './fileuploader';
9
+ import type { InitializedToken } from '../token/token';
10
+ /**
11
+ * UploadGateway abstracts file uploads to CKEditor Cloud Services.
12
+ */
13
+ export default class UploadGateway {
14
+ /**
15
+ * CKEditor Cloud Services access token.
16
+ */
17
+ private readonly _token;
18
+ /**
19
+ * CKEditor Cloud Services API address.
20
+ */
21
+ private readonly _apiAddress;
22
+ /**
23
+ * Creates `UploadGateway` instance.
24
+ *
25
+ * @param token Token used for authentication.
26
+ * @param apiAddress API address.
27
+ */
28
+ constructor(token: InitializedToken, apiAddress: string);
29
+ /**
30
+ * Creates a {@link module:cloud-services/uploadgateway/fileuploader~FileUploader} instance that wraps
31
+ * file upload process. The file is being sent at a time when the
32
+ * {@link module:cloud-services/uploadgateway/fileuploader~FileUploader#send} method is called.
33
+ *
34
+ * ```ts
35
+ * const token = await Token.create( 'https://token-endpoint' );
36
+ * new UploadGateway( token, 'https://example.org' )
37
+ * .upload( 'FILE' )
38
+ * .onProgress( ( data ) => console.log( data ) )
39
+ * .send()
40
+ * .then( ( response ) => console.log( response ) );
41
+ * ```
42
+ *
43
+ * @param {Blob|String} fileOrData A blob object or a data string encoded with Base64.
44
+ * @returns {module:cloud-services/uploadgateway/fileuploader~FileUploader} Returns `FileUploader` instance.
45
+ */
46
+ upload(fileOrData: string | Blob): FileUploader;
47
+ }