From 6c97e843fa8c48d13c5d99da18bf1ff5589f126c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20I=C3=9Fbr=C3=BCcker?= Date: Wed, 30 Oct 2024 10:54:40 +0100 Subject: [PATCH 1/5] add directory mode --- packages/upload/src/vaadin-lit-upload.js | 1 + packages/upload/src/vaadin-upload-mixin.js | 15 +++++++++++++++ packages/upload/src/vaadin-upload.js | 1 + 3 files changed, 17 insertions(+) diff --git a/packages/upload/src/vaadin-lit-upload.js b/packages/upload/src/vaadin-lit-upload.js index 12238c72516..af573a682cb 100644 --- a/packages/upload/src/vaadin-lit-upload.js +++ b/packages/upload/src/vaadin-lit-upload.js @@ -67,6 +67,7 @@ class Upload extends UploadMixin(ElementMixin(ThemableMixin(PolylitMixin(LitElem accept="${this.accept}" ?multiple="${this._isMultiple(this.maxFiles)}" capture="${ifDefined(this.capture)}" + ?webkitdirectory="${this.directory}" /> `; } diff --git a/packages/upload/src/vaadin-upload-mixin.js b/packages/upload/src/vaadin-upload-mixin.js index 1c3479c3504..538839b0f28 100644 --- a/packages/upload/src/vaadin-upload-mixin.js +++ b/packages/upload/src/vaadin-upload-mixin.js @@ -262,6 +262,21 @@ export const UploadMixin = (superClass) => */ capture: String, + /** + * In directory mode, the user can select a directory instead of files. + * When selecting a directory, all files in the directory will be added + * to the upload list. Files are still filtered by the `accept` filter, + * and any non-matching files will be rejected. + * + * Note that this only allows selecting a single directory, and that + * selecting files is not supported in this mode. Browsers may request + * a confirmation from the user before allowing to upload a directory. + */ + directory: { + type: Boolean, + value: false, + }, + /** * The object used to localize this component. * For changing the default localization, change the entire diff --git a/packages/upload/src/vaadin-upload.js b/packages/upload/src/vaadin-upload.js index 42fae0c157c..9923c43476e 100644 --- a/packages/upload/src/vaadin-upload.js +++ b/packages/upload/src/vaadin-upload.js @@ -99,6 +99,7 @@ class Upload extends UploadMixin(ElementMixin(ThemableMixin(ControllerMixin(Poly accept$="{{accept}}" multiple$="[[_isMultiple(maxFiles)]]" capture$="[[capture]]" + webkitdirectory$="[[directory]]" /> `; } From f277f82e4677cfb0fa126c780d18a05407825b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20I=C3=9Fbr=C3=BCcker?= Date: Wed, 30 Oct 2024 11:20:38 +0100 Subject: [PATCH 2/5] add i18n prop --- dev/upload.html | 12 ++++++++++++ packages/upload/src/vaadin-upload-mixin.js | 13 ++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/dev/upload.html b/dev/upload.html index 60ceb299df7..cf47355160a 100644 --- a/dev/upload.html +++ b/dev/upload.html @@ -49,6 +49,11 @@ }); upload.files = files; + + const selectionMode = document.querySelector('#selection-mode'); + selectionMode.addEventListener('value-changed', (e) => { + upload.directory = e.detail.value === 'directory'; + }); @@ -62,5 +67,12 @@ + +
+ + + + + diff --git a/packages/upload/src/vaadin-upload-mixin.js b/packages/upload/src/vaadin-upload-mixin.js index 538839b0f28..b4a0fb662a4 100644 --- a/packages/upload/src/vaadin-upload-mixin.js +++ b/packages/upload/src/vaadin-upload-mixin.js @@ -294,6 +294,9 @@ export const UploadMixin = (superClass) => * one: 'Upload File...', * many: 'Upload Files...' * }, + * addDirectories: { + * one: 'Upload Directory...', + * }, * error: { * tooManyFiles: 'Too Many Files.', * fileIsTooBig: 'File is Too Big.', @@ -349,6 +352,9 @@ export const UploadMixin = (superClass) => one: 'Upload File...', many: 'Upload Files...', }, + addDirectories: { + one: 'Upload Directory...', + }, error: { tooManyFiles: 'Too Many Files.', fileIsTooBig: 'File is Too Big.', @@ -407,7 +413,7 @@ export const UploadMixin = (superClass) => static get observers() { return [ - '__updateAddButton(_addButton, maxFiles, i18n, maxFilesReached)', + '__updateAddButton(_addButton, maxFiles, i18n, maxFilesReached, directory)', '__updateDropLabel(_dropLabel, maxFiles, i18n)', '__updateFileList(_fileList, files, i18n)', '__updateMaxFilesReached(maxFiles, files)', @@ -533,7 +539,8 @@ export const UploadMixin = (superClass) => // Only update text content for the default button element if (addButton === this._addButtonController.defaultNode) { - addButton.textContent = this._i18nPlural(maxFiles, i18n.addFiles); + const translation = this.directory ? i18n.addDirectories : i18n.addFiles; + addButton.textContent = this._i18nPlural(maxFiles, translation); } } } @@ -993,7 +1000,7 @@ export const UploadMixin = (superClass) => /** @private */ _i18nPlural(value, plural) { - return value === 1 ? plural.one : plural.many; + return (value === 1 ? plural.one : plural.many) || plural.one; } /** @protected */ From 65e41c489b8c27ad15aa6da4500dc77fff9267a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20I=C3=9Fbr=C3=BCcker?= Date: Wed, 30 Oct 2024 15:04:14 +0100 Subject: [PATCH 3/5] add tests --- packages/upload/test/upload.common.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/upload/test/upload.common.js b/packages/upload/test/upload.common.js index 835e1557f4f..9b6e4baf6d3 100644 --- a/packages/upload/test/upload.common.js +++ b/packages/upload/test/upload.common.js @@ -160,6 +160,7 @@ describe('upload', () => { function MockFormData() { this.data = []; } + MockFormData.prototype.append = function (name, value, filename) { this.data.push({ name, value, filename }); }; @@ -539,4 +540,28 @@ describe('upload', () => { expect(upload.files.length).to.equal(0); }); }); + + describe('Directory mode', () => { + it('should not set webkitdirectory attribute on the file input by default', () => { + expect(upload.$.fileInput.hasAttribute('webkitdirectory')).to.be.false; + }); + + it('should set webkitdirectory attribute on the file input when directory mode is enabled', async () => { + upload.directory = true; + await nextRender(upload); + + expect(upload.$.fileInput.hasAttribute('webkitdirectory')).to.be.true; + }); + + it('should use add files translation when not using directory mode', () => { + expect(upload.querySelector('[slot="add-button"]').textContent).to.be.equal(upload.i18n.addFiles.many); + }); + + it('should use add directories translation when using directory mode', async () => { + upload.directory = true; + await nextRender(upload); + + expect(upload.querySelector('[slot="add-button"]').textContent).to.be.equal(upload.i18n.addDirectories.one); + }); + }); }); From 918375f3d55617dc476c1cda831d88c988974c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20I=C3=9Fbr=C3=BCcker?= Date: Thu, 31 Oct 2024 08:37:34 +0100 Subject: [PATCH 4/5] cleanup --- packages/upload/src/vaadin-upload-mixin.d.ts | 20 ++++++++++++++++++++ packages/upload/src/vaadin-upload-mixin.js | 11 ++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/upload/src/vaadin-upload-mixin.d.ts b/packages/upload/src/vaadin-upload-mixin.d.ts index a789e2ac2a1..7bfafb221a5 100644 --- a/packages/upload/src/vaadin-upload-mixin.d.ts +++ b/packages/upload/src/vaadin-upload-mixin.d.ts @@ -33,6 +33,9 @@ export interface UploadI18n { one: string; many: string; }; + addDirectories: { + one: string; + }; error: { tooManyFiles: string; fileIsTooBig: string; @@ -184,6 +187,20 @@ export declare class UploadMixinClass { */ capture: string | null | undefined; + /** + * In directory mode, the user can select a directory instead of files. + * When selecting a directory, all files in the directory will be added + * to the upload list. Files are still filtered by the `accept` filter, + * and any non-matching files will be rejected. + * + * Note that this only allows selecting a single directory, and that + * selecting files is not supported in this mode. Browsers may request + * a confirmation from the user before allowing to upload a directory. + * In this mode it is still possible to add a combination of files and + * directories using drag and drop. + */ + directory: string; + /** * The object used to localize this component. * For changing the default localization, change the entire @@ -201,6 +218,9 @@ export declare class UploadMixinClass { * one: 'Upload File...', * many: 'Upload Files...' * }, + * addDirectories: { + * one: 'Upload Directory...', + * }, * error: { * tooManyFiles: 'Too Many Files.', * fileIsTooBig: 'File is Too Big.', diff --git a/packages/upload/src/vaadin-upload-mixin.js b/packages/upload/src/vaadin-upload-mixin.js index b4a0fb662a4..0a02f2fc487 100644 --- a/packages/upload/src/vaadin-upload-mixin.js +++ b/packages/upload/src/vaadin-upload-mixin.js @@ -271,6 +271,8 @@ export const UploadMixin = (superClass) => * Note that this only allows selecting a single directory, and that * selecting files is not supported in this mode. Browsers may request * a confirmation from the user before allowing to upload a directory. + * In this mode it is still possible to add a combination of files and + * directories using drag and drop. */ directory: { type: Boolean, @@ -539,8 +541,11 @@ export const UploadMixin = (superClass) => // Only update text content for the default button element if (addButton === this._addButtonController.defaultNode) { - const translation = this.directory ? i18n.addDirectories : i18n.addFiles; - addButton.textContent = this._i18nPlural(maxFiles, translation); + if (this.directory) { + addButton.textContent = i18n.addDirectories.one; + } else { + addButton.textContent = this._i18nPlural(maxFiles, i18n.addFiles); + } } } } @@ -1000,7 +1005,7 @@ export const UploadMixin = (superClass) => /** @private */ _i18nPlural(value, plural) { - return (value === 1 ? plural.one : plural.many) || plural.one; + return value === 1 ? plural.one : plural.many; } /** @protected */ From 5e9e27b64beedde6e43714ab2b0f9ab464739fa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20I=C3=9Fbr=C3=BCcker?= Date: Thu, 31 Oct 2024 10:45:09 +0100 Subject: [PATCH 5/5] fix TS type --- packages/upload/src/vaadin-upload-mixin.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/upload/src/vaadin-upload-mixin.d.ts b/packages/upload/src/vaadin-upload-mixin.d.ts index 7bfafb221a5..9a704d09ace 100644 --- a/packages/upload/src/vaadin-upload-mixin.d.ts +++ b/packages/upload/src/vaadin-upload-mixin.d.ts @@ -199,7 +199,7 @@ export declare class UploadMixinClass { * In this mode it is still possible to add a combination of files and * directories using drag and drop. */ - directory: string; + directory: boolean; /** * The object used to localize this component.