@vaadin/vaadin-upload 22.0.0-alpha4 → 22.0.0-alpha8

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.
@@ -3,997 +3,11 @@
3
3
  * Copyright (c) 2021 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { PolymerElement, html } from '@polymer/polymer/polymer-element.js';
7
- import { resetMouseCanceller } from '@polymer/polymer/lib/utils/gestures.js';
8
- import '@polymer/polymer/lib/elements/dom-repeat.js';
9
- import { ElementMixin } from '@vaadin/vaadin-element-mixin/vaadin-element-mixin.js';
10
- import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
11
- import '@vaadin/button/src/vaadin-button.js';
12
- import './vaadin-upload-icons.js';
13
- import './vaadin-upload-file.js';
6
+ import { Upload } from '@vaadin/upload/src/vaadin-upload.js';
14
7
 
15
8
  /**
16
- * `<vaadin-upload>` is a Web Component for uploading multiple files with drag and drop support.
17
- *
18
- * Example:
19
- *
20
- * ```
21
- * <vaadin-upload></vaadin-upload>
22
- * ```
23
- *
24
- * ### Styling
25
- *
26
- * The following shadow DOM parts are available for styling:
27
- *
28
- * Part name | Description
29
- * ---|---
30
- * `primary-buttons` | Upload container
31
- * `upload-button` | Upload button
32
- * `drop-label` | Label for drop indicator
33
- * `drop-label-icon` | Icon for drop indicator
34
- * `file-list` | File list container
35
- *
36
- * The following state attributes are available for styling:
37
- *
38
- * Attribute | Description | Part name
39
- * ---|---|---
40
- * `nodrop` | Set when drag and drop is disabled (e. g., on touch devices) | `:host`
41
- * `dragover` | A file is being dragged over the element | `:host`
42
- * `dragover-valid` | A dragged file is valid with `maxFiles` and `accept` criteria | `:host`
43
- *
44
- * See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
45
- *
46
- * @fires {CustomEvent} file-reject - Fired when a file cannot be added to the queue due to a constrain.
47
- * @fires {CustomEvent} files-changed - Fired when the `files` property changes.
48
- * @fires {CustomEvent} max-files-reached-changed - Fired when the `maxFilesReached` property changes.
49
- * @fires {CustomEvent} upload-before - Fired before the XHR is opened.
50
- * @fires {CustomEvent} upload-start - Fired when the XHR is sent.
51
- * @fires {CustomEvent} upload-progress - Fired as many times as the progress is updated.
52
- * @fires {CustomEvent} upload-success - Fired in case the upload process succeeded.
53
- * @fires {CustomEvent} upload-error - Fired in case the upload process failed.
54
- * @fires {CustomEvent} upload-request - Fired when the XHR has been opened but not sent yet.
55
- * @fires {CustomEvent} upload-response - Fired when on the server response before analyzing it.
56
- * @fires {CustomEvent} upload-retry - Fired when retry upload is requested.
57
- * @fires {CustomEvent} upload-abort - Fired when upload abort is requested.
58
- *
59
- * @extends HTMLElement
60
- * @mixes ThemableMixin
61
- * @mixes ElementMixin
9
+ * @deprecated Import `Upload` from `@vaadin/upload` instead.
62
10
  */
63
- class UploadElement extends ElementMixin(ThemableMixin(PolymerElement)) {
64
- static get template() {
65
- return html`
66
- <style>
67
- :host {
68
- display: block;
69
- position: relative;
70
- }
11
+ export const UploadElement = Upload;
71
12
 
72
- :host([hidden]) {
73
- display: none !important;
74
- }
75
-
76
- [hidden] {
77
- display: none !important;
78
- }
79
-
80
- [part='file-list'] {
81
- padding: 0;
82
- margin: 0;
83
- }
84
- </style>
85
-
86
- <div part="primary-buttons">
87
- <div id="addFiles" on-touchend="_onAddFilesTouchEnd" on-click="_onAddFilesClick">
88
- <slot name="add-button">
89
- <vaadin-button part="upload-button" id="addButton" disabled="[[maxFilesReached]]">
90
- [[_i18nPlural(maxFiles, i18n.addFiles, i18n.addFiles.*)]]
91
- </vaadin-button>
92
- </slot>
93
- </div>
94
- <div part="drop-label" hidden$="[[nodrop]]" id="dropLabelContainer">
95
- <slot name="drop-label-icon">
96
- <div part="drop-label-icon"></div>
97
- </slot>
98
- <slot name="drop-label" id="dropLabel"> [[_i18nPlural(maxFiles, i18n.dropFiles, i18n.dropFiles.*)]] </slot>
99
- </div>
100
- </div>
101
- <slot name="file-list">
102
- <ul id="fileList" part="file-list">
103
- <template is="dom-repeat" items="[[files]]" as="file">
104
- <vaadin-upload-file file="[[file]]" i18n="[[i18n]]"></vaadin-upload-file>
105
- </template>
106
- </ul>
107
- </slot>
108
- <slot></slot>
109
- <input
110
- type="file"
111
- id="fileInput"
112
- hidden
113
- on-change="_onFileInputChange"
114
- accept$="{{accept}}"
115
- multiple$="[[_isMultiple(maxFiles)]]"
116
- capture$="[[capture]]"
117
- />
118
- `;
119
- }
120
-
121
- static get is() {
122
- return 'vaadin-upload';
123
- }
124
-
125
- static get properties() {
126
- return {
127
- /**
128
- * Define whether the element supports dropping files on it for uploading.
129
- * By default it's enabled in desktop and disabled in touch devices
130
- * because mobile devices do not support drag events in general. Setting
131
- * it false means that drop is enabled even in touch-devices, and true
132
- * disables drop in all devices.
133
- *
134
- * @type {boolean}
135
- * @default true in touch-devices, false otherwise.
136
- */
137
- nodrop: {
138
- type: Boolean,
139
- reflectToAttribute: true,
140
- value: function () {
141
- try {
142
- return !!document.createEvent('TouchEvent');
143
- } catch (e) {
144
- return false;
145
- }
146
- }
147
- },
148
-
149
- /**
150
- * The server URL. The default value is an empty string, which means that
151
- * _window.location_ will be used.
152
- * @type {string}
153
- */
154
- target: {
155
- type: String,
156
- value: ''
157
- },
158
-
159
- /**
160
- * HTTP Method used to send the files. Only POST and PUT are allowed.
161
- * @type {!UploadMethod}
162
- */
163
- method: {
164
- type: String,
165
- value: 'POST'
166
- },
167
-
168
- /**
169
- * Key-Value map to send to the server. If you set this property as an
170
- * attribute, use a valid JSON string, for example:
171
- * ```
172
- * <vaadin-upload headers='{"X-Foo": "Bar"}'></vaadin-upload>
173
- * ```
174
- * @type {object | string}
175
- */
176
- headers: {
177
- type: Object,
178
- value: {}
179
- },
180
-
181
- /**
182
- * Max time in milliseconds for the entire upload process, if exceeded the
183
- * request will be aborted. Zero means that there is no timeout.
184
- * @type {number}
185
- */
186
- timeout: {
187
- type: Number,
188
- value: 0
189
- },
190
-
191
- /** @private */
192
- _dragover: {
193
- type: Boolean,
194
- value: false,
195
- observer: '_dragoverChanged'
196
- },
197
-
198
- /**
199
- * The array of files being processed, or already uploaded.
200
- *
201
- * Each element is a [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File)
202
- * object with a number of extra properties to track the upload process:
203
- * - `uploadTarget`: The target URL used to upload this file.
204
- * - `elapsed`: Elapsed time since the upload started.
205
- * - `elapsedStr`: Human-readable elapsed time.
206
- * - `remaining`: Number of seconds remaining for the upload to finish.
207
- * - `remainingStr`: Human-readable remaining time for the upload to finish.
208
- * - `progress`: Percentage of the file already uploaded.
209
- * - `speed`: Upload speed in kB/s.
210
- * - `size`: File size in bytes.
211
- * - `totalStr`: Human-readable total size of the file.
212
- * - `loaded`: Bytes transferred so far.
213
- * - `loadedStr`: Human-readable uploaded size at the moment.
214
- * - `status`: Status of the upload process.
215
- * - `error`: Error message in case the upload failed.
216
- * - `abort`: True if the file was canceled by the user.
217
- * - `complete`: True when the file was transferred to the server.
218
- * - `uploading`: True while transferring data to the server.
219
- * @type {!Array<!UploadFile>}
220
- */
221
- files: {
222
- type: Array,
223
- notify: true,
224
- value: function () {
225
- return [];
226
- }
227
- },
228
-
229
- /**
230
- * Limit of files to upload, by default it is unlimited. If the value is
231
- * set to one, native file browser will prevent selecting multiple files.
232
- * @attr {number} max-files
233
- * @type {number}
234
- */
235
- maxFiles: {
236
- type: Number,
237
- value: Infinity
238
- },
239
-
240
- /**
241
- * Specifies if the maximum number of files have been uploaded
242
- * @attr {boolean} max-files-reached
243
- * @type {boolean}
244
- */
245
- maxFilesReached: {
246
- type: Boolean,
247
- value: false,
248
- notify: true,
249
- readOnly: true,
250
- computed: '_maxFilesAdded(maxFiles, files.length)'
251
- },
252
-
253
- /**
254
- * Specifies the types of files that the server accepts.
255
- * Syntax: a comma-separated list of MIME type patterns (wildcards are
256
- * allowed) or file extensions.
257
- * Notice that MIME types are widely supported, while file extensions
258
- * are only implemented in certain browsers, so avoid using it.
259
- * Example: accept="video/*,image/tiff" or accept=".pdf,audio/mp3"
260
- * @type {string}
261
- */
262
- accept: {
263
- type: String,
264
- value: ''
265
- },
266
-
267
- /**
268
- * Specifies the maximum file size in bytes allowed to upload.
269
- * Notice that it is a client-side constraint, which will be checked before
270
- * sending the request. Obviously you need to do the same validation in
271
- * the server-side and be sure that they are aligned.
272
- * @attr {number} max-file-size
273
- * @type {number}
274
- */
275
- maxFileSize: {
276
- type: Number,
277
- value: Infinity
278
- },
279
-
280
- /**
281
- * Specifies if the dragover is validated with maxFiles and
282
- * accept properties.
283
- * @private
284
- */
285
- _dragoverValid: {
286
- type: Boolean,
287
- value: false,
288
- observer: '_dragoverValidChanged'
289
- },
290
-
291
- /**
292
- * Specifies the 'name' property at Content-Disposition
293
- * @attr {string} form-data-name
294
- * @type {string}
295
- */
296
- formDataName: {
297
- type: String,
298
- value: 'file'
299
- },
300
-
301
- /**
302
- * Prevents upload(s) from immediately uploading upon adding file(s).
303
- * When set, you must manually trigger uploads using the `uploadFiles` method
304
- * @attr {boolean} no-auto
305
- * @type {boolean}
306
- */
307
- noAuto: {
308
- type: Boolean,
309
- value: false
310
- },
311
-
312
- /**
313
- * Set the withCredentials flag on the request.
314
- * @attr {boolean} with-credentials
315
- * @type {boolean}
316
- */
317
- withCredentials: {
318
- type: Boolean,
319
- value: false
320
- },
321
-
322
- /**
323
- * Pass-through to input's capture attribute. Allows user to trigger device inputs
324
- * such as camera or microphone immediately.
325
- */
326
- capture: String,
327
-
328
- /**
329
- * The object used to localize this component.
330
- * For changing the default localization, change the entire
331
- * _i18n_ object or just the property you want to modify.
332
- *
333
- * The object has the following JSON structure and default values:
334
- *
335
- * ```
336
- * {
337
- * dropFiles: {
338
- * one: 'Drop file here',
339
- * many: 'Drop files here'
340
- * },
341
- * addFiles: {
342
- * one: 'Select File...',
343
- * many: 'Upload Files...'
344
- * },
345
- * cancel: 'Cancel',
346
- * error: {
347
- * tooManyFiles: 'Too Many Files.',
348
- * fileIsTooBig: 'File is Too Big.',
349
- * incorrectFileType: 'Incorrect File Type.'
350
- * },
351
- * uploading: {
352
- * status: {
353
- * connecting: 'Connecting...',
354
- * stalled: 'Stalled',
355
- * processing: 'Processing File...',
356
- * held: 'Queued'
357
- * },
358
- * remainingTime: {
359
- * prefix: 'remaining time: ',
360
- * unknown: 'unknown remaining time'
361
- * },
362
- * error: {
363
- * serverUnavailable: 'Server Unavailable',
364
- * unexpectedServerError: 'Unexpected Server Error',
365
- * forbidden: 'Forbidden'
366
- * }
367
- * },
368
- * file: {
369
- * retry: 'Retry',
370
- * start: 'Start',
371
- * clear: 'Clear'
372
- * },
373
- * units: {
374
- * size: ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
375
- * sizeBase: 1000
376
- * },
377
- * formatSize: function(bytes) {
378
- * // returns the size followed by the best suitable unit
379
- * },
380
- * formatTime: function(seconds, [secs, mins, hours]) {
381
- * // returns a 'HH:MM:SS' string
382
- * }
383
- * }
384
- * ```
385
- *
386
- * @type {!UploadI18n}
387
- * @default {English}
388
- */
389
- i18n: {
390
- type: Object,
391
- value: function () {
392
- return {
393
- dropFiles: {
394
- one: 'Drop file here',
395
- many: 'Drop files here'
396
- },
397
- addFiles: {
398
- one: 'Upload File...',
399
- many: 'Upload Files...'
400
- },
401
- cancel: 'Cancel',
402
- error: {
403
- tooManyFiles: 'Too Many Files.',
404
- fileIsTooBig: 'File is Too Big.',
405
- incorrectFileType: 'Incorrect File Type.'
406
- },
407
- uploading: {
408
- status: {
409
- connecting: 'Connecting...',
410
- stalled: 'Stalled',
411
- processing: 'Processing File...',
412
- held: 'Queued'
413
- },
414
- remainingTime: {
415
- prefix: 'remaining time: ',
416
- unknown: 'unknown remaining time'
417
- },
418
- error: {
419
- serverUnavailable: 'Upload failed, please try again later',
420
- unexpectedServerError: 'Upload failed due to server error',
421
- forbidden: 'Upload forbidden'
422
- }
423
- },
424
- file: {
425
- retry: 'Retry',
426
- start: 'Start',
427
- clear: 'Clear'
428
- },
429
- units: {
430
- size: ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
431
- }
432
- };
433
- }
434
- }
435
- };
436
- }
437
-
438
- /** @protected */
439
- ready() {
440
- super.ready();
441
- this.addEventListener('dragover', this._onDragover.bind(this));
442
- this.addEventListener('dragleave', this._onDragleave.bind(this));
443
- this.addEventListener('drop', this._onDrop.bind(this));
444
- this.addEventListener('file-retry', this._onFileRetry.bind(this));
445
- this.addEventListener('file-abort', this._onFileAbort.bind(this));
446
- this.addEventListener('file-remove', this._onFileRemove.bind(this));
447
- this.addEventListener('file-start', this._onFileStart.bind(this));
448
- }
449
-
450
- /** @private */
451
- _formatSize(bytes) {
452
- if (typeof this.i18n.formatSize === 'function') {
453
- return this.i18n.formatSize(bytes);
454
- }
455
-
456
- // https://wiki.ubuntu.com/UnitsPolicy
457
- const base = this.i18n.units.sizeBase || 1000;
458
- const unit = ~~(Math.log(bytes) / Math.log(base));
459
- const dec = Math.max(0, Math.min(3, unit - 1));
460
- const size = parseFloat((bytes / Math.pow(base, unit)).toFixed(dec));
461
- return size + ' ' + this.i18n.units.size[unit];
462
- }
463
-
464
- /** @private */
465
- _splitTimeByUnits(time) {
466
- const unitSizes = [60, 60, 24, Infinity];
467
- const timeValues = [0];
468
-
469
- for (var i = 0; i < unitSizes.length && time > 0; i++) {
470
- timeValues[i] = time % unitSizes[i];
471
- time = Math.floor(time / unitSizes[i]);
472
- }
473
-
474
- return timeValues;
475
- }
476
-
477
- /** @private */
478
- _formatTime(seconds, split) {
479
- if (typeof this.i18n.formatTime === 'function') {
480
- return this.i18n.formatTime(seconds, split);
481
- }
482
-
483
- // Fill HH:MM:SS with leading zeros
484
- while (split.length < 3) {
485
- split.push(0);
486
- }
487
-
488
- return split
489
- .reverse()
490
- .map((number) => {
491
- return (number < 10 ? '0' : '') + number;
492
- })
493
- .join(':');
494
- }
495
-
496
- /** @private */
497
- _formatFileProgress(file) {
498
- return (
499
- file.totalStr +
500
- ': ' +
501
- file.progress +
502
- '% (' +
503
- (file.loaded > 0
504
- ? this.i18n.uploading.remainingTime.prefix + file.remainingStr
505
- : this.i18n.uploading.remainingTime.unknown) +
506
- ')'
507
- );
508
- }
509
-
510
- /** @private */
511
- _maxFilesAdded(maxFiles, numFiles) {
512
- return maxFiles >= 0 && numFiles >= maxFiles;
513
- }
514
-
515
- /** @private */
516
- _onDragover(event) {
517
- event.preventDefault();
518
- if (!this.nodrop && !this._dragover) {
519
- this._dragoverValid = !this.maxFilesReached;
520
- this._dragover = true;
521
- }
522
- event.dataTransfer.dropEffect = !this._dragoverValid || this.nodrop ? 'none' : 'copy';
523
- }
524
-
525
- /** @private */
526
- _onDragleave(event) {
527
- event.preventDefault();
528
- if (this._dragover && !this.nodrop) {
529
- this._dragover = this._dragoverValid = false;
530
- }
531
- }
532
-
533
- /** @private */
534
- _onDrop(event) {
535
- if (!this.nodrop) {
536
- event.preventDefault();
537
- this._dragover = this._dragoverValid = false;
538
- this._addFiles(event.dataTransfer.files);
539
- }
540
- }
541
-
542
- /** @private */
543
- _createXhr() {
544
- return new XMLHttpRequest();
545
- }
546
-
547
- /** @private */
548
- _configureXhr(xhr) {
549
- if (typeof this.headers == 'string') {
550
- try {
551
- this.headers = JSON.parse(this.headers);
552
- } catch (e) {
553
- this.headers = undefined;
554
- }
555
- }
556
- for (var key in this.headers) {
557
- xhr.setRequestHeader(key, this.headers[key]);
558
- }
559
- if (this.timeout) {
560
- xhr.timeout = this.timeout;
561
- }
562
- xhr.withCredentials = this.withCredentials;
563
- }
564
-
565
- /** @private */
566
- _setStatus(file, total, loaded, elapsed) {
567
- file.elapsed = elapsed;
568
- file.elapsedStr = this._formatTime(file.elapsed, this._splitTimeByUnits(file.elapsed));
569
- file.remaining = Math.ceil(elapsed * (total / loaded - 1));
570
- file.remainingStr = this._formatTime(file.remaining, this._splitTimeByUnits(file.remaining));
571
- file.speed = ~~(total / elapsed / 1024);
572
- file.totalStr = this._formatSize(total);
573
- file.loadedStr = this._formatSize(loaded);
574
- file.status = this._formatFileProgress(file);
575
- }
576
-
577
- /**
578
- * Triggers the upload of any files that are not completed
579
- *
580
- * @param {!UploadFile | !Array<!UploadFile>=} files - Files being uploaded. Defaults to all outstanding files
581
- */
582
- uploadFiles(files) {
583
- if (files && !Array.isArray(files)) {
584
- files = [files];
585
- }
586
- files = files || this.files;
587
- files = files.filter((file) => !file.complete);
588
- Array.prototype.forEach.call(files, this._uploadFile.bind(this));
589
- }
590
-
591
- /** @private */
592
- _uploadFile(file) {
593
- if (file.uploading) {
594
- return;
595
- }
596
-
597
- const ini = Date.now();
598
- const xhr = (file.xhr = this._createXhr());
599
-
600
- let stalledId, last;
601
- // onprogress is called always after onreadystatechange
602
- xhr.upload.onprogress = (e) => {
603
- clearTimeout(stalledId);
604
-
605
- last = Date.now();
606
- const elapsed = (last - ini) / 1000;
607
- const loaded = e.loaded,
608
- total = e.total,
609
- progress = ~~((loaded / total) * 100);
610
- file.loaded = loaded;
611
- file.progress = progress;
612
- file.indeterminate = loaded <= 0 || loaded >= total;
613
-
614
- if (file.error) {
615
- file.indeterminate = file.status = undefined;
616
- } else if (!file.abort) {
617
- if (progress < 100) {
618
- this._setStatus(file, total, loaded, elapsed);
619
- stalledId = setTimeout(() => {
620
- file.status = this.i18n.uploading.status.stalled;
621
- this._notifyFileChanges(file);
622
- }, 2000);
623
- } else {
624
- file.loadedStr = file.totalStr;
625
- file.status = this.i18n.uploading.status.processing;
626
- }
627
- }
628
-
629
- this._notifyFileChanges(file);
630
- this.dispatchEvent(new CustomEvent('upload-progress', { detail: { file, xhr } }));
631
- };
632
-
633
- // More reliable than xhr.onload
634
- xhr.onreadystatechange = () => {
635
- if (xhr.readyState == 4) {
636
- clearTimeout(stalledId);
637
- file.indeterminate = file.uploading = false;
638
- if (file.abort) {
639
- this._notifyFileChanges(file);
640
- return;
641
- }
642
- file.status = '';
643
- // Custom listener can modify the default behavior either
644
- // preventing default, changing the xhr, or setting the file error
645
- const evt = this.dispatchEvent(
646
- new CustomEvent('upload-response', {
647
- detail: { file, xhr },
648
- cancelable: true
649
- })
650
- );
651
-
652
- if (!evt) {
653
- return;
654
- }
655
- if (xhr.status === 0) {
656
- file.error = this.i18n.uploading.error.serverUnavailable;
657
- } else if (xhr.status >= 500) {
658
- file.error = this.i18n.uploading.error.unexpectedServerError;
659
- } else if (xhr.status >= 400) {
660
- file.error = this.i18n.uploading.error.forbidden;
661
- }
662
-
663
- file.complete = !file.error;
664
- this.dispatchEvent(
665
- new CustomEvent(`upload-${file.error ? 'error' : 'success'}`, {
666
- detail: { file, xhr }
667
- })
668
- );
669
- this._notifyFileChanges(file);
670
- }
671
- };
672
-
673
- const formData = new FormData();
674
-
675
- file.uploadTarget = file.uploadTarget || this.target || '';
676
- file.formDataName = this.formDataName;
677
-
678
- const evt = this.dispatchEvent(
679
- new CustomEvent('upload-before', {
680
- detail: { file, xhr },
681
- cancelable: true
682
- })
683
- );
684
- if (!evt) {
685
- return;
686
- }
687
-
688
- formData.append(file.formDataName, file, file.name);
689
-
690
- xhr.open(this.method, file.uploadTarget, true);
691
- this._configureXhr(xhr);
692
-
693
- file.status = this.i18n.uploading.status.connecting;
694
- file.uploading = file.indeterminate = true;
695
- file.complete = file.abort = file.error = file.held = false;
696
-
697
- xhr.upload.onloadstart = () => {
698
- this.dispatchEvent(
699
- new CustomEvent('upload-start', {
700
- detail: { file, xhr }
701
- })
702
- );
703
- this._notifyFileChanges(file);
704
- };
705
-
706
- // Custom listener could modify the xhr just before sending it
707
- // preventing default
708
- const uploadEvt = this.dispatchEvent(
709
- new CustomEvent('upload-request', {
710
- detail: { file, xhr, formData },
711
- cancelable: true
712
- })
713
- );
714
- if (uploadEvt) {
715
- xhr.send(formData);
716
- }
717
- }
718
-
719
- /** @private */
720
- _retryFileUpload(file) {
721
- const evt = this.dispatchEvent(
722
- new CustomEvent('upload-retry', {
723
- detail: { file, xhr: file.xhr },
724
- cancelable: true
725
- })
726
- );
727
- if (evt) {
728
- this._uploadFile(file);
729
- }
730
- }
731
-
732
- /** @private */
733
- _abortFileUpload(file) {
734
- const evt = this.dispatchEvent(
735
- new CustomEvent('upload-abort', {
736
- detail: { file, xhr: file.xhr },
737
- cancelable: true
738
- })
739
- );
740
- if (evt) {
741
- file.abort = true;
742
- if (file.xhr) {
743
- file.xhr.abort();
744
- }
745
- this._notifyFileChanges(file);
746
- }
747
- }
748
-
749
- /** @private */
750
- _notifyFileChanges(file) {
751
- var p = 'files.' + this.files.indexOf(file) + '.';
752
- for (let i in file) {
753
- // eslint-disable-next-line no-prototype-builtins
754
- if (file.hasOwnProperty(i)) {
755
- this.notifyPath(p + i, file[i]);
756
- }
757
- }
758
- }
759
-
760
- /** @private */
761
- _addFiles(files) {
762
- Array.prototype.forEach.call(files, this._addFile.bind(this));
763
- }
764
-
765
- /**
766
- * Add the file for uploading. Called internally for each file after picking files from dialog or dropping files.
767
- *
768
- * @param {!UploadFile} file File being added
769
- * @protected
770
- */
771
- _addFile(file) {
772
- if (this.maxFilesReached) {
773
- this.dispatchEvent(
774
- new CustomEvent('file-reject', {
775
- detail: { file, error: this.i18n.error.tooManyFiles }
776
- })
777
- );
778
- return;
779
- }
780
- if (this.maxFileSize >= 0 && file.size > this.maxFileSize) {
781
- this.dispatchEvent(
782
- new CustomEvent('file-reject', {
783
- detail: { file, error: this.i18n.error.fileIsTooBig }
784
- })
785
- );
786
- return;
787
- }
788
- const fileExt = file.name.match(/\.[^.]*$|$/)[0];
789
- const re = new RegExp('^(' + this.accept.replace(/[, ]+/g, '|').replace(/\/\*/g, '/.*') + ')$', 'i');
790
- if (this.accept && !(re.test(file.type) || re.test(fileExt))) {
791
- this.dispatchEvent(
792
- new CustomEvent('file-reject', {
793
- detail: { file, error: this.i18n.error.incorrectFileType }
794
- })
795
- );
796
- return;
797
- }
798
- file.loaded = 0;
799
- file.held = true;
800
- file.status = this.i18n.uploading.status.held;
801
- this.files = [file, ...this.files];
802
-
803
- if (!this.noAuto) {
804
- this._uploadFile(file);
805
- }
806
- }
807
-
808
- /**
809
- * Remove file from upload list. Called internally if file upload was canceled.
810
- * @param {!UploadFile} file File to remove
811
- * @protected
812
- */
813
- _removeFile(file) {
814
- if (this.files.indexOf(file) > -1) {
815
- this.files = this.files.filter((i) => i !== file);
816
- }
817
- }
818
-
819
- /** @private */
820
- _onAddFilesTouchEnd(e) {
821
- // Cancel the event to avoid the following click event
822
- e.preventDefault();
823
- // FIXME(platosha): workaround for Polymer Gestures mouseCanceller
824
- // cancelling the following synthetic click. See also:
825
- // https://github.com/Polymer/polymer/issues/5289
826
- this.__resetMouseCanceller();
827
- this._onAddFilesClick();
828
- }
829
-
830
- /** @private */
831
- __resetMouseCanceller() {
832
- resetMouseCanceller();
833
- }
834
-
835
- /** @private */
836
- _onAddFilesClick() {
837
- if (this.maxFilesReached) {
838
- return;
839
- }
840
-
841
- this.$.fileInput.value = '';
842
- this.$.fileInput.click();
843
- }
844
-
845
- /** @private */
846
- _onFileInputChange(event) {
847
- this._addFiles(event.target.files);
848
- }
849
-
850
- /** @private */
851
- _onFileStart(event) {
852
- this._uploadFile(event.detail.file);
853
- }
854
-
855
- /** @private */
856
- _onFileRetry(event) {
857
- this._retryFileUpload(event.detail.file);
858
- }
859
-
860
- /** @private */
861
- _onFileAbort(event) {
862
- this._abortFileUpload(event.detail.file);
863
- }
864
-
865
- /** @private */
866
- _onFileRemove(event) {
867
- this._removeFile(event.detail.file);
868
- }
869
-
870
- /** @private */
871
- _dragoverChanged(dragover) {
872
- dragover ? this.setAttribute('dragover', dragover) : this.removeAttribute('dragover');
873
- }
874
-
875
- /** @private */
876
- _dragoverValidChanged(dragoverValid) {
877
- dragoverValid ? this.setAttribute('dragover-valid', dragoverValid) : this.removeAttribute('dragover-valid');
878
- }
879
-
880
- /** @private */
881
- _i18nPlural(value, plural) {
882
- return value == 1 ? plural.one : plural.many;
883
- }
884
-
885
- /** @private */
886
- _isMultiple(maxFiles) {
887
- return maxFiles != 1;
888
- }
889
-
890
- /**
891
- * Fired when a file cannot be added to the queue due to a constrain:
892
- * file-size, file-type or maxFiles
893
- *
894
- * @event file-reject
895
- * @param {Object} detail
896
- * @param {Object} detail.file the file added
897
- * @param {string} detail.error the cause
898
- */
899
-
900
- /**
901
- * Fired before the XHR is opened. Could be used for changing the request
902
- * URL. If the default is prevented, then XHR would not be opened.
903
- *
904
- * @event upload-before
905
- * @param {Object} detail
906
- * @param {Object} detail.xhr the xhr
907
- * @param {Object} detail.file the file being uploaded
908
- * @param {Object} detail.file.uploadTarget the upload request URL, initialized with the value of vaadin-upload `target` property
909
- */
910
-
911
- /**
912
- * Fired when the XHR has been opened but not sent yet. Useful for appending
913
- * data keys to the FormData object, for changing some parameters like
914
- * headers, etc. If the event is defaultPrevented, `vaadin-upload` will not
915
- * send the request allowing the user to do something on his own.
916
- *
917
- * @event upload-request
918
- * @param {Object} detail
919
- * @param {Object} detail.xhr the xhr
920
- * @param {Object} detail.file the file being uploaded
921
- * @param {Object} detail.formData the FormData object
922
- */
923
-
924
- /**
925
- * Fired when the XHR is sent.
926
- *
927
- * @event upload-start
928
- * @param {Object} detail
929
- * @param {Object} detail.xhr the xhr
930
- * @param {Object} detail.file the file being uploaded
931
- */
932
-
933
- /**
934
- * Fired as many times as the progress is updated.
935
- *
936
- * @event upload-progress
937
- * @param {Object} detail
938
- * @param {Object} detail.xhr the xhr
939
- * @param {Object} detail.file the file being uploaded with loaded info
940
- */
941
-
942
- /**
943
- * Fired when we have the actual server response, and before the component
944
- * analyses it. It's useful for developers to make the upload fail depending
945
- * on the server response. If the event is defaultPrevented the vaadin-upload
946
- * will return allowing the user to do something on his own like retry the
947
- * upload, etc. since he has full access to the `xhr` and `file` objects.
948
- * Otherwise, if the event is not prevented default `vaadin-upload` continues
949
- * with the normal workflow checking the `xhr.status` and `file.error`
950
- * which also might be modified by the user to force a customized response.
951
- *
952
- * @event upload-response
953
- * @param {Object} detail
954
- * @param {Object} detail.xhr the xhr
955
- * @param {Object} detail.file the file being uploaded
956
- */
957
-
958
- /**
959
- * Fired in case the upload process succeed.
960
- *
961
- * @event upload-success
962
- * @param {Object} detail
963
- * @param {Object} detail.xhr the xhr
964
- * @param {Object} detail.file the file being uploaded with loaded info
965
- */
966
-
967
- /**
968
- * Fired in case the upload process failed.
969
- *
970
- * @event upload-error
971
- * @param {Object} detail
972
- * @param {Object} detail.xhr the xhr
973
- * @param {Object} detail.file the file being uploaded
974
- */
975
-
976
- /**
977
- * Fired when retry upload is requested. If the default is prevented, then
978
- * retry would not be performed.
979
- *
980
- * @event upload-retry
981
- * @param {Object} detail
982
- * @param {Object} detail.xhr the previous upload xhr
983
- * @param {Object} detail.file the file being uploaded
984
- */
985
-
986
- /**
987
- * Fired when retry abort is requested. If the default is prevented, then the
988
- * file upload would not be aborted.
989
- *
990
- * @event upload-abort
991
- * @param {Object} detail
992
- * @param {Object} detail.xhr the xhr
993
- * @param {Object} detail.file the file being uploaded
994
- */
995
- }
996
-
997
- customElements.define(UploadElement.is, UploadElement);
998
-
999
- export { UploadElement };
13
+ export * from '@vaadin/upload/src/vaadin-upload.js';