From d8016590d8909c161b3c23218b0fb2a25ceaa6ef Mon Sep 17 00:00:00 2001 From: Tamara Steinwender <tamara.steinwender@tugraz.at> Date: Thu, 8 Apr 2021 15:05:44 +0200 Subject: [PATCH] Save files from clipboard functionality --- .../src/dbp-file-handling-clipboard.js | 277 ++++++++++-------- packages/file-handling/src/file-sink.js | 31 +- packages/file-handling/src/file-source.js | 2 +- .../src/i18n/de/translation.json | 4 +- .../src/i18n/en/translation.json | 4 +- 5 files changed, 180 insertions(+), 138 deletions(-) diff --git a/packages/file-handling/src/dbp-file-handling-clipboard.js b/packages/file-handling/src/dbp-file-handling-clipboard.js index db3cb055..1bff86ce 100644 --- a/packages/file-handling/src/dbp-file-handling-clipboard.js +++ b/packages/file-handling/src/dbp-file-handling-clipboard.js @@ -11,6 +11,7 @@ import {classMap} from 'lit-html/directives/class-map.js'; import * as commonUtils from "@dbp-toolkit/common/utils"; import {name as pkgName} from "../package.json"; import {send} from "@dbp-toolkit/common/notification"; +import {FileSink} from "./file-sink"; /** @@ -30,6 +31,13 @@ export class FileHandlingClipboard extends ScopedElementsMixin(DBPLitElement) { this.tabulatorTable = null; this.maxSelectedItems = true; this._onReceiveBeforeUnload = this.onReceiveBeforeUnload.bind(this); + this.filesToSave = null; + + this.nextcloudAuthUrl = ''; + this.nextcloudWebDavUrl = ''; + this.nextcloudName ='Nextcloud'; + this.nextcloudPath = ''; + this.nextcloudFileURL = ''; } @@ -37,6 +45,7 @@ export class FileHandlingClipboard extends ScopedElementsMixin(DBPLitElement) { return { 'dbp-icon': Icon, 'dbp-mini-spinner': MiniSpinner, + 'dbp-file-sink': FileSink, }; } @@ -53,7 +62,12 @@ export class FileHandlingClipboard extends ScopedElementsMixin(DBPLitElement) { clipboardSelectBtnDisabled: { type: Boolean, attribute: true }, clipboardFiles: {type: Object, attribute: 'clipboard-files'}, clipboardSource: {type: Boolean, attribute: 'clipboard-source'}, + filesToSave: {type: Object, attribute: 'files-to-save'}, + nextcloudAuthUrl: {type: String, attribute: 'nextcloud-auth-url'}, + nextcloudWebDavUrl: {type: String, attribute: 'nextcloud-web-dav-url'}, + nextcloudName: {type: String, attribute: 'nextcloud-name'}, + nextcloudFileURL: {type: String, attribute: 'nextcloud-file-url'}, }; } @@ -68,7 +82,6 @@ export class FileHandlingClipboard extends ScopedElementsMixin(DBPLitElement) { this.generateClipboardTable(); break; } - console.log("source", this.clipboardSource); }); super.update(changedProperties); @@ -86,113 +99,116 @@ export class FileHandlingClipboard extends ScopedElementsMixin(DBPLitElement) { super.connectedCallback(); const that = this; this.updateComplete.then(() => { - - // see: http://tabulator.info/docs/4.7 - this.tabulatorTable = new Tabulator(this._("#clipboard-content-table"), { - layout: "fitColumns", - selectable: this.maxSelectedItems, - selectableRangeMode: "drag", - responsiveLayout: true, - placeholder: i18n.t('nextcloud-file-picker.no-data-type'), - resizableColumns: false, - columns: [ - { - title: "", - field: "type", - align: "center", - headerSort: false, - width: 50, - responsive: 1, - formatter: (cell, formatterParams, onRendered) => { - const icon_tag = that.constructor.getScopedTagName("dbp-icon"); - let icon = `<${icon_tag} name="empty-file" class="nextcloud-picker-icon"></${icon_tag}>`; - return icon; - } - }, - { - title: i18n.t('nextcloud-file-picker.filename'), - responsive: 0, - widthGrow: 5, - minWidth: 150, - field: "name", - sorter: "alphanum", - formatter: (cell) => { - let data = cell.getRow().getData(); - if (data.edit) { - cell.getElement().classList.add("fokus-edit"); + if (this.clipboardSource) { + // see: http://tabulator.info/docs/4.7 + this.tabulatorTable = new Tabulator(this._("#clipboard-content-table"), { + layout: "fitColumns", + selectable: this.maxSelectedItems, + selectableRangeMode: "drag", + responsiveLayout: true, + placeholder: i18n.t('nextcloud-file-picker.no-data-type'), + resizableColumns: false, + columns: [ + { + title: "", + field: "type", + align: "center", + headerSort: false, + width: 50, + responsive: 1, + formatter: (cell, formatterParams, onRendered) => { + const icon_tag = that.constructor.getScopedTagName("dbp-icon"); + let icon = `<${icon_tag} name="empty-file" class="nextcloud-picker-icon"></${icon_tag}>`; + return icon; } - return cell.getValue(); - } - }, - { - title: i18n.t('nextcloud-file-picker.size'), - responsive: 4, - widthGrow: 1, - minWidth: 50, - field: "size", - formatter: (cell, formatterParams, onRendered) => { - return cell.getRow().getData().type === "directory" ? "" : humanFileSize(cell.getValue()); - } - }, - { - title: i18n.t('nextcloud-file-picker.mime-type'), - responsive: 2, - widthGrow: 1, - minWidth: 20, - field: "type", - formatter: (cell, formatterParams, onRendered) => { - if (typeof cell.getValue() === 'undefined') { - return ""; + }, + { + title: i18n.t('nextcloud-file-picker.filename'), + responsive: 0, + widthGrow: 5, + minWidth: 150, + field: "name", + sorter: "alphanum", + formatter: (cell) => { + let data = cell.getRow().getData(); + if (data.edit) { + cell.getElement().classList.add("fokus-edit"); + } + return cell.getValue(); + } + }, + { + title: i18n.t('nextcloud-file-picker.size'), + responsive: 4, + widthGrow: 1, + minWidth: 50, + field: "size", + formatter: (cell, formatterParams, onRendered) => { + return cell.getRow().getData().type === "directory" ? "" : humanFileSize(cell.getValue()); } - const [, fileSubType] = cell.getValue().split('/'); - return fileSubType; - } - }, - { - title: i18n.t('nextcloud-file-picker.last-modified'), - responsive: 3, - widthGrow: 1, - minWidth: 150, - field: "lastModified", - sorter: (a, b, aRow, bRow, column, dir, sorterParams) => { - const a_timestamp = Date.parse(a); - const b_timestamp = Date.parse(b); - return a_timestamp - b_timestamp; }, - formatter: function (cell, formatterParams, onRendered) { - const timestamp = new Date(cell.getValue()); - const year = timestamp.getFullYear(); - const month = ("0" + (timestamp.getMonth() + 1)).slice(-2); - const date = ("0" + timestamp.getDate()).slice(-2); - const hours = ("0" + timestamp.getHours()).slice(-2); - const minutes = ("0" + timestamp.getMinutes()).slice(-2); - return date + "." + month + "." + year + " " + hours + ":" + minutes; + { + title: i18n.t('nextcloud-file-picker.mime-type'), + responsive: 2, + widthGrow: 1, + minWidth: 20, + field: "type", + formatter: (cell, formatterParams, onRendered) => { + if (typeof cell.getValue() === 'undefined') { + return ""; + } + const [, fileSubType] = cell.getValue().split('/'); + return fileSubType; + } + }, + { + title: i18n.t('nextcloud-file-picker.last-modified'), + responsive: 3, + widthGrow: 1, + minWidth: 150, + field: "lastModified", + sorter: (a, b, aRow, bRow, column, dir, sorterParams) => { + const a_timestamp = Date.parse(a); + const b_timestamp = Date.parse(b); + return a_timestamp - b_timestamp; + }, + formatter: function (cell, formatterParams, onRendered) { + const timestamp = new Date(cell.getValue()); + const year = timestamp.getFullYear(); + const month = ("0" + (timestamp.getMonth() + 1)).slice(-2); + const date = ("0" + timestamp.getDate()).slice(-2); + const hours = ("0" + timestamp.getHours()).slice(-2); + const minutes = ("0" + timestamp.getMinutes()).slice(-2); + return date + "." + month + "." + year + " " + hours + ":" + minutes; + } + }, + {title: "file", field: "file", visible: false} + ], + initialSort: [ + {column: "name", dir: "asc"}, + {column: "type", dir: "asc"}, + ], + rowClick: (e, row) => { + if (this.tabulatorTable !== null + && this.tabulatorTable.getSelectedRows().length === this.tabulatorTable.getRows().filter(row => this.checkFileType(row.getData())).length) { + this.showSelectAllButton = false; + } else { + this.showSelectAllButton = true; } }, - {title: "file", field: "file", visible: false} - ], - initialSort: [ - {column: "name", dir: "asc"}, - {column: "type", dir: "asc"}, - ], - rowClick: (e, row) => { - if (this.tabulatorTable !== null - && this.tabulatorTable.getSelectedRows().length === this.tabulatorTable.getRows().filter(row => this.checkFileType(row.getData())).length) { - this.showSelectAllButton = false; - } else { - this.showSelectAllButton = true; - } - }, - rowSelectionChanged: (data, rows) => { - if (this.tabulatorTable && this.tabulatorTable.getSelectedRows().length > 0) { - this.clipboardSelectBtnDisabled = false; - } else { - this.clipboardSelectBtnDisabled = true; + rowSelectionChanged: (data, rows) => { + if (this.tabulatorTable && this.tabulatorTable.getSelectedRows().length > 0) { + this.clipboardSelectBtnDisabled = false; + } else { + this.clipboardSelectBtnDisabled = true; + } } - } - }); + }); + } }); - window.addEventListener('beforeunload', this._onReceiveBeforeUnload); + if (!this.clipboardSource) { + window.addEventListener('beforeunload', this._onReceiveBeforeUnload); + } } @@ -204,7 +220,6 @@ export class FileHandlingClipboard extends ScopedElementsMixin(DBPLitElement) { this.tabulatorTable.selectRow(this.tabulatorTable.getRows().filter(row => this.checkFileType(row.getData()))); if (this.tabulatorTable.getSelectedRows().length > 0) { this.showSelectAllButton = false; - console.log("Show Select All Button:", this.showSelectAllButton); } } @@ -215,7 +230,6 @@ export class FileHandlingClipboard extends ScopedElementsMixin(DBPLitElement) { deselectAll() { this.tabulatorTable.deselectRow(); this.showSelectAllButton = true; - console.log("Show Select All Button:", this.showSelectAllButton); } checkFileType(file) { @@ -237,20 +251,22 @@ export class FileHandlingClipboard extends ScopedElementsMixin(DBPLitElement) { } generateClipboardTable() { - let data = []; - for (let i = 0; i < this.clipboardFiles.files.length; i++){ - data[i] = { - name: this.clipboardFiles.files[i].name, - size: this.clipboardFiles.files[i].size, - type: this.clipboardFiles.files[i].type, - lastModified: this.clipboardFiles.files[i].lastModified, - file: this.clipboardFiles.files[i] - }; - } + if (this.clipboardFiles.files) { + let data = []; + for (let i = 0; i < this.clipboardFiles.files.length; i++){ + data[i] = { + name: this.clipboardFiles.files[i].name, + size: this.clipboardFiles.files[i].size, + type: this.clipboardFiles.files[i].type, + lastModified: this.clipboardFiles.files[i].lastModified, + file: this.clipboardFiles.files[i] + }; + } - if (this.tabulatorTable !== null){ - this.tabulatorTable.clearData(); - this.tabulatorTable.setData(data); + if (this.tabulatorTable !== null){ + this.tabulatorTable.clearData(); + this.tabulatorTable.setData(data); + } } } @@ -261,7 +277,7 @@ export class FileHandlingClipboard extends ScopedElementsMixin(DBPLitElement) { await this.sendFileEvent(files[i].file); } this.tabulatorTable.deselectRow(); - this.closeDialog(); + //this.closeDialog(); } @@ -315,17 +331,18 @@ export class FileHandlingClipboard extends ScopedElementsMixin(DBPLitElement) { { //save it let data = {}; - if (this.files.length !== 0) { - data = {"files": this.files}; + if (this.filesToSave && this.filesToSave.length !== 0) { + data = {"files": this.filesToSave}; this.sendSetPropertyEvent('clipboard-files', data); - this.closeDialog(); + const event = new CustomEvent("dbp-clipboard-file-picker-file-uploaded", + { bubbles: true, composed: true }); + this.dispatchEvent(event); send({ "summary": i18n.t('file-sink.save-to-clipboard-title'), - "body": i18n.t('file-sink.save-to-clipboard-body', {count: this.files.length}), + "body": i18n.t('file-sink.save-to-clipboard-body', {count: this.filesToSave.length}), "type": "success", "timeout": 5, }); - console.log("--------------", this.clipboardFiles); } } @@ -346,7 +363,7 @@ export class FileHandlingClipboard extends ScopedElementsMixin(DBPLitElement) { */ async openClipboardFileSink() { this._("#file-sink-clipboard").files = this.clipboardFiles.files; - this._("#file-sink-clipboard").setAttribute("dialog-open", ""); + this._("#file-sink-clipboard").openDialog(); } static get styles() { @@ -516,7 +533,7 @@ export class FileHandlingClipboard extends ScopedElementsMixin(DBPLitElement) { <button class="button is-primary clipboard-btn" ?disabled="${this.disabled}" @click="${() => { this.saveFilesToClipboard(); }}"> - ${this.buttonLabel || i18n.t('file-sink.save-to-clipboard-btn', {count:this.clipboardFiles.files.length})} + ${this.buttonLabel || i18n.t('file-sink.save-to-clipboard-btn', {count:this.filesToSave ? this.filesToSave.length : 0})} </button> <div class="warning-container"> <dbp-icon name="warning" class="warning-icon"></dbp-icon> @@ -533,14 +550,14 @@ export class FileHandlingClipboard extends ScopedElementsMixin(DBPLitElement) { </div> <dbp-file-sink id="file-sink-clipboard" - context="${i18n.t('qualified-pdf-upload.save-field-label', {count: this.clipboardFiles ? this.clipboardFiles.files.length : 0})}" - filename="signed-documents.zip" - subscribe="initial-file-handling-state:initial-file-handling-state" - enabled-targets="local${this.showNextcloudFilePicker ? ",nextcloud" : ""}" - nextcloud-auth-url="${this.nextcloudWebAppPasswordURL}" - nextcloud-web-dav-url="${this.nextcloudWebDavURL}" + context="${i18n.t('clipboard.save-files-from-clipboard', {count: this.clipboardFiles ? this.clipboardFiles.files.length : 0})}" + filename="clipboard-documents.zip" + enabled-targets="local" + nextcloud-auth-url="${this.nextcloudAuthUrl}" + nextcloud-web-dav-url="${this.nextcloudWebDavUrl}" nextcloud-name="${this.nextcloudName}" nextcloud-file-url="${this.nextcloudFileURL}" + fullsize-modal="true" lang="${this.lang}" ></dbp-file-sink> diff --git a/packages/file-handling/src/file-sink.js b/packages/file-handling/src/file-sink.js index c433d6e3..a64223d3 100644 --- a/packages/file-handling/src/file-sink.js +++ b/packages/file-handling/src/file-sink.js @@ -38,6 +38,7 @@ export class FileSink extends ScopedElementsMixin(DBPLitElement) { this.enabledTargets = 'local'; this.firstOpen = true; this.showClipboard = false; + this.fullsizeModal = false; this.initialFileHandlingState = {target: '', path: ''}; } @@ -73,6 +74,7 @@ export class FileSink extends ScopedElementsMixin(DBPLitElement) { firstOpen: {type: Boolean, attribute: false}, nextcloudPath: {type: String, attribute: false}, showClipboard: { type: Boolean, attribute: 'show-clipboard' }, + fullsizeModal: { type: Boolean, attribute: 'fullsize-modal' }, initialFileHandlingState: {type: Object, attribute: 'initial-file-handling-state'}, @@ -137,7 +139,11 @@ export class FileSink extends ScopedElementsMixin(DBPLitElement) { break; case "files": if (this.files.length !== 0 && !this.isDialogOpen) { + console.log("--------------", this.files); this.openDialog(); + if (this.enabledTargets.includes("clipboard")) { + this._("#clipboard-file-sink").filesToSave = this.files; + } } break; case "initialFileHandlingState": @@ -194,7 +200,7 @@ export class FileSink extends ScopedElementsMixin(DBPLitElement) { loadWebdavDirectory() { - if (this._('#nextcloud-file-picker').webDavClient !== null) { + if (this._('#nextcloud-file-picker') && this._('#nextcloud-file-picker').webDavClient !== null) { this._('#nextcloud-file-picker').loadDirectory(this._('#nextcloud-file-picker').directoryPath); } } @@ -221,8 +227,11 @@ export class FileSink extends ScopedElementsMixin(DBPLitElement) { } closeDialog(e) { + console.log("close start"); this.sendDestination(); MicroModal.close(this._('#modal-picker')); + console.log("close end"); + } getClipboardHtml() { @@ -234,8 +243,12 @@ export class FileSink extends ScopedElementsMixin(DBPLitElement) { lang="${this.lang}" auth-url="${this.nextcloudAuthUrl}" allowed-mime-types="${this.allowedMimeTypes}" - @dbp-clipboard-file-picker-file-downloaded="${(event) => { - this.sendFileEvent(event.detail.file);}}"> + nextcloud-auth-url="${this.nextcloudAuthUrl}" + nextcloud-web-dav-url="${this.nextcloudWebDavUrl}" + nextcloud-name="${this.nextcloudName}" + nextcloud-file-url="${this.nextcloudFileURL}" + @dbp-clipboard-file-picker-file-uploaded="${(event) => { + this.closeDialog(event);}}"> </dbp-clipboard>`; } return html``; @@ -270,6 +283,8 @@ export class FileSink extends ScopedElementsMixin(DBPLitElement) { static get styles() { + + // language=css return css` ${commonStyles.getThemeCSS()} @@ -278,6 +293,11 @@ export class FileSink extends ScopedElementsMixin(DBPLitElement) { ${commonStyles.getModalDialogCSS()} ${fileHandlingStyles.getFileHandlingCss()} + .modal-container-full-size{ + min-width: 100%; + min-height: 100%; + } + #zip-download-block { height: 100%; width: 100%; @@ -295,18 +315,19 @@ export class FileSink extends ScopedElementsMixin(DBPLitElement) { width: 100%; height: 100%; } + + `; } render() { const isClipboardHidden = !this.showClipboard; - return html` <vpu-notification lang="de" client-id="my-client-id"></vpu-notification> <div class="modal micromodal-slide" id="modal-picker" aria-hidden="true"> <div class="modal-overlay" tabindex="-1"> - <div class="modal-container" role="dialog" aria-modal="true" aria-labelledby="modal-picker-title"> + <div class="modal-container ${classMap({"modal-container-full-size": this.fullsizeModal})}" role="dialog" aria-modal="true" aria-labelledby="modal-picker-title"> <nav class="modal-nav"> <div title="${i18n.t('file-sink.nav-local')}" @click="${() => { this.activeTarget = "local"; }}" diff --git a/packages/file-handling/src/file-source.js b/packages/file-handling/src/file-source.js index 04ed7eeb..e62a32e4 100644 --- a/packages/file-handling/src/file-source.js +++ b/packages/file-handling/src/file-source.js @@ -399,7 +399,7 @@ export class FileSource extends ScopedElementsMixin(DBPLitElement) { if (this.initialFileHandlingState.target !== '' && typeof this.initialFileHandlingState.target !== 'undefined' && this.firstOpen) { this.activeDestination = this.initialFileHandlingState.target; this.nextcloudPath = this.initialFileHandlingState.path; - if (this._('#nextcloud-file-picker').webDavClient !== null) { + if (this._('#nextcloud-file-picker') && this._('#nextcloud-file-picker').webDavClient !== null) { this._('#nextcloud-file-picker').loadDirectory(this.initialFileHandlingState.path); //console.log("load default nextcloud source", this.initialFileHandlingState.target); } diff --git a/packages/file-handling/src/i18n/de/translation.json b/packages/file-handling/src/i18n/de/translation.json index f6a46d42..c3972041 100644 --- a/packages/file-handling/src/i18n/de/translation.json +++ b/packages/file-handling/src/i18n/de/translation.json @@ -100,6 +100,8 @@ "clipboard": { "file-warning": "Achtung!", "file-warning-body": "Es befindet sich noch eine Datei in der Zwischenablage. Die Zwischenablage wird beim Verlassen der Seite automatisch verworfen.", - "file-warning-body_plural": "Es befinden sich noch {{count}} Dateien in der Zwischenablage. Die Zwischenablage wird beim Verlassen der Seite automatisch verworfen." + "file-warning-body_plural": "Es befinden sich noch {{count}} Dateien in der Zwischenablage. Die Zwischenablage wird beim Verlassen der Seite automatisch verworfen.", + "save-files-from-clipboard": "Eine Datei aus der Zwischenablage speichern", + "save-files-from-clipboard_plural": "{{count}} Dateien aus der Zwischenablage speichern" } } diff --git a/packages/file-handling/src/i18n/en/translation.json b/packages/file-handling/src/i18n/en/translation.json index 881fb18d..1321a2d8 100644 --- a/packages/file-handling/src/i18n/en/translation.json +++ b/packages/file-handling/src/i18n/en/translation.json @@ -100,6 +100,8 @@ "clipboard": { "file-warning": "Attention!", "file-warning-body": "There is still a file on the clipboard. The clipboard is automatically discarded when you exit the page.", - "file-warning-body_plural": "There are still {{count}} files on the clipboard. The clipboard is automatically discarded when you exit the page." + "file-warning-body_plural": "There are still {{count}} files on the clipboard. The clipboard is automatically discarded when you exit the page.", + "save-files-from-clipboard": "Save a file from the clipboard", + "save-files-from-clipboard_plural": "Save {{count}} files from the clipboard" } } -- GitLab