@ckeditor/ckeditor5-upload 0.0.0-nightly-20240422.0 → 0.0.0-nightly-20240424.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.
Files changed (125) hide show
  1. package/dist/index-content.css +4 -0
  2. package/dist/index-editor.css +4 -0
  3. package/dist/index.css +4 -0
  4. package/dist/index.js +582 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/translations/ar.d.ts +8 -0
  7. package/dist/translations/ar.js +5 -0
  8. package/dist/translations/az.d.ts +8 -0
  9. package/dist/translations/az.js +5 -0
  10. package/dist/translations/bg.d.ts +8 -0
  11. package/dist/translations/bg.js +5 -0
  12. package/dist/translations/bn.d.ts +8 -0
  13. package/dist/translations/bn.js +5 -0
  14. package/dist/translations/ca.d.ts +8 -0
  15. package/dist/translations/ca.js +5 -0
  16. package/dist/translations/cs.d.ts +8 -0
  17. package/dist/translations/cs.js +5 -0
  18. package/dist/translations/da.d.ts +8 -0
  19. package/dist/translations/da.js +5 -0
  20. package/dist/translations/de-ch.d.ts +8 -0
  21. package/dist/translations/de-ch.js +5 -0
  22. package/dist/translations/de.d.ts +8 -0
  23. package/dist/translations/de.js +5 -0
  24. package/dist/translations/el.d.ts +8 -0
  25. package/dist/translations/el.js +5 -0
  26. package/dist/translations/en-au.d.ts +8 -0
  27. package/dist/translations/en-au.js +5 -0
  28. package/dist/translations/en-gb.d.ts +8 -0
  29. package/dist/translations/en-gb.js +5 -0
  30. package/dist/translations/en.d.ts +8 -0
  31. package/dist/translations/en.js +5 -0
  32. package/dist/translations/es-co.d.ts +8 -0
  33. package/dist/translations/es-co.js +5 -0
  34. package/dist/translations/es.d.ts +8 -0
  35. package/dist/translations/es.js +5 -0
  36. package/dist/translations/et.d.ts +8 -0
  37. package/dist/translations/et.js +5 -0
  38. package/dist/translations/fa.d.ts +8 -0
  39. package/dist/translations/fa.js +5 -0
  40. package/dist/translations/fi.d.ts +8 -0
  41. package/dist/translations/fi.js +5 -0
  42. package/dist/translations/fr.d.ts +8 -0
  43. package/dist/translations/fr.js +5 -0
  44. package/dist/translations/gl.d.ts +8 -0
  45. package/dist/translations/gl.js +5 -0
  46. package/dist/translations/he.d.ts +8 -0
  47. package/dist/translations/he.js +5 -0
  48. package/dist/translations/hi.d.ts +8 -0
  49. package/dist/translations/hi.js +5 -0
  50. package/dist/translations/hr.d.ts +8 -0
  51. package/dist/translations/hr.js +5 -0
  52. package/dist/translations/hu.d.ts +8 -0
  53. package/dist/translations/hu.js +5 -0
  54. package/dist/translations/id.d.ts +8 -0
  55. package/dist/translations/id.js +5 -0
  56. package/dist/translations/it.d.ts +8 -0
  57. package/dist/translations/it.js +5 -0
  58. package/dist/translations/ja.d.ts +8 -0
  59. package/dist/translations/ja.js +5 -0
  60. package/dist/translations/ko.d.ts +8 -0
  61. package/dist/translations/ko.js +5 -0
  62. package/dist/translations/ku.d.ts +8 -0
  63. package/dist/translations/ku.js +5 -0
  64. package/dist/translations/lt.d.ts +8 -0
  65. package/dist/translations/lt.js +5 -0
  66. package/dist/translations/lv.d.ts +8 -0
  67. package/dist/translations/lv.js +5 -0
  68. package/dist/translations/ms.d.ts +8 -0
  69. package/dist/translations/ms.js +5 -0
  70. package/dist/translations/nb.d.ts +8 -0
  71. package/dist/translations/nb.js +5 -0
  72. package/dist/translations/ne.d.ts +8 -0
  73. package/dist/translations/ne.js +5 -0
  74. package/dist/translations/nl.d.ts +8 -0
  75. package/dist/translations/nl.js +5 -0
  76. package/dist/translations/no.d.ts +8 -0
  77. package/dist/translations/no.js +5 -0
  78. package/dist/translations/pl.d.ts +8 -0
  79. package/dist/translations/pl.js +5 -0
  80. package/dist/translations/pt-br.d.ts +8 -0
  81. package/dist/translations/pt-br.js +5 -0
  82. package/dist/translations/pt.d.ts +8 -0
  83. package/dist/translations/pt.js +5 -0
  84. package/dist/translations/ro.d.ts +8 -0
  85. package/dist/translations/ro.js +5 -0
  86. package/dist/translations/ru.d.ts +8 -0
  87. package/dist/translations/ru.js +5 -0
  88. package/dist/translations/sk.d.ts +8 -0
  89. package/dist/translations/sk.js +5 -0
  90. package/dist/translations/sq.d.ts +8 -0
  91. package/dist/translations/sq.js +5 -0
  92. package/dist/translations/sr-latn.d.ts +8 -0
  93. package/dist/translations/sr-latn.js +5 -0
  94. package/dist/translations/sr.d.ts +8 -0
  95. package/dist/translations/sr.js +5 -0
  96. package/dist/translations/sv.d.ts +8 -0
  97. package/dist/translations/sv.js +5 -0
  98. package/dist/translations/th.d.ts +8 -0
  99. package/dist/translations/th.js +5 -0
  100. package/dist/translations/tk.d.ts +8 -0
  101. package/dist/translations/tk.js +5 -0
  102. package/dist/translations/tr.d.ts +8 -0
  103. package/dist/translations/tr.js +5 -0
  104. package/dist/translations/ug.d.ts +8 -0
  105. package/dist/translations/ug.js +5 -0
  106. package/dist/translations/uk.d.ts +8 -0
  107. package/dist/translations/uk.js +5 -0
  108. package/dist/translations/ur.d.ts +8 -0
  109. package/dist/translations/ur.js +5 -0
  110. package/dist/translations/uz.d.ts +8 -0
  111. package/dist/translations/uz.js +5 -0
  112. package/dist/translations/vi.d.ts +8 -0
  113. package/dist/translations/vi.js +5 -0
  114. package/dist/translations/zh-cn.d.ts +8 -0
  115. package/dist/translations/zh-cn.js +5 -0
  116. package/dist/translations/zh.d.ts +8 -0
  117. package/dist/translations/zh.js +5 -0
  118. package/dist/types/adapters/base64uploadadapter.d.ts +37 -0
  119. package/dist/types/adapters/simpleuploadadapter.d.ts +52 -0
  120. package/dist/types/augmentation.d.ts +24 -0
  121. package/dist/types/filereader.d.ts +60 -0
  122. package/dist/types/filerepository.d.ts +346 -0
  123. package/dist/types/index.d.ts +16 -0
  124. package/dist/types/uploadconfig.d.ts +94 -0
  125. package/package.json +4 -3
@@ -0,0 +1,4 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
@@ -0,0 +1,4 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
package/dist/index.css ADDED
@@ -0,0 +1,4 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
package/dist/index.js ADDED
@@ -0,0 +1,582 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, 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 { Plugin, PendingActions } from '@ckeditor/ckeditor5-core/dist/index.js';
6
+ import { ObservableMixin, CKEditorError, uid, logWarning, Collection } from '@ckeditor/ckeditor5-utils/dist/index.js';
7
+
8
+ class FileReader extends ObservableMixin() {
9
+ /**
10
+ * Returns error that occurred during file reading.
11
+ */ get error() {
12
+ return this._reader.error;
13
+ }
14
+ /**
15
+ * Holds the data of an already loaded file. The file must be first loaded
16
+ * by using {@link module:upload/filereader~FileReader#read `read()`}.
17
+ */ get data() {
18
+ return this._data;
19
+ }
20
+ /**
21
+ * Reads the provided file.
22
+ *
23
+ * @param file Native File object.
24
+ * @returns Returns a promise that will be resolved with file's content.
25
+ * The promise will be rejected in case of an error or when the reading process is aborted.
26
+ */ read(file) {
27
+ const reader = this._reader;
28
+ this.total = file.size;
29
+ return new Promise((resolve, reject)=>{
30
+ reader.onload = ()=>{
31
+ const result = reader.result;
32
+ this._data = result;
33
+ resolve(result);
34
+ };
35
+ reader.onerror = ()=>{
36
+ reject('error');
37
+ };
38
+ reader.onabort = ()=>{
39
+ reject('aborted');
40
+ };
41
+ this._reader.readAsDataURL(file);
42
+ });
43
+ }
44
+ /**
45
+ * Aborts file reader.
46
+ */ abort() {
47
+ this._reader.abort();
48
+ }
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
+ }
62
+
63
+ class FileRepository extends Plugin {
64
+ /**
65
+ * @inheritDoc
66
+ */ static get pluginName() {
67
+ return 'FileRepository';
68
+ }
69
+ /**
70
+ * @inheritDoc
71
+ */ static get requires() {
72
+ return [
73
+ PendingActions
74
+ ];
75
+ }
76
+ /**
77
+ * @inheritDoc
78
+ */ init() {
79
+ // Keeps upload in a sync with pending actions.
80
+ this.loaders.on('change', ()=>this._updatePendingAction());
81
+ this.set('uploaded', 0);
82
+ this.set('uploadTotal', null);
83
+ this.bind('uploadedPercent').to(this, 'uploaded', this, 'uploadTotal', (uploaded, total)=>{
84
+ return total ? uploaded / total * 100 : 0;
85
+ });
86
+ }
87
+ /**
88
+ * Returns the loader associated with specified file or promise.
89
+ *
90
+ * To get loader by id use `fileRepository.loaders.get( id )`.
91
+ *
92
+ * @param fileOrPromise Native file or promise handle.
93
+ */ getLoader(fileOrPromise) {
94
+ return this._loadersMap.get(fileOrPromise) || null;
95
+ }
96
+ /**
97
+ * Creates a loader instance for the given file.
98
+ *
99
+ * Requires {@link #createUploadAdapter} factory to be defined.
100
+ *
101
+ * @param fileOrPromise Native File object or native Promise object which resolves to a File.
102
+ */ createLoader(fileOrPromise) {
103
+ if (!this.createUploadAdapter) {
104
+ /**
105
+ * You need to enable an upload adapter in order to be able to upload files.
106
+ *
107
+ * This warning shows up when {@link module:upload/filerepository~FileRepository} is being used
108
+ * without {@link module:upload/filerepository~FileRepository#createUploadAdapter defining an upload adapter}.
109
+ *
110
+ * **If you see this warning when using one of the {@glink installation/getting-started/predefined-builds
111
+ * CKEditor 5 Builds}**
112
+ * it means that you did not configure any of the upload adapters available by default in those builds.
113
+ *
114
+ * See the {@glink features/images/image-upload/image-upload comprehensive "Image upload overview"} to learn which upload
115
+ * adapters are available in the builds and how to configure them.
116
+ *
117
+ * **If you see this warning when using a custom build** there is a chance that you enabled
118
+ * a feature like {@link module:image/imageupload~ImageUpload},
119
+ * or {@link module:image/imageupload/imageuploadui~ImageUploadUI} but you did not enable any upload adapter.
120
+ * You can choose one of the existing upload adapters listed in the
121
+ * {@glink features/images/image-upload/image-upload "Image upload overview"}.
122
+ *
123
+ * You can also implement your {@glink framework/deep-dive/upload-adapter own image upload adapter}.
124
+ *
125
+ * @error filerepository-no-upload-adapter
126
+ */ logWarning('filerepository-no-upload-adapter');
127
+ return null;
128
+ }
129
+ const loader = new FileLoader(Promise.resolve(fileOrPromise), this.createUploadAdapter);
130
+ this.loaders.add(loader);
131
+ this._loadersMap.set(fileOrPromise, loader);
132
+ // Store also file => loader mapping so loader can be retrieved by file instance returned upon Promise resolution.
133
+ if (fileOrPromise instanceof Promise) {
134
+ loader.file.then((file)=>{
135
+ this._loadersMap.set(file, loader);
136
+ })// Every then() must have a catch().
137
+ // File loader state (and rejections) are handled in read() and upload().
138
+ // Also, see the "does not swallow the file promise rejection" test.
139
+ .catch(()=>{});
140
+ }
141
+ loader.on('change:uploaded', ()=>{
142
+ let aggregatedUploaded = 0;
143
+ for (const loader of this.loaders){
144
+ aggregatedUploaded += loader.uploaded;
145
+ }
146
+ this.uploaded = aggregatedUploaded;
147
+ });
148
+ loader.on('change:uploadTotal', ()=>{
149
+ let aggregatedTotal = 0;
150
+ for (const loader of this.loaders){
151
+ if (loader.uploadTotal) {
152
+ aggregatedTotal += loader.uploadTotal;
153
+ }
154
+ }
155
+ this.uploadTotal = aggregatedTotal;
156
+ });
157
+ return loader;
158
+ }
159
+ /**
160
+ * Destroys the given loader.
161
+ *
162
+ * @param fileOrPromiseOrLoader File or Promise associated with that loader or loader itself.
163
+ */ destroyLoader(fileOrPromiseOrLoader) {
164
+ const loader = fileOrPromiseOrLoader instanceof FileLoader ? fileOrPromiseOrLoader : this.getLoader(fileOrPromiseOrLoader);
165
+ loader._destroy();
166
+ this.loaders.remove(loader);
167
+ this._loadersMap.forEach((value, key)=>{
168
+ if (value === loader) {
169
+ this._loadersMap.delete(key);
170
+ }
171
+ });
172
+ }
173
+ /**
174
+ * Registers or deregisters pending action bound with upload progress.
175
+ */ _updatePendingAction() {
176
+ const pendingActions = this.editor.plugins.get(PendingActions);
177
+ if (this.loaders.length) {
178
+ if (!this._pendingAction) {
179
+ const t = this.editor.t;
180
+ const getMessage = (value)=>`${t('Upload in progress')} ${parseInt(value)}%.`;
181
+ this._pendingAction = pendingActions.add(getMessage(this.uploadedPercent));
182
+ this._pendingAction.bind('message').to(this, 'uploadedPercent', getMessage);
183
+ }
184
+ } else {
185
+ pendingActions.remove(this._pendingAction);
186
+ this._pendingAction = null;
187
+ }
188
+ }
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
+ }
203
+ /**
204
+ * File loader class.
205
+ *
206
+ * It is used to control the process of reading the file and uploading it using the specified upload adapter.
207
+ */ class FileLoader extends ObservableMixin() {
208
+ /**
209
+ * A `Promise` which resolves to a `File` instance associated with this file loader.
210
+ */ get file() {
211
+ if (!this._filePromiseWrapper) {
212
+ // Loader was destroyed, return promise which resolves to null.
213
+ return Promise.resolve(null);
214
+ } else {
215
+ // The `this._filePromiseWrapper.promise` is chained and not simply returned to handle a case when:
216
+ //
217
+ // * The `loader.file.then( ... )` is called by external code (returned promise is pending).
218
+ // * Then `loader._destroy()` is called (call is synchronous) which destroys the `loader`.
219
+ // * Promise returned by the first `loader.file.then( ... )` call is resolved.
220
+ //
221
+ // Returning `this._filePromiseWrapper.promise` will still resolve to a `File` instance so there
222
+ // is an additional check needed in the chain to see if `loader` was destroyed in the meantime.
223
+ return this._filePromiseWrapper.promise.then((file)=>this._filePromiseWrapper ? file : null);
224
+ }
225
+ }
226
+ /**
227
+ * Returns the file data. To read its data, you need for first load the file
228
+ * by using the {@link module:upload/filerepository~FileLoader#read `read()`} method.
229
+ */ get data() {
230
+ return this._reader.data;
231
+ }
232
+ /**
233
+ * Reads file using {@link module:upload/filereader~FileReader}.
234
+ *
235
+ * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `filerepository-read-wrong-status` when status
236
+ * is different than `idle`.
237
+ *
238
+ * Example usage:
239
+ *
240
+ * ```ts
241
+ * fileLoader.read()
242
+ * .then( data => { ... } )
243
+ * .catch( err => {
244
+ * if ( err === 'aborted' ) {
245
+ * console.log( 'Reading aborted.' );
246
+ * } else {
247
+ * console.log( 'Reading error.', err );
248
+ * }
249
+ * } );
250
+ * ```
251
+ *
252
+ * @returns Returns promise that will be resolved with read data. Promise will be rejected if error
253
+ * occurs or if read process is aborted.
254
+ */ read() {
255
+ if (this.status != 'idle') {
256
+ /**
257
+ * You cannot call read if the status is different than idle.
258
+ *
259
+ * @error filerepository-read-wrong-status
260
+ */ throw new CKEditorError('filerepository-read-wrong-status', this);
261
+ }
262
+ this.status = 'reading';
263
+ return this.file.then((file)=>this._reader.read(file)).then((data)=>{
264
+ // Edge case: reader was aborted after file was read - double check for proper status.
265
+ // It can happen when image was deleted during its upload.
266
+ if (this.status !== 'reading') {
267
+ throw this.status;
268
+ }
269
+ this.status = 'idle';
270
+ return data;
271
+ }).catch((err)=>{
272
+ if (err === 'aborted') {
273
+ this.status = 'aborted';
274
+ throw 'aborted';
275
+ }
276
+ this.status = 'error';
277
+ throw this._reader.error ? this._reader.error : err;
278
+ });
279
+ }
280
+ /**
281
+ * Reads file using the provided {@link module:upload/filerepository~UploadAdapter}.
282
+ *
283
+ * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `filerepository-upload-wrong-status` when status
284
+ * is different than `idle`.
285
+ * Example usage:
286
+ *
287
+ * ```ts
288
+ * fileLoader.upload()
289
+ * .then( data => { ... } )
290
+ * .catch( e => {
291
+ * if ( e === 'aborted' ) {
292
+ * console.log( 'Uploading aborted.' );
293
+ * } else {
294
+ * console.log( 'Uploading error.', e );
295
+ * }
296
+ * } );
297
+ * ```
298
+ *
299
+ * @returns Returns promise that will be resolved with response data. Promise will be rejected if error
300
+ * occurs or if read process is aborted.
301
+ */ upload() {
302
+ if (this.status != 'idle') {
303
+ /**
304
+ * You cannot call upload if the status is different than idle.
305
+ *
306
+ * @error filerepository-upload-wrong-status
307
+ */ throw new CKEditorError('filerepository-upload-wrong-status', this);
308
+ }
309
+ this.status = 'uploading';
310
+ return this.file.then(()=>this._adapter.upload()).then((data)=>{
311
+ this.uploadResponse = data;
312
+ this.status = 'idle';
313
+ return data;
314
+ }).catch((err)=>{
315
+ if (this.status === 'aborted') {
316
+ throw 'aborted';
317
+ }
318
+ this.status = 'error';
319
+ throw err;
320
+ });
321
+ }
322
+ /**
323
+ * Aborts loading process.
324
+ */ abort() {
325
+ const status = this.status;
326
+ this.status = 'aborted';
327
+ if (!this._filePromiseWrapper.isFulfilled) {
328
+ // Edge case: file loader is aborted before read() is called
329
+ // so it might happen that no one handled the rejection of this promise.
330
+ // See https://github.com/ckeditor/ckeditor5-upload/pull/100
331
+ this._filePromiseWrapper.promise.catch(()=>{});
332
+ this._filePromiseWrapper.rejecter('aborted');
333
+ } else if (status == 'reading') {
334
+ this._reader.abort();
335
+ } else if (status == 'uploading' && this._adapter.abort) {
336
+ this._adapter.abort();
337
+ }
338
+ this._destroy();
339
+ }
340
+ /**
341
+ * Performs cleanup.
342
+ *
343
+ * @internal
344
+ */ _destroy() {
345
+ this._filePromiseWrapper = undefined;
346
+ this._reader = undefined;
347
+ this._adapter = undefined;
348
+ this.uploadResponse = undefined;
349
+ }
350
+ /**
351
+ * Wraps a given file promise into another promise giving additional
352
+ * control (resolving, rejecting, checking if fulfilled) over it.
353
+ *
354
+ * @param filePromise The initial file promise to be wrapped.
355
+ */ _createFilePromiseWrapper(filePromise) {
356
+ const wrapper = {};
357
+ wrapper.promise = new Promise((resolve, reject)=>{
358
+ wrapper.rejecter = reject;
359
+ wrapper.isFulfilled = false;
360
+ filePromise.then((file)=>{
361
+ wrapper.isFulfilled = true;
362
+ resolve(file);
363
+ }).catch((err)=>{
364
+ wrapper.isFulfilled = true;
365
+ reject(err);
366
+ });
367
+ });
368
+ return wrapper;
369
+ }
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
+ }
390
+
391
+ class Base64UploadAdapter extends Plugin {
392
+ /**
393
+ * @inheritDoc
394
+ */ static get requires() {
395
+ return [
396
+ FileRepository
397
+ ];
398
+ }
399
+ /**
400
+ * @inheritDoc
401
+ */ static get pluginName() {
402
+ return 'Base64UploadAdapter';
403
+ }
404
+ /**
405
+ * @inheritDoc
406
+ */ init() {
407
+ this.editor.plugins.get(FileRepository).createUploadAdapter = (loader)=>new Adapter$1(loader);
408
+ }
409
+ }
410
+ /**
411
+ * The upload adapter that converts images inserted into the editor into Base64 strings.
412
+ */ let Adapter$1 = class Adapter {
413
+ /**
414
+ * Starts the upload process.
415
+ *
416
+ * @see module:upload/filerepository~UploadAdapter#upload
417
+ */ upload() {
418
+ return new Promise((resolve, reject)=>{
419
+ const reader = this.reader = new window.FileReader();
420
+ reader.addEventListener('load', ()=>{
421
+ resolve({
422
+ default: reader.result
423
+ });
424
+ });
425
+ reader.addEventListener('error', (err)=>{
426
+ reject(err);
427
+ });
428
+ reader.addEventListener('abort', ()=>{
429
+ reject();
430
+ });
431
+ this.loader.file.then((file)=>{
432
+ reader.readAsDataURL(file);
433
+ });
434
+ });
435
+ }
436
+ /**
437
+ * Aborts the upload process.
438
+ *
439
+ * @see module:upload/filerepository~UploadAdapter#abort
440
+ */ abort() {
441
+ this.reader.abort();
442
+ }
443
+ /**
444
+ * Creates a new adapter instance.
445
+ */ constructor(loader){
446
+ this.loader = loader;
447
+ }
448
+ };
449
+
450
+ class SimpleUploadAdapter extends Plugin {
451
+ /**
452
+ * @inheritDoc
453
+ */ static get requires() {
454
+ return [
455
+ FileRepository
456
+ ];
457
+ }
458
+ /**
459
+ * @inheritDoc
460
+ */ static get pluginName() {
461
+ return 'SimpleUploadAdapter';
462
+ }
463
+ /**
464
+ * @inheritDoc
465
+ */ init() {
466
+ const options = this.editor.config.get('simpleUpload');
467
+ if (!options) {
468
+ return;
469
+ }
470
+ if (!options.uploadUrl) {
471
+ /**
472
+ * The {@link module:upload/uploadconfig~SimpleUploadConfig#uploadUrl `config.simpleUpload.uploadUrl`}
473
+ * configuration required by the {@link module:upload/adapters/simpleuploadadapter~SimpleUploadAdapter `SimpleUploadAdapter`}
474
+ * is missing. Make sure the correct URL is specified for the image upload to work properly.
475
+ *
476
+ * @error simple-upload-adapter-missing-uploadurl
477
+ */ logWarning('simple-upload-adapter-missing-uploadurl');
478
+ return;
479
+ }
480
+ this.editor.plugins.get(FileRepository).createUploadAdapter = (loader)=>{
481
+ return new Adapter(loader, options);
482
+ };
483
+ }
484
+ }
485
+ /**
486
+ * Upload adapter.
487
+ */ class Adapter {
488
+ /**
489
+ * Starts the upload process.
490
+ *
491
+ * @see module:upload/filerepository~UploadAdapter#upload
492
+ */ upload() {
493
+ return this.loader.file.then((file)=>new Promise((resolve, reject)=>{
494
+ this._initRequest();
495
+ this._initListeners(resolve, reject, file);
496
+ this._sendRequest(file);
497
+ }));
498
+ }
499
+ /**
500
+ * Aborts the upload process.
501
+ *
502
+ * @see module:upload/filerepository~UploadAdapter#abort
503
+ */ abort() {
504
+ if (this.xhr) {
505
+ this.xhr.abort();
506
+ }
507
+ }
508
+ /**
509
+ * Initializes the `XMLHttpRequest` object using the URL specified as
510
+ * {@link module:upload/uploadconfig~SimpleUploadConfig#uploadUrl `simpleUpload.uploadUrl`} in the editor's
511
+ * configuration.
512
+ */ _initRequest() {
513
+ const xhr = this.xhr = new XMLHttpRequest();
514
+ xhr.open('POST', this.options.uploadUrl, true);
515
+ xhr.responseType = 'json';
516
+ }
517
+ /**
518
+ * Initializes XMLHttpRequest listeners
519
+ *
520
+ * @param resolve Callback function to be called when the request is successful.
521
+ * @param reject Callback function to be called when the request cannot be completed.
522
+ * @param file Native File object.
523
+ */ _initListeners(resolve, reject, file) {
524
+ const xhr = this.xhr;
525
+ const loader = this.loader;
526
+ const genericErrorText = `Couldn't upload file: ${file.name}.`;
527
+ xhr.addEventListener('error', ()=>reject(genericErrorText));
528
+ xhr.addEventListener('abort', ()=>reject());
529
+ xhr.addEventListener('load', ()=>{
530
+ const response = xhr.response;
531
+ if (!response || response.error) {
532
+ return reject(response && response.error && response.error.message ? response.error.message : genericErrorText);
533
+ }
534
+ const urls = response.url ? {
535
+ default: response.url
536
+ } : response.urls;
537
+ // Resolve with the normalized `urls` property and pass the rest of the response
538
+ // to allow customizing the behavior of features relying on the upload adapters.
539
+ resolve({
540
+ ...response,
541
+ urls
542
+ });
543
+ });
544
+ // Upload progress when it is supported.
545
+ /* istanbul ignore else -- @preserve */ if (xhr.upload) {
546
+ xhr.upload.addEventListener('progress', (evt)=>{
547
+ if (evt.lengthComputable) {
548
+ loader.uploadTotal = evt.total;
549
+ loader.uploaded = evt.loaded;
550
+ }
551
+ });
552
+ }
553
+ }
554
+ /**
555
+ * Prepares the data and sends the request.
556
+ *
557
+ * @param file File instance to be uploaded.
558
+ */ _sendRequest(file) {
559
+ // Set headers if specified.
560
+ const headers = this.options.headers || {};
561
+ // Use the withCredentials flag if specified.
562
+ const withCredentials = this.options.withCredentials || false;
563
+ for (const headerName of Object.keys(headers)){
564
+ this.xhr.setRequestHeader(headerName, headers[headerName]);
565
+ }
566
+ this.xhr.withCredentials = withCredentials;
567
+ // Prepare the form data.
568
+ const data = new FormData();
569
+ data.append('upload', file);
570
+ // Send the request.
571
+ this.xhr.send(data);
572
+ }
573
+ /**
574
+ * Creates a new adapter instance.
575
+ */ constructor(loader, options){
576
+ this.loader = loader;
577
+ this.options = options;
578
+ }
579
+ }
580
+
581
+ export { Base64UploadAdapter, FileRepository, SimpleUploadAdapter };
582
+ //# sourceMappingURL=index.js.map