From ea55ef15d07eed3ee22842772205ba925d1b9a42 Mon Sep 17 00:00:00 2001 From: Patrizio Bekerle <patrizio@bekerle.com> Date: Tue, 30 Jun 2020 08:16:54 +0200 Subject: [PATCH] Implement vpu-file-sink web component (VPU/Apps/Signature#28) --- packages/file-handling/README.md | 49 +++++++- packages/file-handling/package.json | 1 + packages/file-handling/src/file-sink.js | 131 ++++++++++++++++++++ packages/file-handling/src/vpu-file-sink.js | 4 + packages/file-handling/vendor/common | 2 +- 5 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 packages/file-handling/src/file-sink.js create mode 100644 packages/file-handling/src/vpu-file-sink.js diff --git a/packages/file-handling/README.md b/packages/file-handling/README.md index c17e4cab..7c2d6658 100644 --- a/packages/file-handling/README.md +++ b/packages/file-handling/README.md @@ -4,6 +4,9 @@ ## FileSource +This web component allows the selection of local files via file dialog or drag and drop and to select and download +files from a [Nextcloud](https://nextcloud.com/) instance. + ### Usage ```html @@ -31,7 +34,7 @@ - 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 -### Events +### Outgoing Events #### `vpu-file-source-file-selected` @@ -39,6 +42,46 @@ This event is sent if a file was selected. **Payload**: `{'file': File}` where `File` is the binary file that was selected +## FileSink + +This web component is able to receive files and present as them as ZIP file download. + +### Usage + +```html +<vpu-file-sink></vpu-file-sink> +``` + +### Attributes + +- `lang` (optional, default: `de`): set to `de` or `en` for German or English + - example `<vpu-file-source lang="de"></vpu-file-source>` +- `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>` + - `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>` + - `nextcloud-auth-url` also needs to be set for the Nextcloud file picker to be active + +### Incoming Events + +#### `vpu-file-sink-download-compressed-files` + +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); +``` + ## Local development ```bash @@ -55,3 +98,7 @@ npm run watch-local ``` Jump to <http://localhost:8002> and you should get a demo page. + +To use the Nextcloud functionality you need a running Nextcloud server with the +[webapppassword](https://gitlab.tugraz.at/VPU/Middleware/Nextcloud/webapppassword) Nextcloud app like this +[Nextcloud Development Environment](https://gitlab.tugraz.at/VPU/Middleware/Nextcloud/webapppassword/-/tree/master/docker). diff --git a/packages/file-handling/package.json b/packages/file-handling/package.json index 97783b5a..4e2a79e9 100644 --- a/packages/file-handling/package.json +++ b/packages/file-handling/package.json @@ -26,6 +26,7 @@ }, "dependencies": { "@open-wc/scoped-elements": "^1.0.8", + "file-saver": "^2.0.2", "i18next": "^19.4.2", "jszip": "^3.5.0", "lit-element": "^2.1.0", diff --git a/packages/file-handling/src/file-sink.js b/packages/file-handling/src/file-sink.js new file mode 100644 index 00000000..ee76039c --- /dev/null +++ b/packages/file-handling/src/file-sink.js @@ -0,0 +1,131 @@ +import {i18n} from './i18n'; +import {css, html} from 'lit-element'; +import {ScopedElementsMixin} from '@open-wc/scoped-elements'; +import VPULitElement from 'vpu-common/vpu-lit-element'; +import * as commonUtils from "vpu-common/utils"; +import {Icon, MiniSpinner} from 'vpu-common'; +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'; + + +/** + * FileSink web component + */ +export class FileSink extends ScopedElementsMixin(VPULitElement) { + constructor() { + super(); + this.lang = 'de'; + this.nextcloudAuthUrl = ''; + this.nextcloudWebDavUrl = ''; + + this._onDownloadCompressedFiles = this.onDownloadCompressedFiles.bind(this); + } + + static get scopedElements() { + return { + 'vpu-icon': Icon, + 'vpu-mini-spinner': MiniSpinner, + 'vpu-nextcloud-file-picker': NextcloudFilePicker, + }; + } + + /** + * See: https://lit-element.polymer-project.org/guide/properties#initialize + */ + static get properties() { + return { + lang: { type: String }, + nextcloudAuthUrl: { type: String, attribute: 'nextcloud-auth-url' }, + nextcloudWebDavUrl: { type: String, attribute: 'nextcloud-web-dav-url' }, + }; + } + + async onDownloadCompressedFiles(event) { + const detail = event.detail; + + console.log("event", event); + console.log("detail", detail); + + // 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) => { + let fileName = file.name; + + // add pseudo-random string on duplicate file name + if (fileNames.indexOf(fileName) !== -1) { + fileName = commonUtils.getBaseName(fileName) + "-" + Math.random().toString(36).substring(7) + "." + + commonUtils.getFileExtension(fileName); + } + + fileNames.push(fileName); + zip.file(fileName, file); + }); + + let content = await zip.generateAsync({type:"blob"}); + + // see: https://github.com/eligrey/FileSaver.js#readme + FileSaver.saveAs(content, detail.filename || "files.zip"); + } + + update(changedProperties) { + changedProperties.forEach((oldValue, propName) => { + switch (propName) { + case "lang": + i18n.changeLanguage(this.lang); + break; + } + }); + + super.update(changedProperties); + } + + connectedCallback() { + super.connectedCallback(); + + this.updateComplete.then(() => { + this.addEventListener('vpu-file-sink-download-compressed-files', this._onDownloadCompressedFiles); + }); + } + + disconnectedCallback() { + // remove event listeners + window.removeEventListener('vpu-file-sink-download-compressed-files', this._onDownloadCompressedFiles); + + super.disconnectedCallback(); + } + + preventDefaults (e) { + e.preventDefault(); + e.stopPropagation(); + } + + static get styles() { + // language=css + return css` + ${commonStyles.getGeneralCSS()} + ${commonStyles.getButtonCSS()} + `; + } + + render() { + return html` +<!-- + <vpu-nextcloud-file-picker id="nextcloud-file-picker" + class="${classMap({hidden: this.nextcloudWebDavUrl === "" || this.nextcloudAuthUrl === ""})}" + ?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> +--> + `; + } +} \ No newline at end of file diff --git a/packages/file-handling/src/vpu-file-sink.js b/packages/file-handling/src/vpu-file-sink.js new file mode 100644 index 00000000..bcc2431e --- /dev/null +++ b/packages/file-handling/src/vpu-file-sink.js @@ -0,0 +1,4 @@ +import * as commonUtils from "vpu-common/utils"; +import {FileSink} from './file-sink'; + +commonUtils.defineCustomElement('vpu-file-sink', FileSink); diff --git a/packages/file-handling/vendor/common b/packages/file-handling/vendor/common index 338c8012..63b49c3a 160000 --- a/packages/file-handling/vendor/common +++ b/packages/file-handling/vendor/common @@ -1 +1 @@ -Subproject commit 338c8012f85e7b54a1e32f0f7af603e864573463 +Subproject commit 63b49c3a2eeae312b4a2aeec4cc2f7f0ee12b749 -- GitLab