@ckeditor/ckeditor5-upload 41.4.2 → 42.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.
- 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 };
|