@ckeditor/ckeditor5-upload 41.3.1 → 41.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) 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/ar.umd.js +11 -0
  9. package/dist/translations/az.d.ts +8 -0
  10. package/dist/translations/az.js +5 -0
  11. package/dist/translations/az.umd.js +11 -0
  12. package/dist/translations/bg.d.ts +8 -0
  13. package/dist/translations/bg.js +5 -0
  14. package/dist/translations/bg.umd.js +11 -0
  15. package/dist/translations/bn.d.ts +8 -0
  16. package/dist/translations/bn.js +5 -0
  17. package/dist/translations/bn.umd.js +11 -0
  18. package/dist/translations/ca.d.ts +8 -0
  19. package/dist/translations/ca.js +5 -0
  20. package/dist/translations/ca.umd.js +11 -0
  21. package/dist/translations/cs.d.ts +8 -0
  22. package/dist/translations/cs.js +5 -0
  23. package/dist/translations/cs.umd.js +11 -0
  24. package/dist/translations/da.d.ts +8 -0
  25. package/dist/translations/da.js +5 -0
  26. package/dist/translations/da.umd.js +11 -0
  27. package/dist/translations/de-ch.d.ts +8 -0
  28. package/dist/translations/de-ch.js +5 -0
  29. package/dist/translations/de-ch.umd.js +11 -0
  30. package/dist/translations/de.d.ts +8 -0
  31. package/dist/translations/de.js +5 -0
  32. package/dist/translations/de.umd.js +11 -0
  33. package/dist/translations/el.d.ts +8 -0
  34. package/dist/translations/el.js +5 -0
  35. package/dist/translations/el.umd.js +11 -0
  36. package/dist/translations/en-au.d.ts +8 -0
  37. package/dist/translations/en-au.js +5 -0
  38. package/dist/translations/en-au.umd.js +11 -0
  39. package/dist/translations/en-gb.d.ts +8 -0
  40. package/dist/translations/en-gb.js +5 -0
  41. package/dist/translations/en-gb.umd.js +11 -0
  42. package/dist/translations/en.d.ts +8 -0
  43. package/dist/translations/en.js +5 -0
  44. package/dist/translations/en.umd.js +11 -0
  45. package/dist/translations/es-co.d.ts +8 -0
  46. package/dist/translations/es-co.js +5 -0
  47. package/dist/translations/es-co.umd.js +11 -0
  48. package/dist/translations/es.d.ts +8 -0
  49. package/dist/translations/es.js +5 -0
  50. package/dist/translations/es.umd.js +11 -0
  51. package/dist/translations/et.d.ts +8 -0
  52. package/dist/translations/et.js +5 -0
  53. package/dist/translations/et.umd.js +11 -0
  54. package/dist/translations/fa.d.ts +8 -0
  55. package/dist/translations/fa.js +5 -0
  56. package/dist/translations/fa.umd.js +11 -0
  57. package/dist/translations/fi.d.ts +8 -0
  58. package/dist/translations/fi.js +5 -0
  59. package/dist/translations/fi.umd.js +11 -0
  60. package/dist/translations/fr.d.ts +8 -0
  61. package/dist/translations/fr.js +5 -0
  62. package/dist/translations/fr.umd.js +11 -0
  63. package/dist/translations/gl.d.ts +8 -0
  64. package/dist/translations/gl.js +5 -0
  65. package/dist/translations/gl.umd.js +11 -0
  66. package/dist/translations/he.d.ts +8 -0
  67. package/dist/translations/he.js +5 -0
  68. package/dist/translations/he.umd.js +11 -0
  69. package/dist/translations/hi.d.ts +8 -0
  70. package/dist/translations/hi.js +5 -0
  71. package/dist/translations/hi.umd.js +11 -0
  72. package/dist/translations/hr.d.ts +8 -0
  73. package/dist/translations/hr.js +5 -0
  74. package/dist/translations/hr.umd.js +11 -0
  75. package/dist/translations/hu.d.ts +8 -0
  76. package/dist/translations/hu.js +5 -0
  77. package/dist/translations/hu.umd.js +11 -0
  78. package/dist/translations/id.d.ts +8 -0
  79. package/dist/translations/id.js +5 -0
  80. package/dist/translations/id.umd.js +11 -0
  81. package/dist/translations/it.d.ts +8 -0
  82. package/dist/translations/it.js +5 -0
  83. package/dist/translations/it.umd.js +11 -0
  84. package/dist/translations/ja.d.ts +8 -0
  85. package/dist/translations/ja.js +5 -0
  86. package/dist/translations/ja.umd.js +11 -0
  87. package/dist/translations/ko.d.ts +8 -0
  88. package/dist/translations/ko.js +5 -0
  89. package/dist/translations/ko.umd.js +11 -0
  90. package/dist/translations/ku.d.ts +8 -0
  91. package/dist/translations/ku.js +5 -0
  92. package/dist/translations/ku.umd.js +11 -0
  93. package/dist/translations/lt.d.ts +8 -0
  94. package/dist/translations/lt.js +5 -0
  95. package/dist/translations/lt.umd.js +11 -0
  96. package/dist/translations/lv.d.ts +8 -0
  97. package/dist/translations/lv.js +5 -0
  98. package/dist/translations/lv.umd.js +11 -0
  99. package/dist/translations/ms.d.ts +8 -0
  100. package/dist/translations/ms.js +5 -0
  101. package/dist/translations/ms.umd.js +11 -0
  102. package/dist/translations/nb.d.ts +8 -0
  103. package/dist/translations/nb.js +5 -0
  104. package/dist/translations/nb.umd.js +11 -0
  105. package/dist/translations/ne.d.ts +8 -0
  106. package/dist/translations/ne.js +5 -0
  107. package/dist/translations/ne.umd.js +11 -0
  108. package/dist/translations/nl.d.ts +8 -0
  109. package/dist/translations/nl.js +5 -0
  110. package/dist/translations/nl.umd.js +11 -0
  111. package/dist/translations/no.d.ts +8 -0
  112. package/dist/translations/no.js +5 -0
  113. package/dist/translations/no.umd.js +11 -0
  114. package/dist/translations/pl.d.ts +8 -0
  115. package/dist/translations/pl.js +5 -0
  116. package/dist/translations/pl.umd.js +11 -0
  117. package/dist/translations/pt-br.d.ts +8 -0
  118. package/dist/translations/pt-br.js +5 -0
  119. package/dist/translations/pt-br.umd.js +11 -0
  120. package/dist/translations/pt.d.ts +8 -0
  121. package/dist/translations/pt.js +5 -0
  122. package/dist/translations/pt.umd.js +11 -0
  123. package/dist/translations/ro.d.ts +8 -0
  124. package/dist/translations/ro.js +5 -0
  125. package/dist/translations/ro.umd.js +11 -0
  126. package/dist/translations/ru.d.ts +8 -0
  127. package/dist/translations/ru.js +5 -0
  128. package/dist/translations/ru.umd.js +11 -0
  129. package/dist/translations/sk.d.ts +8 -0
  130. package/dist/translations/sk.js +5 -0
  131. package/dist/translations/sk.umd.js +11 -0
  132. package/dist/translations/sq.d.ts +8 -0
  133. package/dist/translations/sq.js +5 -0
  134. package/dist/translations/sq.umd.js +11 -0
  135. package/dist/translations/sr-latn.d.ts +8 -0
  136. package/dist/translations/sr-latn.js +5 -0
  137. package/dist/translations/sr-latn.umd.js +11 -0
  138. package/dist/translations/sr.d.ts +8 -0
  139. package/dist/translations/sr.js +5 -0
  140. package/dist/translations/sr.umd.js +11 -0
  141. package/dist/translations/sv.d.ts +8 -0
  142. package/dist/translations/sv.js +5 -0
  143. package/dist/translations/sv.umd.js +11 -0
  144. package/dist/translations/th.d.ts +8 -0
  145. package/dist/translations/th.js +5 -0
  146. package/dist/translations/th.umd.js +11 -0
  147. package/dist/translations/tk.d.ts +8 -0
  148. package/dist/translations/tk.js +5 -0
  149. package/dist/translations/tk.umd.js +11 -0
  150. package/dist/translations/tr.d.ts +8 -0
  151. package/dist/translations/tr.js +5 -0
  152. package/dist/translations/tr.umd.js +11 -0
  153. package/dist/translations/ug.d.ts +8 -0
  154. package/dist/translations/ug.js +5 -0
  155. package/dist/translations/ug.umd.js +11 -0
  156. package/dist/translations/uk.d.ts +8 -0
  157. package/dist/translations/uk.js +5 -0
  158. package/dist/translations/uk.umd.js +11 -0
  159. package/dist/translations/ur.d.ts +8 -0
  160. package/dist/translations/ur.js +5 -0
  161. package/dist/translations/ur.umd.js +11 -0
  162. package/dist/translations/uz.d.ts +8 -0
  163. package/dist/translations/uz.js +5 -0
  164. package/dist/translations/uz.umd.js +11 -0
  165. package/dist/translations/vi.d.ts +8 -0
  166. package/dist/translations/vi.js +5 -0
  167. package/dist/translations/vi.umd.js +11 -0
  168. package/dist/translations/zh-cn.d.ts +8 -0
  169. package/dist/translations/zh-cn.js +5 -0
  170. package/dist/translations/zh-cn.umd.js +11 -0
  171. package/dist/translations/zh.d.ts +8 -0
  172. package/dist/translations/zh.js +5 -0
  173. package/dist/translations/zh.umd.js +11 -0
  174. package/dist/types/adapters/base64uploadadapter.d.ts +37 -0
  175. package/dist/types/adapters/simpleuploadadapter.d.ts +52 -0
  176. package/dist/types/augmentation.d.ts +24 -0
  177. package/dist/types/filereader.d.ts +60 -0
  178. package/dist/types/filerepository.d.ts +346 -0
  179. package/dist/types/index.d.ts +16 -0
  180. package/dist/types/uploadconfig.d.ts +94 -0
  181. 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