@ckeditor/ckeditor5-upload 41.4.1 → 42.0.0-alpha.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +6 -0
- package/dist/index.js +314 -235
- package/dist/index.js.map +1 -1
- package/dist/types/adapters/base64uploadadapter.d.ts +1 -1
- package/dist/types/filereader.d.ts +1 -1
- package/dist/types/filerepository.d.ts +1 -1
- package/package.json +3 -3
- package/src/adapters/base64uploadadapter.d.ts +1 -1
- package/src/adapters/base64uploadadapter.js +1 -1
- package/src/filereader.d.ts +1 -1
- package/src/filereader.js +1 -1
- package/src/filerepository.d.ts +1 -1
- package/src/filerepository.js +6 -3
package/dist/index.js
CHANGED
@@ -3,27 +3,49 @@
|
|
3
3
|
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
4
4
|
*/
|
5
5
|
import { Plugin, PendingActions } from '@ckeditor/ckeditor5-core/dist/index.js';
|
6
|
-
import { ObservableMixin,
|
6
|
+
import { ObservableMixin, Collection, logWarning, uid, CKEditorError } from '@ckeditor/ckeditor5-utils/dist/index.js';
|
7
7
|
|
8
|
-
|
8
|
+
/**
|
9
|
+
* Wrapper over the native `FileReader`.
|
10
|
+
*/ class FileReader extends /* #__PURE__ */ ObservableMixin() {
|
11
|
+
total;
|
12
|
+
/**
|
13
|
+
* Instance of native FileReader.
|
14
|
+
*/ _reader;
|
15
|
+
/**
|
16
|
+
* Holds the data of an already loaded file. The file must be first loaded
|
17
|
+
* by using {@link module:upload/filereader~FileReader#read `read()`}.
|
18
|
+
*/ _data;
|
19
|
+
/**
|
20
|
+
* Creates an instance of the FileReader.
|
21
|
+
*/ constructor(){
|
22
|
+
super();
|
23
|
+
const reader = new window.FileReader();
|
24
|
+
this._reader = reader;
|
25
|
+
this._data = undefined;
|
26
|
+
this.set('loaded', 0);
|
27
|
+
reader.onprogress = (evt)=>{
|
28
|
+
this.loaded = evt.loaded;
|
29
|
+
};
|
30
|
+
}
|
9
31
|
/**
|
10
|
-
|
11
|
-
|
32
|
+
* Returns error that occurred during file reading.
|
33
|
+
*/ get error() {
|
12
34
|
return this._reader.error;
|
13
35
|
}
|
14
36
|
/**
|
15
|
-
|
16
|
-
|
17
|
-
|
37
|
+
* Holds the data of an already loaded file. The file must be first loaded
|
38
|
+
* by using {@link module:upload/filereader~FileReader#read `read()`}.
|
39
|
+
*/ get data() {
|
18
40
|
return this._data;
|
19
41
|
}
|
20
42
|
/**
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
43
|
+
* Reads the provided file.
|
44
|
+
*
|
45
|
+
* @param file Native File object.
|
46
|
+
* @returns Returns a promise that will be resolved with file's content.
|
47
|
+
* The promise will be rejected in case of an error or when the reading process is aborted.
|
48
|
+
*/ read(file) {
|
27
49
|
const reader = this._reader;
|
28
50
|
this.total = file.size;
|
29
51
|
return new Promise((resolve, reject)=>{
|
@@ -42,40 +64,49 @@ class FileReader extends ObservableMixin() {
|
|
42
64
|
});
|
43
65
|
}
|
44
66
|
/**
|
45
|
-
|
46
|
-
|
67
|
+
* Aborts file reader.
|
68
|
+
*/ abort() {
|
47
69
|
this._reader.abort();
|
48
70
|
}
|
49
|
-
/**
|
50
|
-
* Creates an instance of the FileReader.
|
51
|
-
*/ constructor(){
|
52
|
-
super();
|
53
|
-
const reader = new window.FileReader();
|
54
|
-
this._reader = reader;
|
55
|
-
this._data = undefined;
|
56
|
-
this.set('loaded', 0);
|
57
|
-
reader.onprogress = (evt)=>{
|
58
|
-
this.loaded = evt.loaded;
|
59
|
-
};
|
60
|
-
}
|
61
71
|
}
|
62
72
|
|
63
|
-
|
73
|
+
/**
|
74
|
+
* File repository plugin. A central point for managing file upload.
|
75
|
+
*
|
76
|
+
* To use it, first you need an upload adapter. Upload adapter's job is to handle communication with the server
|
77
|
+
* (sending the file and handling server's response). You can use one of the existing plugins introducing upload adapters
|
78
|
+
* (e.g. {@link module:easy-image/cloudservicesuploadadapter~CloudServicesUploadAdapter} or
|
79
|
+
* {@link module:adapter-ckfinder/uploadadapter~CKFinderUploadAdapter}) or write your own one – see
|
80
|
+
* the {@glink framework/deep-dive/upload-adapter Custom image upload adapter deep-dive} guide.
|
81
|
+
*
|
82
|
+
* Then, you can use {@link module:upload/filerepository~FileRepository#createLoader `createLoader()`} and the returned
|
83
|
+
* {@link module:upload/filerepository~FileLoader} instance to load and upload files.
|
84
|
+
*/ class FileRepository extends Plugin {
|
85
|
+
/**
|
86
|
+
* Collection of loaders associated with this repository.
|
87
|
+
*/ loaders = new Collection();
|
88
|
+
/**
|
89
|
+
* Loaders mappings used to retrieve loaders references.
|
90
|
+
*/ _loadersMap = new Map();
|
64
91
|
/**
|
65
|
-
|
66
|
-
|
92
|
+
* Reference to a pending action registered in a {@link module:core/pendingactions~PendingActions} plugin
|
93
|
+
* while upload is in progress. When there is no upload then value is `null`.
|
94
|
+
*/ _pendingAction = null;
|
95
|
+
/**
|
96
|
+
* @inheritDoc
|
97
|
+
*/ static get pluginName() {
|
67
98
|
return 'FileRepository';
|
68
99
|
}
|
69
100
|
/**
|
70
|
-
|
71
|
-
|
101
|
+
* @inheritDoc
|
102
|
+
*/ static get requires() {
|
72
103
|
return [
|
73
104
|
PendingActions
|
74
105
|
];
|
75
106
|
}
|
76
107
|
/**
|
77
|
-
|
78
|
-
|
108
|
+
* @inheritDoc
|
109
|
+
*/ init() {
|
79
110
|
// Keeps upload in a sync with pending actions.
|
80
111
|
this.loaders.on('change', ()=>this._updatePendingAction());
|
81
112
|
this.set('uploaded', 0);
|
@@ -85,45 +116,48 @@ class FileRepository extends Plugin {
|
|
85
116
|
});
|
86
117
|
}
|
87
118
|
/**
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
119
|
+
* Returns the loader associated with specified file or promise.
|
120
|
+
*
|
121
|
+
* To get loader by id use `fileRepository.loaders.get( id )`.
|
122
|
+
*
|
123
|
+
* @param fileOrPromise Native file or promise handle.
|
124
|
+
*/ getLoader(fileOrPromise) {
|
94
125
|
return this._loadersMap.get(fileOrPromise) || null;
|
95
126
|
}
|
96
127
|
/**
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
128
|
+
* Creates a loader instance for the given file.
|
129
|
+
*
|
130
|
+
* Requires {@link #createUploadAdapter} factory to be defined.
|
131
|
+
*
|
132
|
+
* @param fileOrPromise Native File object or native Promise object which resolves to a File.
|
133
|
+
*/ createLoader(fileOrPromise) {
|
103
134
|
if (!this.createUploadAdapter) {
|
104
135
|
/**
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
136
|
+
* You need to enable an upload adapter in order to be able to upload files.
|
137
|
+
*
|
138
|
+
* This warning shows up when {@link module:upload/filerepository~FileRepository} is being used
|
139
|
+
* without {@link module:upload/filerepository~FileRepository#createUploadAdapter defining an upload adapter}.
|
140
|
+
*
|
141
|
+
* **If you see this warning when using one of the {@glink getting-started/legacy/installation-methods/predefined-builds
|
142
|
+
* CKEditor 5 Builds}**
|
143
|
+
* it means that you did not configure any of the upload adapters available by default in those builds.
|
144
|
+
*
|
145
|
+
* Predefined builds are a deprecated solution and we strongly advise
|
146
|
+
* {@glink updating/new-installation-methods migrating to new installation methods}.
|
147
|
+
*
|
148
|
+
* See the {@glink features/images/image-upload/image-upload comprehensive "Image upload overview"} to learn which upload
|
149
|
+
* adapters are available in the builds and how to configure them.
|
150
|
+
*
|
151
|
+
* Otherwise, if you see this warning, there is a chance that you enabled
|
152
|
+
* a feature like {@link module:image/imageupload~ImageUpload},
|
153
|
+
* or {@link module:image/imageupload/imageuploadui~ImageUploadUI} but you did not enable any upload adapter.
|
154
|
+
* You can choose one of the existing upload adapters listed in the
|
155
|
+
* {@glink features/images/image-upload/image-upload "Image upload overview"}.
|
156
|
+
*
|
157
|
+
* You can also implement your {@glink framework/deep-dive/upload-adapter own image upload adapter}.
|
158
|
+
*
|
159
|
+
* @error filerepository-no-upload-adapter
|
160
|
+
*/ logWarning('filerepository-no-upload-adapter');
|
127
161
|
return null;
|
128
162
|
}
|
129
163
|
const loader = new FileLoader(Promise.resolve(fileOrPromise), this.createUploadAdapter);
|
@@ -157,10 +191,10 @@ class FileRepository extends Plugin {
|
|
157
191
|
return loader;
|
158
192
|
}
|
159
193
|
/**
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
194
|
+
* Destroys the given loader.
|
195
|
+
*
|
196
|
+
* @param fileOrPromiseOrLoader File or Promise associated with that loader or loader itself.
|
197
|
+
*/ destroyLoader(fileOrPromiseOrLoader) {
|
164
198
|
const loader = fileOrPromiseOrLoader instanceof FileLoader ? fileOrPromiseOrLoader : this.getLoader(fileOrPromiseOrLoader);
|
165
199
|
loader._destroy();
|
166
200
|
this.loaders.remove(loader);
|
@@ -171,8 +205,8 @@ class FileRepository extends Plugin {
|
|
171
205
|
});
|
172
206
|
}
|
173
207
|
/**
|
174
|
-
|
175
|
-
|
208
|
+
* Registers or deregisters pending action bound with upload progress.
|
209
|
+
*/ _updatePendingAction() {
|
176
210
|
const pendingActions = this.editor.plugins.get(PendingActions);
|
177
211
|
if (this.loaders.length) {
|
178
212
|
if (!this._pendingAction) {
|
@@ -186,28 +220,48 @@ class FileRepository extends Plugin {
|
|
186
220
|
this._pendingAction = null;
|
187
221
|
}
|
188
222
|
}
|
189
|
-
constructor(){
|
190
|
-
super(...arguments);
|
191
|
-
/**
|
192
|
-
* Collection of loaders associated with this repository.
|
193
|
-
*/ this.loaders = new Collection();
|
194
|
-
/**
|
195
|
-
* Loaders mappings used to retrieve loaders references.
|
196
|
-
*/ this._loadersMap = new Map();
|
197
|
-
/**
|
198
|
-
* Reference to a pending action registered in a {@link module:core/pendingactions~PendingActions} plugin
|
199
|
-
* while upload is in progress. When there is no upload then value is `null`.
|
200
|
-
*/ this._pendingAction = null;
|
201
|
-
}
|
202
223
|
}
|
203
224
|
/**
|
204
225
|
* File loader class.
|
205
226
|
*
|
206
227
|
* It is used to control the process of reading the file and uploading it using the specified upload adapter.
|
207
|
-
*/ class FileLoader extends ObservableMixin() {
|
228
|
+
*/ class FileLoader extends /* #__PURE__ */ ObservableMixin() {
|
229
|
+
/**
|
230
|
+
* Unique id of FileLoader instance.
|
231
|
+
*
|
232
|
+
* @readonly
|
233
|
+
*/ id;
|
234
|
+
/**
|
235
|
+
* Additional wrapper over the initial file promise passed to this loader.
|
236
|
+
*/ _filePromiseWrapper;
|
237
|
+
/**
|
238
|
+
* Adapter instance associated with this file loader.
|
239
|
+
*/ _adapter;
|
240
|
+
/**
|
241
|
+
* FileReader used by FileLoader.
|
242
|
+
*/ _reader;
|
243
|
+
/**
|
244
|
+
* Creates a new instance of `FileLoader`.
|
245
|
+
*
|
246
|
+
* @param filePromise A promise which resolves to a file instance.
|
247
|
+
* @param uploadAdapterCreator The function which returns {@link module:upload/filerepository~UploadAdapter} instance.
|
248
|
+
*/ constructor(filePromise, uploadAdapterCreator){
|
249
|
+
super();
|
250
|
+
this.id = uid();
|
251
|
+
this._filePromiseWrapper = this._createFilePromiseWrapper(filePromise);
|
252
|
+
this._adapter = uploadAdapterCreator(this);
|
253
|
+
this._reader = new FileReader();
|
254
|
+
this.set('status', 'idle');
|
255
|
+
this.set('uploaded', 0);
|
256
|
+
this.set('uploadTotal', null);
|
257
|
+
this.bind('uploadedPercent').to(this, 'uploaded', this, 'uploadTotal', (uploaded, total)=>{
|
258
|
+
return total ? uploaded / total * 100 : 0;
|
259
|
+
});
|
260
|
+
this.set('uploadResponse', null);
|
261
|
+
}
|
208
262
|
/**
|
209
|
-
|
210
|
-
|
263
|
+
* A `Promise` which resolves to a `File` instance associated with this file loader.
|
264
|
+
*/ get file() {
|
211
265
|
if (!this._filePromiseWrapper) {
|
212
266
|
// Loader was destroyed, return promise which resolves to null.
|
213
267
|
return Promise.resolve(null);
|
@@ -224,40 +278,40 @@ class FileRepository extends Plugin {
|
|
224
278
|
}
|
225
279
|
}
|
226
280
|
/**
|
227
|
-
|
228
|
-
|
229
|
-
|
281
|
+
* Returns the file data. To read its data, you need for first load the file
|
282
|
+
* by using the {@link module:upload/filerepository~FileLoader#read `read()`} method.
|
283
|
+
*/ get data() {
|
230
284
|
return this._reader.data;
|
231
285
|
}
|
232
286
|
/**
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
287
|
+
* Reads file using {@link module:upload/filereader~FileReader}.
|
288
|
+
*
|
289
|
+
* Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `filerepository-read-wrong-status` when status
|
290
|
+
* is different than `idle`.
|
291
|
+
*
|
292
|
+
* Example usage:
|
293
|
+
*
|
294
|
+
* ```ts
|
295
|
+
* fileLoader.read()
|
296
|
+
* .then( data => { ... } )
|
297
|
+
* .catch( err => {
|
298
|
+
* if ( err === 'aborted' ) {
|
299
|
+
* console.log( 'Reading aborted.' );
|
300
|
+
* } else {
|
301
|
+
* console.log( 'Reading error.', err );
|
302
|
+
* }
|
303
|
+
* } );
|
304
|
+
* ```
|
305
|
+
*
|
306
|
+
* @returns Returns promise that will be resolved with read data. Promise will be rejected if error
|
307
|
+
* occurs or if read process is aborted.
|
308
|
+
*/ read() {
|
255
309
|
if (this.status != 'idle') {
|
256
310
|
/**
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
311
|
+
* You cannot call read if the status is different than idle.
|
312
|
+
*
|
313
|
+
* @error filerepository-read-wrong-status
|
314
|
+
*/ throw new CKEditorError('filerepository-read-wrong-status', this);
|
261
315
|
}
|
262
316
|
this.status = 'reading';
|
263
317
|
return this.file.then((file)=>this._reader.read(file)).then((data)=>{
|
@@ -278,33 +332,33 @@ class FileRepository extends Plugin {
|
|
278
332
|
});
|
279
333
|
}
|
280
334
|
/**
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
335
|
+
* Reads file using the provided {@link module:upload/filerepository~UploadAdapter}.
|
336
|
+
*
|
337
|
+
* Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `filerepository-upload-wrong-status` when status
|
338
|
+
* is different than `idle`.
|
339
|
+
* Example usage:
|
340
|
+
*
|
341
|
+
* ```ts
|
342
|
+
* fileLoader.upload()
|
343
|
+
* .then( data => { ... } )
|
344
|
+
* .catch( e => {
|
345
|
+
* if ( e === 'aborted' ) {
|
346
|
+
* console.log( 'Uploading aborted.' );
|
347
|
+
* } else {
|
348
|
+
* console.log( 'Uploading error.', e );
|
349
|
+
* }
|
350
|
+
* } );
|
351
|
+
* ```
|
352
|
+
*
|
353
|
+
* @returns Returns promise that will be resolved with response data. Promise will be rejected if error
|
354
|
+
* occurs or if read process is aborted.
|
355
|
+
*/ upload() {
|
302
356
|
if (this.status != 'idle') {
|
303
357
|
/**
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
358
|
+
* You cannot call upload if the status is different than idle.
|
359
|
+
*
|
360
|
+
* @error filerepository-upload-wrong-status
|
361
|
+
*/ throw new CKEditorError('filerepository-upload-wrong-status', this);
|
308
362
|
}
|
309
363
|
this.status = 'uploading';
|
310
364
|
return this.file.then(()=>this._adapter.upload()).then((data)=>{
|
@@ -320,8 +374,8 @@ class FileRepository extends Plugin {
|
|
320
374
|
});
|
321
375
|
}
|
322
376
|
/**
|
323
|
-
|
324
|
-
|
377
|
+
* Aborts loading process.
|
378
|
+
*/ abort() {
|
325
379
|
const status = this.status;
|
326
380
|
this.status = 'aborted';
|
327
381
|
if (!this._filePromiseWrapper.isFulfilled) {
|
@@ -338,21 +392,21 @@ class FileRepository extends Plugin {
|
|
338
392
|
this._destroy();
|
339
393
|
}
|
340
394
|
/**
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
395
|
+
* Performs cleanup.
|
396
|
+
*
|
397
|
+
* @internal
|
398
|
+
*/ _destroy() {
|
345
399
|
this._filePromiseWrapper = undefined;
|
346
400
|
this._reader = undefined;
|
347
401
|
this._adapter = undefined;
|
348
402
|
this.uploadResponse = undefined;
|
349
403
|
}
|
350
404
|
/**
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
405
|
+
* Wraps a given file promise into another promise giving additional
|
406
|
+
* control (resolving, rejecting, checking if fulfilled) over it.
|
407
|
+
*
|
408
|
+
* @param filePromise The initial file promise to be wrapped.
|
409
|
+
*/ _createFilePromiseWrapper(filePromise) {
|
356
410
|
const wrapper = {};
|
357
411
|
wrapper.promise = new Promise((resolve, reject)=>{
|
358
412
|
wrapper.rejecter = reject;
|
@@ -367,43 +421,33 @@ class FileRepository extends Plugin {
|
|
367
421
|
});
|
368
422
|
return wrapper;
|
369
423
|
}
|
370
|
-
/**
|
371
|
-
* Creates a new instance of `FileLoader`.
|
372
|
-
*
|
373
|
-
* @param filePromise A promise which resolves to a file instance.
|
374
|
-
* @param uploadAdapterCreator The function which returns {@link module:upload/filerepository~UploadAdapter} instance.
|
375
|
-
*/ constructor(filePromise, uploadAdapterCreator){
|
376
|
-
super();
|
377
|
-
this.id = uid();
|
378
|
-
this._filePromiseWrapper = this._createFilePromiseWrapper(filePromise);
|
379
|
-
this._adapter = uploadAdapterCreator(this);
|
380
|
-
this._reader = new FileReader();
|
381
|
-
this.set('status', 'idle');
|
382
|
-
this.set('uploaded', 0);
|
383
|
-
this.set('uploadTotal', null);
|
384
|
-
this.bind('uploadedPercent').to(this, 'uploaded', this, 'uploadTotal', (uploaded, total)=>{
|
385
|
-
return total ? uploaded / total * 100 : 0;
|
386
|
-
});
|
387
|
-
this.set('uploadResponse', null);
|
388
|
-
}
|
389
424
|
}
|
390
425
|
|
391
|
-
|
426
|
+
/**
|
427
|
+
* A plugin that converts images inserted into the editor into [Base64 strings](https://en.wikipedia.org/wiki/Base64)
|
428
|
+
* in the {@glink getting-started/setup/getting-and-setting-data editor output}.
|
429
|
+
*
|
430
|
+
* This kind of image upload does not require server processing – images are stored with the rest of the text and
|
431
|
+
* displayed by the web browser without additional requests.
|
432
|
+
*
|
433
|
+
* Check out the {@glink features/images/image-upload/image-upload comprehensive "Image upload overview"} to learn about
|
434
|
+
* other ways to upload images into CKEditor 5.
|
435
|
+
*/ class Base64UploadAdapter extends Plugin {
|
392
436
|
/**
|
393
|
-
|
394
|
-
|
437
|
+
* @inheritDoc
|
438
|
+
*/ static get requires() {
|
395
439
|
return [
|
396
440
|
FileRepository
|
397
441
|
];
|
398
442
|
}
|
399
443
|
/**
|
400
|
-
|
401
|
-
|
444
|
+
* @inheritDoc
|
445
|
+
*/ static get pluginName() {
|
402
446
|
return 'Base64UploadAdapter';
|
403
447
|
}
|
404
448
|
/**
|
405
|
-
|
406
|
-
|
449
|
+
* @inheritDoc
|
450
|
+
*/ init() {
|
407
451
|
this.editor.plugins.get(FileRepository).createUploadAdapter = (loader)=>new Adapter$1(loader);
|
408
452
|
}
|
409
453
|
}
|
@@ -411,10 +455,19 @@ class Base64UploadAdapter extends Plugin {
|
|
411
455
|
* The upload adapter that converts images inserted into the editor into Base64 strings.
|
412
456
|
*/ let Adapter$1 = class Adapter {
|
413
457
|
/**
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
458
|
+
* `FileLoader` instance to use during the upload.
|
459
|
+
*/ loader;
|
460
|
+
reader;
|
461
|
+
/**
|
462
|
+
* Creates a new adapter instance.
|
463
|
+
*/ constructor(loader){
|
464
|
+
this.loader = loader;
|
465
|
+
}
|
466
|
+
/**
|
467
|
+
* Starts the upload process.
|
468
|
+
*
|
469
|
+
* @see module:upload/filerepository~UploadAdapter#upload
|
470
|
+
*/ upload() {
|
418
471
|
return new Promise((resolve, reject)=>{
|
419
472
|
const reader = this.reader = new window.FileReader();
|
420
473
|
reader.addEventListener('load', ()=>{
|
@@ -434,47 +487,66 @@ class Base64UploadAdapter extends Plugin {
|
|
434
487
|
});
|
435
488
|
}
|
436
489
|
/**
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
490
|
+
* Aborts the upload process.
|
491
|
+
*
|
492
|
+
* @see module:upload/filerepository~UploadAdapter#abort
|
493
|
+
*/ abort() {
|
441
494
|
this.reader.abort();
|
442
495
|
}
|
443
|
-
/**
|
444
|
-
* Creates a new adapter instance.
|
445
|
-
*/ constructor(loader){
|
446
|
-
this.loader = loader;
|
447
|
-
}
|
448
496
|
};
|
449
497
|
|
450
|
-
|
498
|
+
/**
|
499
|
+
* The Simple upload adapter allows uploading images to an application running on your server using
|
500
|
+
* the [`XMLHttpRequest`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) API with a
|
501
|
+
* minimal {@link module:upload/uploadconfig~SimpleUploadConfig editor configuration}.
|
502
|
+
*
|
503
|
+
* ```ts
|
504
|
+
* ClassicEditor
|
505
|
+
* .create( document.querySelector( '#editor' ), {
|
506
|
+
* simpleUpload: {
|
507
|
+
* uploadUrl: 'http://example.com',
|
508
|
+
* headers: {
|
509
|
+
* ...
|
510
|
+
* }
|
511
|
+
* }
|
512
|
+
* } )
|
513
|
+
* .then( ... )
|
514
|
+
* .catch( ... );
|
515
|
+
* ```
|
516
|
+
*
|
517
|
+
* See the {@glink features/images/image-upload/simple-upload-adapter "Simple upload adapter"} guide to learn how to
|
518
|
+
* learn more about the feature (configuration, server–side requirements, etc.).
|
519
|
+
*
|
520
|
+
* Check out the {@glink features/images/image-upload/image-upload comprehensive "Image upload overview"} to learn about
|
521
|
+
* other ways to upload images into CKEditor 5.
|
522
|
+
*/ class SimpleUploadAdapter extends Plugin {
|
451
523
|
/**
|
452
|
-
|
453
|
-
|
524
|
+
* @inheritDoc
|
525
|
+
*/ static get requires() {
|
454
526
|
return [
|
455
527
|
FileRepository
|
456
528
|
];
|
457
529
|
}
|
458
530
|
/**
|
459
|
-
|
460
|
-
|
531
|
+
* @inheritDoc
|
532
|
+
*/ static get pluginName() {
|
461
533
|
return 'SimpleUploadAdapter';
|
462
534
|
}
|
463
535
|
/**
|
464
|
-
|
465
|
-
|
536
|
+
* @inheritDoc
|
537
|
+
*/ init() {
|
466
538
|
const options = this.editor.config.get('simpleUpload');
|
467
539
|
if (!options) {
|
468
540
|
return;
|
469
541
|
}
|
470
542
|
if (!options.uploadUrl) {
|
471
543
|
/**
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
544
|
+
* The {@link module:upload/uploadconfig~SimpleUploadConfig#uploadUrl `config.simpleUpload.uploadUrl`}
|
545
|
+
* configuration required by the {@link module:upload/adapters/simpleuploadadapter~SimpleUploadAdapter `SimpleUploadAdapter`}
|
546
|
+
* is missing. Make sure the correct URL is specified for the image upload to work properly.
|
547
|
+
*
|
548
|
+
* @error simple-upload-adapter-missing-uploadurl
|
549
|
+
*/ logWarning('simple-upload-adapter-missing-uploadurl');
|
478
550
|
return;
|
479
551
|
}
|
480
552
|
this.editor.plugins.get(FileRepository).createUploadAdapter = (loader)=>{
|
@@ -486,10 +558,23 @@ class SimpleUploadAdapter extends Plugin {
|
|
486
558
|
* Upload adapter.
|
487
559
|
*/ class Adapter {
|
488
560
|
/**
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
561
|
+
* FileLoader instance to use during the upload.
|
562
|
+
*/ loader;
|
563
|
+
/**
|
564
|
+
* The configuration of the adapter.
|
565
|
+
*/ options;
|
566
|
+
xhr;
|
567
|
+
/**
|
568
|
+
* Creates a new adapter instance.
|
569
|
+
*/ constructor(loader, options){
|
570
|
+
this.loader = loader;
|
571
|
+
this.options = options;
|
572
|
+
}
|
573
|
+
/**
|
574
|
+
* Starts the upload process.
|
575
|
+
*
|
576
|
+
* @see module:upload/filerepository~UploadAdapter#upload
|
577
|
+
*/ upload() {
|
493
578
|
return this.loader.file.then((file)=>new Promise((resolve, reject)=>{
|
494
579
|
this._initRequest();
|
495
580
|
this._initListeners(resolve, reject, file);
|
@@ -497,30 +582,30 @@ class SimpleUploadAdapter extends Plugin {
|
|
497
582
|
}));
|
498
583
|
}
|
499
584
|
/**
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
585
|
+
* Aborts the upload process.
|
586
|
+
*
|
587
|
+
* @see module:upload/filerepository~UploadAdapter#abort
|
588
|
+
*/ abort() {
|
504
589
|
if (this.xhr) {
|
505
590
|
this.xhr.abort();
|
506
591
|
}
|
507
592
|
}
|
508
593
|
/**
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
594
|
+
* Initializes the `XMLHttpRequest` object using the URL specified as
|
595
|
+
* {@link module:upload/uploadconfig~SimpleUploadConfig#uploadUrl `simpleUpload.uploadUrl`} in the editor's
|
596
|
+
* configuration.
|
597
|
+
*/ _initRequest() {
|
513
598
|
const xhr = this.xhr = new XMLHttpRequest();
|
514
599
|
xhr.open('POST', this.options.uploadUrl, true);
|
515
600
|
xhr.responseType = 'json';
|
516
601
|
}
|
517
602
|
/**
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
603
|
+
* Initializes XMLHttpRequest listeners
|
604
|
+
*
|
605
|
+
* @param resolve Callback function to be called when the request is successful.
|
606
|
+
* @param reject Callback function to be called when the request cannot be completed.
|
607
|
+
* @param file Native File object.
|
608
|
+
*/ _initListeners(resolve, reject, file) {
|
524
609
|
const xhr = this.xhr;
|
525
610
|
const loader = this.loader;
|
526
611
|
const genericErrorText = `Couldn't upload file: ${file.name}.`;
|
@@ -552,10 +637,10 @@ class SimpleUploadAdapter extends Plugin {
|
|
552
637
|
}
|
553
638
|
}
|
554
639
|
/**
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
640
|
+
* Prepares the data and sends the request.
|
641
|
+
*
|
642
|
+
* @param file File instance to be uploaded.
|
643
|
+
*/ _sendRequest(file) {
|
559
644
|
// Set headers if specified.
|
560
645
|
const headers = this.options.headers || {};
|
561
646
|
// Use the withCredentials flag if specified.
|
@@ -570,12 +655,6 @@ class SimpleUploadAdapter extends Plugin {
|
|
570
655
|
// Send the request.
|
571
656
|
this.xhr.send(data);
|
572
657
|
}
|
573
|
-
/**
|
574
|
-
* Creates a new adapter instance.
|
575
|
-
*/ constructor(loader, options){
|
576
|
-
this.loader = loader;
|
577
|
-
this.options = options;
|
578
|
-
}
|
579
658
|
}
|
580
659
|
|
581
660
|
export { Base64UploadAdapter, FileRepository, SimpleUploadAdapter };
|