@vaadin/upload 25.2.7 → 25.3.0-alpha10

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.
@@ -228,11 +228,15 @@ export class UploadManager extends EventTarget {
228
228
  validFiles.push(file);
229
229
  }
230
230
 
231
- this.#setFiles(validFiles);
231
+ this._setFiles(validFiles);
232
232
  }
233
233
 
234
- // Internal setter - bypasses validation for internal use only
235
- #setFiles(value) {
234
+ /**
235
+ * Internal setter - bypasses validation for internal use only.
236
+ * @param {Array<UploadFile>} value
237
+ * @private
238
+ */
239
+ _setFiles(value) {
236
240
  this.#files = value;
237
241
  this.#updateMaxFilesReached();
238
242
  this.#notifyFilesChanged();
@@ -286,7 +290,7 @@ export class UploadManager extends EventTarget {
286
290
  files = [files];
287
291
  }
288
292
  // Only upload files that are managed by this instance and not already complete
289
- files.filter((file) => this.#files.includes(file) && !file.complete).forEach((file) => this.#queueFileUpload(file));
293
+ files.filter((file) => this._isFileManaged(file) && !file.complete).forEach((file) => this._queueFileUpload(file));
290
294
  }
291
295
 
292
296
  /**
@@ -310,7 +314,19 @@ export class UploadManager extends EventTarget {
310
314
  * @param {UploadFile} file - The file to remove
311
315
  */
312
316
  removeFile(file) {
313
- this.#removeFile(file);
317
+ this._removeFile(file);
318
+ }
319
+
320
+ /**
321
+ * Whether the given file is managed by this instance: only managed files
322
+ * are uploaded by `uploadFiles`, and an upload is canceled if its file is
323
+ * no longer managed after the `upload-before` or `upload-request` event.
324
+ * @param {UploadFile} file
325
+ * @returns {boolean}
326
+ * @private
327
+ */
328
+ _isFileManaged(file) {
329
+ return this.#files.includes(file);
314
330
  }
315
331
 
316
332
  // ============ Private methods ============
@@ -376,14 +392,20 @@ export class UploadManager extends EventTarget {
376
392
  file.loaded = 0;
377
393
  file.held = true;
378
394
  file.formDataName = this.formDataName;
379
- this.#setFiles([file, ...this.#files]);
395
+ this._setFiles([file, ...this.#files]);
380
396
 
381
397
  if (!this.noAuto) {
382
- this.#queueFileUpload(file);
398
+ this._queueFileUpload(file);
383
399
  }
384
400
  }
385
401
 
386
- #removeFile(file) {
402
+ /**
403
+ * Remove a file from the list and the upload queue, aborting its active
404
+ * upload if any.
405
+ * @param {UploadFile} file
406
+ * @private
407
+ */
408
+ _removeFile(file) {
387
409
  this.#uploadQueue = this.#uploadQueue.filter((f) => f !== file);
388
410
 
389
411
  // If the file is actively uploading (not held) and not already aborted, abort the XHR
@@ -394,7 +416,7 @@ export class UploadManager extends EventTarget {
394
416
 
395
417
  const fileIndex = this.#files.indexOf(file);
396
418
  if (fileIndex >= 0) {
397
- this.#setFiles(this.#files.filter((f) => f !== file));
419
+ this._setFiles(this.#files.filter((f) => f !== file));
398
420
 
399
421
  this.dispatchEvent(
400
422
  new CustomEvent('file-remove', {
@@ -404,7 +426,13 @@ export class UploadManager extends EventTarget {
404
426
  }
405
427
  }
406
428
 
407
- #queueFileUpload(file) {
429
+ /**
430
+ * Queue an upload of the given file, resetting its upload state. A file
431
+ * that is already uploading or queued is ignored.
432
+ * @param {UploadFile} file
433
+ * @private
434
+ */
435
+ _queueFileUpload(file) {
408
436
  if (file.uploading) {
409
437
  return;
410
438
  }
@@ -414,8 +442,7 @@ export class UploadManager extends EventTarget {
414
442
  return;
415
443
  }
416
444
 
417
- file.loaded = 0;
418
- file.progress = 0;
445
+ this._resetFileProgress(file);
419
446
  file.held = true;
420
447
  file.uploading = file.indeterminate = true;
421
448
  file.complete = file.abort = file.errorKey = false;
@@ -423,10 +450,24 @@ export class UploadManager extends EventTarget {
423
450
  this.#notifyFilesChanged();
424
451
 
425
452
  this.#uploadQueue.push(file);
426
- this.#processUploadQueue();
453
+ this._processUploadQueue();
427
454
  }
428
455
 
429
- #processUploadQueue() {
456
+ /**
457
+ * Reset the progress properties of a file when it is queued for upload.
458
+ * @param {UploadFile} file
459
+ * @private
460
+ */
461
+ _resetFileProgress(file) {
462
+ file.loaded = 0;
463
+ file.progress = 0;
464
+ }
465
+
466
+ /**
467
+ * Start uploads for queued files if there is capacity for them.
468
+ * @private
469
+ */
470
+ _processUploadQueue() {
430
471
  while (this.#uploadQueue.length > 0 && this.#activeUploads < this.maxConcurrentUploads) {
431
472
  const nextFile = this.#uploadQueue.shift();
432
473
  if (nextFile) {
@@ -484,7 +525,7 @@ export class UploadManager extends EventTarget {
484
525
  clearTimeout(stalledId);
485
526
  this.#activeUploads -= 1;
486
527
  this.#cleanupXhr(xhr);
487
- this.#processUploadQueue();
528
+ this._processUploadQueue();
488
529
  };
489
530
 
490
531
  xhr.ontimeout = () => {
@@ -494,7 +535,7 @@ export class UploadManager extends EventTarget {
494
535
  file.status = '';
495
536
 
496
537
  this.#activeUploads -= 1;
497
- this.#processUploadQueue();
538
+ this._processUploadQueue();
498
539
  this.#cleanupXhr(xhr);
499
540
 
500
541
  this.dispatchEvent(new CustomEvent('upload-error', { detail: { file, xhr } }));
@@ -507,7 +548,7 @@ export class UploadManager extends EventTarget {
507
548
  file.indeterminate = file.uploading = false;
508
549
 
509
550
  this.#activeUploads -= 1;
510
- this.#processUploadQueue();
551
+ this._processUploadQueue();
511
552
  this.#cleanupXhr(xhr);
512
553
 
513
554
  // Return early if already handled (abort or timeout)
@@ -540,8 +581,7 @@ export class UploadManager extends EventTarget {
540
581
  const eventName = file.errorKey ? 'upload-error' : 'upload-success';
541
582
  this.dispatchEvent(new CustomEvent(eventName, { detail: { file, xhr } }));
542
583
 
543
- // Clear file.xhr reference to allow garbage collection
544
- file.xhr = null;
584
+ this._clearFileXhr(file);
545
585
 
546
586
  this.#notifyFilesChanged();
547
587
  }
@@ -560,18 +600,18 @@ export class UploadManager extends EventTarget {
560
600
  }),
561
601
  );
562
602
  if (!evt) {
563
- this.#holdFile(file);
603
+ this._holdFile(file);
564
604
  return;
565
605
  }
566
606
 
567
607
  // Check if file was removed during upload-before handler
568
608
  // If file.abort is true, onabort already decremented #activeUploads
569
- if (!this.#files.includes(file)) {
609
+ if (!this._isFileManaged(file)) {
570
610
  if (!file.abort) {
571
611
  this.#activeUploads -= 1;
572
612
  }
573
613
  this.#cleanupXhr(xhr);
574
- this.#processUploadQueue();
614
+ this._processUploadQueue();
575
615
  return;
576
616
  }
577
617
 
@@ -616,18 +656,18 @@ export class UploadManager extends EventTarget {
616
656
  }),
617
657
  );
618
658
  if (!uploadEvt) {
619
- this.#holdFile(file);
659
+ this._holdFile(file);
620
660
  return;
621
661
  }
622
662
 
623
663
  // Check if file was removed during upload-request handler
624
664
  // If file.abort is true, onabort already decremented #activeUploads
625
- if (!this.#files.includes(file)) {
665
+ if (!this._isFileManaged(file)) {
626
666
  if (!file.abort) {
627
667
  this.#activeUploads -= 1;
628
668
  }
629
669
  this.#cleanupXhr(xhr);
630
- this.#processUploadQueue();
670
+ this._processUploadQueue();
631
671
  return;
632
672
  }
633
673
 
@@ -640,7 +680,7 @@ export class UploadManager extends EventTarget {
640
680
  file.errorKey = e.message || 'sendFailed';
641
681
  this.#cleanupXhr(xhr);
642
682
  this.#notifyFilesChanged();
643
- this.#processUploadQueue();
683
+ this._processUploadQueue();
644
684
  }
645
685
  }
646
686
 
@@ -653,15 +693,28 @@ export class UploadManager extends EventTarget {
653
693
  }
654
694
 
655
695
  /**
656
- * Reset file state when upload is prevented.
696
+ * Reset the file state and free its upload slot when its `upload-before`
697
+ * or `upload-request` event is prevented.
698
+ * @param {UploadFile} file
699
+ * @private
657
700
  */
658
- #holdFile(file) {
701
+ _holdFile(file) {
659
702
  this.#activeUploads -= 1;
660
703
  file.uploading = false;
661
704
  file.indeterminate = false;
662
705
  file.held = true;
663
706
  this.#notifyFilesChanged();
664
- this.#processUploadQueue();
707
+ this._processUploadQueue();
708
+ }
709
+
710
+ /**
711
+ * Clear the file's reference to the request once the upload has finished,
712
+ * to allow garbage collection.
713
+ * @param {UploadFile} file
714
+ * @private
715
+ */
716
+ _clearFileXhr(file) {
717
+ file.xhr = null;
665
718
  }
666
719
 
667
720
  /**
@@ -701,12 +754,12 @@ export class UploadManager extends EventTarget {
701
754
  }),
702
755
  );
703
756
  if (evt) {
704
- // Reset uploading flag so #queueFileUpload doesn't early-return
757
+ // Reset uploading flag so _queueFileUpload doesn't early-return
705
758
  // This allows retrying queued files that haven't started yet
706
759
  file.uploading = false;
707
760
  // Remove from queue if present (for queued files being retried)
708
761
  this.#uploadQueue = this.#uploadQueue.filter((f) => f !== file);
709
- this.#queueFileUpload(file);
762
+ this._queueFileUpload(file);
710
763
  }
711
764
  }
712
765
 
@@ -722,7 +775,7 @@ export class UploadManager extends EventTarget {
722
775
  if (file.xhr) {
723
776
  file.xhr.abort();
724
777
  }
725
- this.#removeFile(file);
778
+ this._removeFile(file);
726
779
  }
727
780
  }
728
781
 
@@ -5,27 +5,18 @@
5
5
  */
6
6
  import type { Constructor } from '@open-wc/dedupe-mixin';
7
7
  import type { I18nMixinClass } from '@vaadin/component-base/src/i18n-mixin.js';
8
+ import type { UploadFileListI18n } from './vaadin-upload-file-list-mixin.js';
9
+ import type { UploadFile as UploadManagerFile } from './vaadin-upload-manager.js';
8
10
 
9
- export interface UploadFile extends File {
10
- uploadTarget: string;
11
- elapsed: number;
11
+ export interface UploadFile extends UploadManagerFile {
12
12
  elapsedStr: string;
13
- remaining: number;
14
13
  remainingStr: string;
15
- progress: number;
16
- speed: number;
17
14
  totalStr: string;
18
- loaded: number;
19
15
  loadedStr: string;
20
- status: string;
21
16
  error: string;
22
- abort?: boolean;
23
- complete?: boolean;
24
- held?: boolean;
25
- uploading?: boolean;
26
17
  }
27
18
 
28
- export interface UploadI18n {
19
+ export interface UploadI18n extends UploadFileListI18n {
29
20
  dropFiles?: {
30
21
  one?: string;
31
22
  many?: string;
@@ -34,37 +25,6 @@ export interface UploadI18n {
34
25
  one?: string;
35
26
  many?: string;
36
27
  };
37
- error?: {
38
- tooManyFiles?: string;
39
- fileIsTooBig?: string;
40
- incorrectFileType?: string;
41
- };
42
- uploading?: {
43
- status?: {
44
- connecting?: string;
45
- stalled?: string;
46
- processing?: string;
47
- held?: string;
48
- };
49
- remainingTime?: {
50
- prefix?: string;
51
- unknown?: string;
52
- };
53
- error?: {
54
- serverUnavailable?: string;
55
- unexpectedServerError?: string;
56
- forbidden?: string;
57
- fileTooLarge?: string;
58
- };
59
- };
60
- units?: {
61
- size?: string[];
62
- sizeBase?: number;
63
- };
64
-
65
- formatSize?(bytes: number): string;
66
-
67
- formatTime?(seconds: number, units: number[]): string;
68
28
  }
69
29
 
70
30
  export type UploadMethod = 'POST' | 'PUT';