diff --git a/packages/file-handling/README.md b/packages/file-handling/README.md index 8ff1f61faed58167cf8352203ae46ec00245eff6..3e75d7407fac487bd9ffb0b28d6714e3065f1e77 100644 --- a/packages/file-handling/README.md +++ b/packages/file-handling/README.md @@ -22,10 +22,9 @@ files from a [Nextcloud](https://nextcloud.com/) instance. - example `<vpu-file-source allowed-mime-types='image/*'></vpu-file-source>` ... images (of all sub types) only - example `<vpu-file-source allowed-mime-types='image/png,text/plain'></vpu-file-source>` ... PNGs or TXTs only - example `<vpu-file-source allowed-mime-types='*/*'></vpu-file-source>` ... all file types (default) -- `enabled-sources` (optional): sets which sources are enabled +- `enabled-sources` (optional, default: `local`): sets which sources are enabled - you can use `local` and `nextcloud` - - default is `local` - - example `<vpu-file-source enabled-sources='local,nextcloud'></vpu-file-source>` + - example `<vpu-file-source enabled-sources="local,nextcloud"></vpu-file-source>` - `disabled` (optional): disable input control - example `<vpu-file-source disabled></vpu-file-source>` - `decompress-zip` (optional): decompress zip file and send the contained files (including files in folders) @@ -37,8 +36,12 @@ files from a [Nextcloud](https://nextcloud.com/) instance. - `nextcloud-web-dav-url` (optional): Nextcloud WebDav Url to use with the Nextcloud file picker - example `<vpu-file-source nextcloud-web-dav-url="http://localhost:8081/remote.php/dav/files"></vpu-file-source>` - `nextcloud-auth-url` also needs to be set for the Nextcloud file picker to be active -- `dialog-open` (optional): If this attribute is set the dialog for selecting local or Nextcloud files will open +- `dialog-open` (optional): if this attribute is set the dialog for selecting local or Nextcloud files will open - example `<vpu-file-source dialog-open></vpu-file-source>` +- `text` (optional): the text that is shown above the button to select files + - example `<vpu-file-source text="Please select some files"></vpu-file-source>` +- `button-label` (optional): the text that is shown on the button to select files + - example `<vpu-file-source button-label="Select files"></vpu-file-source>` ### Outgoing Events @@ -61,37 +64,32 @@ This web component is able to receive files and present as them as ZIP file down ### Attributes - `lang` (optional, default: `de`): set to `de` or `en` for German or English - - example `<vpu-file-source lang="de"></vpu-file-source>` + - example `<vpu-file-sink lang="de"></vpu-file-sink>` +- `enabled-destinations` (optional, default: `local`): sets which destination are enabled + - you can use `local` and `nextcloud` + - example `<vpu-file-sink enabled-destinations="local,nextcloud"></vpu-file-sink>` +- `filename` (optional, default: `files.zip`): sets a file name to use for downloading the zip file + - example `<vpu-file-sink filename="signed-documents.zip"></vpu-file-sink>` - `nextcloud-auth-url` (optional): Nextcloud Auth Url to use with the Nextcloud file picker - - example `<vpu-file-source nextcloud-auth-url="http://localhost:8081/index.php/apps/webapppassword"></vpu-file-source>` + - example `<vpu-file-sink nextcloud-auth-url="http://localhost:8081/index.php/apps/webapppassword"></vpu-file-sink>` - `nextcloud-web-dav-url` also needs to be set for the Nextcloud file picker to be active - `nextcloud-web-dav-url` (optional): Nextcloud WebDav Url to use with the Nextcloud file picker - - example `<vpu-file-source nextcloud-web-dav-url="http://localhost:8081/remote.php/dav/files"></vpu-file-source>` + - example `<vpu-file-sink nextcloud-web-dav-url="http://localhost:8081/remote.php/dav/files"></vpu-file-sink>` - `nextcloud-auth-url` also needs to be set for the Nextcloud file picker to be active +- `text` (optional): the text that is shown above the button to download the zip file + - example `<vpu-file-sink text="Download files as ZIP-file"></vpu-file-sink>` +- `button-label` (optional): the text that is shown on the button to download the zip file + - example `<vpu-file-sink button-label="Download files"></vpu-file-sink>` -### Incoming Events - -#### `vpu-file-sink-download-compressed-files` +### Properties -If this event is received a *save-as* dialog will pop up to store a zip file of the received files. - -##### Payload - -`{'files': [File], 'filename': 'my-file.zip'}` where `[File]` is an array of binary files which should be -compressed and `filename` is the name of the zip file that should be suggested in the *save-as* dialog - -##### Example - -```javascript -const detail = { "files": files, "filename": "signed-documents.zip" }; -const event = new CustomEvent("vpu-file-sink-download-compressed-files", { "detail": detail }); -this._("#file-sink").dispatchEvent(event); -``` +- `files`: an array of File objects which should be downloaded in the dialog + - if the property is set the dialog opens ## Local development ```bash -# get the source +# get the source code git clone git@gitlab.tugraz.at:VPU/WebComponents/FileHandling.git cd FileHandling git submodule update --init diff --git a/packages/file-handling/src/file-sink.js b/packages/file-handling/src/file-sink.js index 362722439bf7834d2e1b1fd73acc14e1c07ff8d6..07b297d9e165857a2d4312f05a8990fdee4148ab 100644 --- a/packages/file-handling/src/file-sink.js +++ b/packages/file-handling/src/file-sink.js @@ -8,6 +8,7 @@ import * as commonStyles from 'vpu-common/styles'; import {NextcloudFilePicker} from "./vpu-nextcloud-file-picker"; import {classMap} from 'lit-html/directives/class-map.js'; import FileSaver from 'file-saver'; +import MicroModal from "./micromodal.es"; /** @@ -19,8 +20,13 @@ export class FileSink extends ScopedElementsMixin(VPULitElement) { this.lang = 'de'; this.nextcloudAuthUrl = ''; this.nextcloudWebDavUrl = ''; - - this._onDownloadCompressedFiles = this.onDownloadCompressedFiles.bind(this); + this.text = ''; + this.buttonLabel = ''; + this.filename = "files.zip"; + this.files = []; + this.activeDestination = 'local'; + this.isDialogOpen = false; + this.enabledDestinations = 'local'; } static get scopedElements() { @@ -37,24 +43,26 @@ export class FileSink extends ScopedElementsMixin(VPULitElement) { static get properties() { return { lang: { type: String }, + filename: { type: String }, + files: { type: Array, attribute: false }, + enabledDestinations: { type: String, attribute: 'enabled-destinations' }, nextcloudAuthUrl: { type: String, attribute: 'nextcloud-auth-url' }, nextcloudWebDavUrl: { type: String, attribute: 'nextcloud-web-dav-url' }, + text: { type: String }, + buttonLabel: { type: String, attribute: 'button-label' }, + isDialogOpen: { type: Boolean, attribute: false }, + activeDestination: { type: Boolean, attribute: false }, }; } - async onDownloadCompressedFiles(event) { - const detail = event.detail; - - console.log("event", event); - console.log("detail", detail); - + async downloadCompressedFiles() { // see: https://stuk.github.io/jszip/ let JSZip = (await import('jszip/dist/jszip.js')).default; let zip = new JSZip(); let fileNames = []; // add all signed pdf-files - detail.files.forEach((file) => { + this.files.forEach((file) => { let fileName = file.name; // add pseudo-random string on duplicate file name @@ -70,7 +78,7 @@ export class FileSink extends ScopedElementsMixin(VPULitElement) { let content = await zip.generateAsync({type:"blob"}); // see: https://github.com/eligrey/FileSaver.js#readme - FileSaver.saveAs(content, detail.filename || "files.zip"); + FileSaver.saveAs(content, this.filename || "files.zip"); } update(changedProperties) { @@ -79,25 +87,28 @@ export class FileSink extends ScopedElementsMixin(VPULitElement) { case "lang": i18n.changeLanguage(this.lang); break; + case "enabledDestinations": + if (!this.hasEnabledDestination(this.activeDestination)) { + this.activeDestination = this.enabledDestinations.split(",")[0]; + } + break; + case "files": + if (this.files.length !== 0 && !this.isDialogOpen) { + this.openDialog(); + } + break; } }); super.update(changedProperties); } - connectedCallback() { - super.connectedCallback(); - - this.updateComplete.then(() => { - this.addEventListener('vpu-file-sink-download-compressed-files', this._onDownloadCompressedFiles); - }); + hasEnabledDestination(source) { + return this.enabledDestinations.split(',').includes(source); } - disconnectedCallback() { - // remove event listeners - window.removeEventListener('vpu-file-sink-download-compressed-files', this._onDownloadCompressedFiles); - - super.disconnectedCallback(); + uploadToNextcloud(directory) { + console.log(directory); } preventDefaults (e) { @@ -105,29 +116,88 @@ export class FileSink extends ScopedElementsMixin(VPULitElement) { e.stopPropagation(); } + openDialog() { + console.log("openDialog"); + MicroModal.show(this._('#modal-picker'), { + onClose: modal => { this.isDialogOpen = false; } + }); + } + + closeDialog() { + console.log("closeDialog"); + MicroModal.close(); + } + static get styles() { // language=css return css` ${commonStyles.getGeneralCSS()} ${commonStyles.getButtonCSS()} + ${commonStyles.getModalDialogCSS()} + + #zip-download-block { + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + } + + .block { + margin-bottom: 10px; + } `; } render() { return html` -<!-- - <vpu-nextcloud-file-picker id="nextcloud-file-picker" - class="${classMap({hidden: this.nextcloudWebDavUrl === "" || this.nextcloudAuthUrl === ""})}" - directories-only - select-button-text="${i18n.t('file-sink.select-directory')}" - ?disabled="${this.disabled}" - lang="${this.lang}" - auth-url="${this.nextcloudAuthUrl}" - web-dav-url="${this.nextcloudWebDavUrl}" - @vpu-nextcloud-file-picker-file-downloaded="${(event) => { - this.sendFileEvent(event.detail.file); - }}"></vpu-nextcloud-file-picker> ---> + <div class="modal micromodal-slide" id="modal-picker" aria-hidden="true"> + <div class="modal-overlay" tabindex="-1" data-micromodal-close> + <div class="modal-container" role="dialog" aria-modal="true" aria-labelledby="modal-picker-title"> + <nav class="modal-nav"> + <div title="${i18n.t('file-sink.nav-local')}" + @click="${() => { this.activeDestination = "local"; }}" + class="${classMap({"active": this.activeDestination === "local", hidden: !this.hasEnabledDestination("local")})}"> + <vpu-icon class="nav-icon" name="laptop"></vpu-icon> + </div> + <div title="Nextcloud" + @click="${() => { this.activeDestination = "nextcloud"; }}" + class="${classMap({"active": this.activeDestination === "nextcloud", hidden: !this.hasEnabledDestination("nextcloud")})}"> + <vpu-icon class="nav-icon" name="cloud"></vpu-icon> + </div> + </nav> + <main class="modal-content" id="modal-picker-content"> + <button title="${i18n.t('file-sink.modal-close')}" class="modal-close" aria-label="Close modal" data-micromodal-close></button> + <div class="source-main ${classMap({"hidden": this.activeDestination !== "local"})}"> + <div id="zip-download-block"> + <div class="block"> + ${this.text || i18n.t('file-sink.local-intro', {'amount': this.files.length})} + </div> + <button class="button is-primary" + ?disabled="${this.disabled}" + @click="${() => { this.downloadCompressedFiles(); }}"> + ${this.buttonLabel || i18n.t('file-sink.local-button')} + </button> + </div> + </div> + <div class="source-main ${classMap({"hidden": this.activeDestination !== "nextcloud"})}"> + <vpu-nextcloud-file-picker id="nextcloud-file-picker" + class="${classMap({hidden: this.nextcloudWebDavUrl === "" || this.nextcloudAuthUrl === ""})}" + directories-only + max-selected-items="1" + select-button-text="${i18n.t('file-sink.select-directory')}" + ?disabled="${this.disabled}" + lang="${this.lang}" + auth-url="${this.nextcloudAuthUrl}" + web-dav-url="${this.nextcloudWebDavUrl}" + @vpu-nextcloud-file-picker-file-downloaded="${(event) => { + this.uploadToNextcloud(event.detail.file); + }}"></vpu-nextcloud-file-picker> + </div> + </main> + </div> + </div> + </div> `; } } \ No newline at end of file diff --git a/packages/file-handling/src/i18n/de/translation.json b/packages/file-handling/src/i18n/de/translation.json index 27ae5492ab3ee5d149164f60e82581e16e1c05d3..64dacae8c08e19431a0fe7131899e0486c741ca6 100644 --- a/packages/file-handling/src/i18n/de/translation.json +++ b/packages/file-handling/src/i18n/de/translation.json @@ -15,6 +15,12 @@ "modal-close": "Dialog schließen", "nav-local": "Lokaler Computer" }, + "file-sink": { + "local-intro": "{{amount}} Datei(en) als ZIP-Datei herunterladen", + "local-button": "ZIP-Datei herunterladen", + "modal-close": "Dialog schließen", + "nav-local": "Lokaler Computer" + }, "nextcloud-file-picker": { "open": "Nextcloud", "open-nextcloud-file-picker": "Dateien von Ihrer Nextcloud auswählen", diff --git a/packages/file-handling/src/i18n/en/translation.json b/packages/file-handling/src/i18n/en/translation.json index 5f61a5cd7e0f54c7418f6ec538a99d917626379e..3f1f9f081e76f3c1c217d9569213743d1f7235a9 100644 --- a/packages/file-handling/src/i18n/en/translation.json +++ b/packages/file-handling/src/i18n/en/translation.json @@ -15,6 +15,12 @@ "modal-close": "Close dialog", "nav-local": "My device" }, + "file-sink": { + "local-intro": "Download {{amount}} file(s) as ZIP-file", + "local-button": "Download ZIP-file", + "modal-close": "Close dialog", + "nav-local": "My device" + }, "nextcloud-file-picker": { "open": "Nextcloud", "open-nextcloud-file-picker": "Select files from your Nextcloud",