From d1a1b6d26212ecf7b4ac2272e0487d4ef417f68a Mon Sep 17 00:00:00 2001
From: Patrizio Bekerle <patrizio.bekerle@tugraz.at>
Date: Wed, 30 Jun 2021 11:27:11 +0200
Subject: [PATCH] Do file name refactoring and build dbp-nextcloud-file-picker
 as distinct component

---
 packages/file-handling/rollup.config.js       |    2 +-
 .../src/dbp-nextcloud-file-picker.js          | 1797 +----------------
 packages/file-handling/src/file-sink.js       |    2 +-
 packages/file-handling/src/file-source.js     |    2 +-
 .../src/nextcloud-file-picker.js              | 1795 ++++++++++++++++
 5 files changed, 1801 insertions(+), 1797 deletions(-)
 create mode 100644 packages/file-handling/src/nextcloud-file-picker.js

diff --git a/packages/file-handling/rollup.config.js b/packages/file-handling/rollup.config.js
index a7b1bd00..c26f3f26 100644
--- a/packages/file-handling/rollup.config.js
+++ b/packages/file-handling/rollup.config.js
@@ -17,7 +17,7 @@ let nextcloudFileURL = nextcloudBaseURL + '/apps/files/?dir=';
 
 export default (async () => {
     return {
-        input: (build !== 'test') ? ['src/demo.js', 'src/dbp-file-source.js', 'src/dbp-file-sink.js', 'src/dbp-clipboard.js'] : glob.sync('test/**/*.js'),
+        input: (build !== 'test') ? ['src/demo.js', 'src/dbp-file-source.js', 'src/dbp-file-sink.js', 'src/dbp-clipboard.js', 'src/dbp-nextcloud-file-picker.js'] : glob.sync('test/**/*.js'),
         output: {
             dir: 'dist',
             entryFileNames: '[name].js',
diff --git a/packages/file-handling/src/dbp-nextcloud-file-picker.js b/packages/file-handling/src/dbp-nextcloud-file-picker.js
index 65b7f12b..97613153 100644
--- a/packages/file-handling/src/dbp-nextcloud-file-picker.js
+++ b/packages/file-handling/src/dbp-nextcloud-file-picker.js
@@ -1,1795 +1,4 @@
-import {i18n} from './i18n';
-import {css, html} from 'lit-element';
-import {ScopedElementsMixin} from '@open-wc/scoped-elements';
-import DBPLitElement from '@dbp-toolkit/common/dbp-lit-element';
-import {Icon, MiniSpinner} from '@dbp-toolkit/common';
-import * as commonUtils from '@dbp-toolkit/common/utils';
-import * as commonStyles from '@dbp-toolkit/common/styles';
-import {createClient} from 'webdav/web';
-import {classMap} from 'lit-html/directives/class-map.js';
-import {humanFileSize} from '@dbp-toolkit/common/i18next';
-import Tabulator from 'tabulator-tables';
-import MicroModal from './micromodal.es';
-import {name as pkgName} from './../package.json';
-import * as fileHandlingStyles from './styles';
+import * as commonUtils from "@dbp-toolkit/common/utils";
+import {NextcloudFilePicker} from './nextcloud-file-picker';
 
-/**
- * NextcloudFilePicker web component
- */
-export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
-    constructor() {
-        super();
-        this.lang = 'de';
-        this.authUrl = '';
-        this.webDavUrl = '';
-        this.nextcloudName = 'Nextcloud';
-        this.nextcloudFileURL = '';
-        this.loginWindow = null;
-        this.isPickerActive = false;
-        this.statusText = '';
-        this.lastDirectoryPath = '/';
-        this.directoryPath = '';
-        this.webDavClient = null;
-        this.tabulatorTable = null;
-        this.allowedMimeTypes = '*/*';
-        this.directoriesOnly = false;
-        this.maxSelectedItems = true;
-        this.loading = false;
-        this._onReceiveWindowMessage = this.onReceiveWindowMessage.bind(this);
-
-        this.folderIsSelected = i18n.t('nextcloud-file-picker.load-in-folder');
-        this.generatedFilename = '';
-        this.replaceFilename = '';
-        this.customFilename = '';
-        this.uploadFileObject = null;
-        this.uploadFileDirectory = null;
-        this.fileList = [];
-        this.fileNameCounter = 1;
-        this.activeDirectoryRights = 'RGDNVCK';
-        this.activeDirectoryACL = '';
-        this.forAll = false;
-        this.uploadCount = 0;
-        this.abortUploadButton = false;
-        this.abortUpload = false;
-        this.authInfo = '';
-        this.selectBtnDisabled = true;
-    }
-
-    static get scopedElements() {
-        return {
-            'dbp-icon': Icon,
-            'dbp-mini-spinner': MiniSpinner,
-        };
-    }
-
-    /**
-     * See: https://lit-element.polymer-project.org/guide/properties#initialize
-     */
-    static get properties() {
-        return {
-            ...super.properties,
-            lang: {type: String},
-            authUrl: {type: String, attribute: 'auth-url'},
-            webDavUrl: {type: String, attribute: 'web-dav-url'},
-            nextcloudFileURL: {type: String, attribute: 'nextcloud-file-url'},
-            nextcloudName: {type: String, attribute: 'nextcloud-name'},
-            isPickerActive: {type: Boolean, attribute: false},
-            statusText: {type: String, attribute: false},
-            folderIsSelected: {type: String, attribute: false},
-            authInfo: {type: String, attribute: 'auth-info'},
-            directoryPath: {type: String, attribute: 'directory-path'},
-            allowedMimeTypes: {type: String, attribute: 'allowed-mime-types'},
-            directoriesOnly: {type: Boolean, attribute: 'directories-only'},
-            maxSelectedItems: {type: Number, attribute: 'max-selected-items'},
-            loading: {type: Boolean, attribute: false},
-            replaceFilename: {type: String, attribute: false},
-            uploadFileObject: {type: Object, attribute: false},
-            uploadFileDirectory: {type: String, attribute: false},
-            activeDirectoryRights: {type: String, attribute: false},
-            activeDirectoryACL: {type: String, attribute: false},
-            abortUploadButton: {type: Boolean, attribute: false},
-            selectBtnDisabled: {type: Boolean, attribute: true},
-        };
-
-    }
-
-    update(changedProperties) {
-        changedProperties.forEach((oldValue, propName) => {
-            switch (propName) {
-                case "lang":
-                    i18n.changeLanguage(this.lang);
-                    break;
-                case "directoriesOnly":
-                    if (this.directoriesOnly && this._("#select_all_wrapper")) {
-                        this._("#select_all_wrapper").classList.remove("button-container");
-                        this._("#select_all_wrapper").classList.add("hidden");
-                    }
-                    if (!this.directoriesOnly && this._("#select_all_wrapper")) {
-                        this._("#select_all_wrapper").classList.add("button-container");
-                        this._("#select_all_wrapper").classList.remove("hidden");
-                    }
-            }
-        });
-
-        super.update(changedProperties);
-    }
-
-    disconnectedCallback() {
-        window.removeEventListener('message', this._onReceiveWindowMessage);
-        super.disconnectedCallback();
-    }
-
-    async firstUpdated() {
-        // Give the browser a chance to paint
-        await new Promise((r) => setTimeout(r, 0));
-        if (this._("#select_all")) {
-            let boundSelectHandler = this.selectAllFiles.bind(this);
-            this._("#select_all").addEventListener('click', boundSelectHandler);
-        }
-        if (this.directoriesOnly && this._("#select_all_wrapper")) {
-            this._("#select_all_wrapper").classList.remove("button-container");
-            this._("#select_all_wrapper").classList.add("hidden");
-        }
-
-    }
-
-    connectedCallback() {
-        super.connectedCallback();
-        const that = this;
-        this.updateComplete.then(() => {
-            // see: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
-            window.addEventListener('message', this._onReceiveWindowMessage);
-
-            // see: http://tabulator.info/docs/4.7
-            this.tabulatorTable = new Tabulator(this._("#directory-content-table"), {
-                layout: "fitColumns",
-                selectable: this.maxSelectedItems,
-                selectableRangeMode: "drag",
-                placeholder: this.directoriesOnly ? i18n.t('nextcloud-file-picker.no-data') : i18n.t('nextcloud-file-picker.no-data-type'),
-                responsiveLayout: "collapse",
-                responsiveLayoutCollapseStartOpen: false,
-                resizableColumns: false,
-                columns: [
-                    {
-                        formatter:"responsiveCollapse", width:32, minWidth:32, align:"center", resizable:false, headerSort:false},
-                    {
-                        title: '<label id="select_all_wrapper" class="button-container select-all-icon">' +
-                            '<input type="checkbox" id="select_all" name="select_all" value="select_all">' +
-                            '<span class="checkmark" id="select_all_checkmark"></span>' +
-                            '</label>',
-                        field: "type",
-                        align: "center",
-                        headerSort: false,
-                        width: 50,
-                        responsive: 1,
-                        formatter: (cell, formatterParams, onRendered) => {
-                            const icon_tag = that.getScopedTagName("dbp-icon");
-                            let disabled = this.directoriesOnly ? "nextcloud-picker-icon-disabled" : "";
-                            let icon = `<${icon_tag} name="empty-file" class="nextcloud-picker-icon ` + disabled + `"></${icon_tag}>`;
-                            return (cell.getValue() === "directory") ? `<${icon_tag} name="folder" class="nextcloud-picker-icon"></${icon_tag}>` : icon;
-                        }
-                    },
-                    {
-                        title: i18n.t('nextcloud-file-picker.filename'),
-                        responsive: 0,
-                        widthGrow: 5,
-                        minWidth: 150,
-                        field: "basename",
-                        sorter: "alphanum",
-                        formatter: (cell) => {
-                            var 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: 65,
-                        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: 35,
-                        field: "mime",
-                        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: 100,
-                        field: "lastmod",
-                        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 d = Date.parse(cell.getValue());
-                            const timestamp = new Date(d);
-                            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: "rights", field: "props.permissions", visible: false},
-                    {title: "acl", field: "props.acl-list.acl.acl-permissions", visible: false}
-                ],
-                initialSort: [
-                    {column: "basename", dir: "asc"},
-                    {column: "type", dir: "asc"},
-
-                ],
-                rowFormatter: (row) => {
-                    let data = row.getData();
-                    if (!this.checkFileType(data, this.allowedMimeTypes)) {
-                        row.getElement().classList.add("no-select");
-                        row.getElement().classList.remove("tabulator-selectable");
-                    }
-                    if (this.directoriesOnly && typeof data.mime !== 'undefined') {
-                        row.getElement().classList.add("no-select");
-                        row.getElement().classList.remove("tabulator-selectable");
-                    }
-                },
-                rowSelectionChanged: (data, rows) => {
-                    if (data.length > 0 && this.directoriesOnly) {
-                        this.folderIsSelected = i18n.t('nextcloud-file-picker.load-to-folder');
-                    } else {
-                        this.folderIsSelected = i18n.t('nextcloud-file-picker.load-in-folder');
-                    }
-                    if (this.tabulatorTable && this.tabulatorTable.getSelectedRows().filter(row => row.getData().type != 'directory' && this.checkFileType(row.getData(), this.allowedMimeTypes)).length > 0) {
-                        this.selectBtnDisabled = false;
-                    } else {
-                        this.selectBtnDisabled = true;
-                    }
-                    if (this._("#select_all_checkmark")) {
-                        this._("#select_all_checkmark").title = this.checkAllSelected() ? i18n.t('clipboard.select-nothing') : i18n.t('clipboard.select-all');
-                    }
-                    this.requestUpdate();
-                },
-                rowClick: (e, row) => {
-                    const data = row.getData();
-
-                    if (!row.getElement().classList.contains("no-select")) {
-                        if (this.directoriesOnly) {
-                            // comment out if you want to navigate through folders with double click
-                            const data = row.getData();
-                            this.directoryClicked(e, data);
-                            this.folderIsSelected = i18n.t('nextcloud-file-picker.load-in-folder');
-                        } else {
-                            switch (data.type) {
-                                case "directory":
-                                    this.directoryClicked(e, data);
-                                    break;
-                                case "file":
-                                    if (this.tabulatorTable !== null
-                                        && this.tabulatorTable.getSelectedRows().length === this.tabulatorTable.getRows().filter(row => row.getData().type != 'directory' && this.checkFileType(row.getData(), this.allowedMimeTypes)).length) {
-                                        this._("#select_all").checked = true;
-                                    } else {
-                                        this._("#select_all").checked = false;
-                                    }
-                                    break;
-                            }
-                        }
-                    } else {
-                        row.deselect();
-                    }
-                },
-                rowDblClick: (e, row) => {
-                    // comment this in for double click directory change
-                    /* if (this.directoriesOnly) {
-                         const data = row.getData();
-                         this.directoryClicked(e, data);
-                         this.folderIsSelected = i18n.t('nextcloud-file-picker.load-in-folder');
-                     }*/
-                },
-                rowAdded: (row) => {
-                    row.getElement().classList.toggle("addRowAnimation");
-                }
-            });
-
-
-            // Strg + click select mode on desktop
-            /*if (this.tabulatorTable.browserMobile === false) {
-                this.tabulatorTable.options.selectableRangeMode = "click";
-            }*/
-
-            if (typeof this.allowedMimeTypes !== 'undefined' && !this.directoriesOnly) {
-                this.tabulatorTable.setFilter(this.checkFileType, this.allowedMimeTypes);
-            }
-            // comment this in to show only directories in filesink
-            /*
-            if (typeof this.directoriesOnly !== 'undefined' && this.directoriesOnly) {
-                this.tabulatorTable.setFilter([
-                    {field:"type", type:"=", value:"directory"},
-                ]);
-            }
-            */
-
-            // add folder on enter
-            this._('#new-folder').addEventListener('keydown', function (e) {
-                if (e.keyCode === 13) {
-                    that.addFolder();
-                }
-            });
-
-            //this.checkSessionStorage();
-        });
-    }
-
-    /**
-     *
-     */
-    async checkSessionStorage() {
-        if (sessionStorage.getItem("nextcloud-webdav-username") && sessionStorage.getItem("nextcloud-webdav-password")) {
-            this.webDavClient = createClient(
-                this.webDavUrl + "/" + sessionStorage.getItem("nextcloud-webdav-username"),
-                {
-                    username: sessionStorage.getItem("nextcloud-webdav-username"),
-                    password: sessionStorage.getItem("nextcloud-webdav-password")
-                }
-            );
-            console.log("check");
-
-            this.loadDirectory(this.directoryPath);
-
-        }
-    }
-
-    /**
-     * check mime type of row
-     *
-     * @param data
-     * @param filterParams
-     */
-    checkFileType(data, filterParams) {
-        if (typeof data.mime === 'undefined') {
-            return true;
-        }
-        const [fileMainType, fileSubType] = data.mime.split('/');
-        const mimeTypes = filterParams.split(',');
-        let deny = true;
-
-        mimeTypes.forEach((str) => {
-            const [mainType, subType] = str.split('/');
-            deny = deny && ((mainType !== '*' && mainType !== fileMainType) || (subType !== '*' && subType !== fileSubType));
-        });
-
-        return !deny;
-    }
-
-    openFilePicker() {
-        if (this.webDavClient === null) {
-            this.loading = true;
-            this.statusText = i18n.t('nextcloud-file-picker.auth-progress');
-            const authUrl = this.authUrl + "?target-origin=" + encodeURIComponent(window.location.href);
-            this.loginWindow = window.open(authUrl, "Nextcloud Login",
-                "width=400,height=400,menubar=no,scrollbars=no,status=no,titlebar=no,toolbar=no");
-            //console.log("open nextcloud filepicker, no webdavclient");
-        } else {
-            this.loadDirectory(this.directoryPath, this.webDavClient);
-            //console.log("load in nextcloud webcomponent");
-        }
-    }
-
-    onReceiveWindowMessage(event) {
-        console.log("hui");
-        if (this.webDavClient === null) {
-            const data = event.data;
-
-            if (data.type === "webapppassword") {
-                if (this.loginWindow !== null) {
-                    this.loginWindow.close();
-                }
-                console.log("lala");
-
-                // see https://github.com/perry-mitchell/webdav-client/blob/master/API.md#module_WebDAV.createClient
-                this.webDavClient = createClient(
-                    data.webdavUrl || this.webDavUrl + "/" + data.loginName,
-                    {
-                        username: data.loginName,
-                        password: data.token
-                    }
-                );
-                console.log("tada");
-
-                if (this._("#remember-checkbox") && this._("#remember-checkbox").checked) {
-                    sessionStorage.setItem('nextcloud-webdav-username', data.loginName);
-                    sessionStorage.setItem('nextcloud-webdav-password', data.token);
-                    console.log("saved");
-
-                }
-                this.loadDirectory(this.directoryPath);
-            }
-        }
-    }
-
-    /**
-     * Loads the directory from WebDAV
-     *
-     * @param path
-     */
-    loadDirectory(path) {
-        if (typeof this.directoryPath === 'undefined' || this.directoryPath === undefined) {
-            this.directoryPath = '';
-        }
-        if (path === undefined) {
-            path = '';
-        }
-
-        // console.log("load nextcloud directory", path);
-        this.loading = true;
-        this.statusText = i18n.t('nextcloud-file-picker.loadpath-nextcloud-file-picker', {name: this.nextcloudName});
-        this.lastDirectoryPath = this.directoryPath;
-        this.directoryPath = path;
-        if (this._("#select_all"))
-            this._("#select_all").checked = false;
-
-        // see https://github.com/perry-mitchell/webdav-client#getdirectorycontents
-        if (this.webDavClient === null) {
-            // client is broken reload try to reset & reconnect
-            this.tabulatorTable.clearData();
-            this.webDavClient = null;
-            let reloadButton = html`${i18n.t('nextcloud-file-picker.something-went-wrong')}
-            <button class="button"
-                    title="${i18n.t('nextcloud-file-picker.refresh-nextcloud-file-picker')}"
-                    @click="${async () => {
-                        this.openFilePicker();
-                    }}">
-                <dbp-icon name="reload">
-            </button>`;
-            this.loading = false;
-            this.statusText = reloadButton;
-        }
-        this.webDavClient
-            .getDirectoryContents(path, {
-                details: true, data: "<?xml version=\"1.0\"?>" +
-                    "<d:propfind  xmlns:d=\"DAV:\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\"  xmlns:ocs=\"http://open-collaboration-services.org/ns\">" +
-                    "  <d:prop>" +
-                    "        <d:getlastmodified />" +
-                    "        <d:resourcetype />" +
-                    "        <d:getcontenttype />" +
-                    "        <d:getcontentlength />" +
-                    "        <d:getetag />" +
-                    "        <oc:permissions />" +
-                    "        <nc:acl-list>" +
-                    "           <nc:acl>" +
-                    "               <nc:acl-permissions />" +
-                    "           </nc:acl>" +
-                    "        </nc:acl-list>" +
-                    "  </d:prop>" +
-                    "</d:propfind>"
-            })
-            .then(contents => {
-                //console.log("------", contents);
-                this.loading = false;
-                this.statusText = "";
-                this.tabulatorTable.setData(contents.data);
-                this.isPickerActive = true;
-                this._(".nextcloud-content").scrollTop = 0;
-                if (!this.activeDirectoryRights.includes("CK") && !this.activeDirectoryRights.includes("NV")) {
-                    this._("#download-button").setAttribute("disabled", "true");
-                } else {
-                    this._("#download-button").removeAttribute("disabled");
-                }
-            }).catch(error => {
-            console.error(error.message);
-
-            // on Error: try to reload with home directory
-            if ((path !== "/" && path !== "") && this.webDavClient !== null && error.message.search("401") === -1) {
-                console.log("error in load directory");
-                this.directoryPath = "";
-                this.loadDirectory("");
-
-            } else {
-                this.loading = false;
-                this.statusText = html`<span
-                        class="error"> ${i18n.t('nextcloud-file-picker.webdav-error', {error: error.message})} </span>`;
-                this.isPickerActive = false;
-                this.tabulatorTable.clearData();
-                this.webDavClient = null;
-                let reloadButton = html`${i18n.t('nextcloud-file-picker.something-went-wrong')}
-                <button class="button"
-                        title="${i18n.t('nextcloud-file-picker.refresh-nextcloud-file-picker')}"
-                        @click="${async () => {
-                            this.openFilePicker();
-                        }}">
-                    <dbp-icon name="reload">
-                </button>`;
-                this.loading = false;
-                this.statusText = reloadButton;
-            }
-        });
-    }
-
-    /**
-     * Event Triggered when a directory in tabulator table is clicked
-     *
-     * @param event
-     * @param file
-     */
-    directoryClicked(event, file) {
-        // save rights of clicked directory
-        if (typeof file.props !== 'undefined') {
-            this.activeDirectoryRights = file.props.permissions;
-            if (typeof file.props['acl-list'] !== "undefined" &&
-                typeof file.props['acl-list']['acl']['acl-permissions'] !== "undefined" && file.props['acl-list']['acl']['acl-permissions']) {
-                this.activeDirectoryACL = file.props['acl-list']['acl']['acl-permissions'];
-            } else {
-                this.activeDirectoryACL = '';
-            }
-        } else {
-            this.activeDirectoryRights = 'SGDNVCK';
-        }
-        this.loadDirectory(file.filename);
-        event.preventDefault();
-    }
-
-    /**
-     * Download all files
-     *
-     * @param files
-     */
-    downloadFiles(files) {
-        files.forEach((fileData) => this.downloadFile(fileData));
-        this.tabulatorTable.deselectRow();
-        if (this._("#select_all")) {
-            this._("#select_all").checked = false;
-        }
-        const data = {"count": files.length};
-        const event = new CustomEvent("dbp-nextcloud-file-picker-number-files",
-            {"detail": data, bubbles: true, composed: true});
-        this.dispatchEvent(event);
-
-        if (files.length > 0) {
-            this.sendSetPropertyEvent(
-                'analytics-event',
-                {category: 'FileHandlingNextcloud', action: 'DownloadFiles', name: files.length});
-        }
-    }
-
-    /**
-     * Download a single file
-     *
-     * @param fileData
-     */
-    downloadFile(fileData) {
-        this.loading = true;
-        this.statusText = "Loading " + fileData.filename + "...";
-
-        // https://github.com/perry-mitchell/webdav-client#getfilecontents
-        this.webDavClient
-            .getFileContents(fileData.filename)
-            .then(contents => {
-                // create file to send via event
-                const file = new File([contents], fileData.basename, {type: fileData.mime});
-                // send event
-                const data = {"file": file, "data": fileData};
-                const event = new CustomEvent("dbp-nextcloud-file-picker-file-downloaded",
-                    {"detail": data, bubbles: true, composed: true});
-                this.dispatchEvent(event);
-                this.loading = false;
-                this.statusText = "";
-            }).catch(error => {
-            console.error(error.message);
-            this.loading = false;
-            this.statusText = html`<span
-                    class="error"> ${i18n.t('nextcloud-file-picker.webdav-error', {error: error.message})} </span>`;
-        });
-    }
-
-    /**
-     * Send the directory to filesink
-     *
-     * @param directory
-     */
-    sendDirectory(directory) {
-        this.tabulatorTable.deselectRow();
-        let path;
-
-        if (!directory[0]) {
-            path = this.directoryPath;
-        } else {
-            path = directory[0].filename;
-        }
-        this.loading = true;
-        this.statusText = i18n.t('nextcloud-file-picker.upload-to', {path: path});
-
-        const event = new CustomEvent("dbp-nextcloud-file-picker-file-uploaded",
-            {"detail": path, bubbles: true, composed: true});
-        this.dispatchEvent(event);
-    }
-
-
-    /**
-     * Upload Files to a directory
-     *
-     * @param files
-     * @param directory
-     */
-    uploadFiles(files, directory) {
-        this.loading = true;
-        this.statusText = i18n.t('nextcloud-file-picker.upload-to', {path: directory});
-        this.fileList = files;
-        this.forAll = false;
-        this.setRepeatForAllConflicts();
-        this.uploadFile(directory);
-
-        if (files.length > 0) {
-            this.sendSetPropertyEvent(
-                'analytics-event',
-                {category: 'FileHandlingNextcloud', action: 'UploadFiles', name: files.length});
-        }
-    }
-
-    /**
-     * Upload a single file from this.filelist to given directory
-     *
-     * @param directory
-     */
-    async uploadFile(directory) {
-        if (this.abortUpload) {
-            this.abortUpload = false;
-            this.abortUploadButton = false;
-            this.forAll = false;
-            this.loading = false;
-            this.statusText = i18n.t('nextcloud-file-picker.abort-message');
-            this._("#replace_mode_all").checked = false;
-            return;
-        }
-        if (this.fileList.length !== 0) {
-            let file = this.fileList[0];
-            this.replaceFilename = file.name;
-            let path = directory + "/" + file.name;
-            // https://github.com/perry-mitchell/webdav-client#putfilecontents
-            let that = this;
-            this.loading = true;
-            this.statusText = i18n.t('nextcloud-file-picker.upload-to', {path: path});
-            await this.webDavClient
-                .putFileContents(path, file, {
-                    overwrite: false, onUploadProgress: progress => {
-                        /* console.log(`Uploaded ${progress.loaded} bytes of ${progress.total}`);*/
-                    }
-                }).then(function () {
-                    that.uploadCount += 1;
-                    that.fileList.shift();
-                    that.uploadFile(directory);
-                }).catch(error => {
-                    if (error.message.search("412") !== -1 || error.message.search("403") !== -1) {
-                        this.generatedFilename = this.getNextFilename();
-                        this._("#replace-filename").value = this.generatedFilename;
-                        if (this.forAll) {
-                            this.uploadFileObject = file;
-                            this.uploadFileDirectory = directory;
-                            this.abortUploadButton = true;
-                            this.uploadFileAfterConflict();
-                        } else {
-                            this.replaceModalDialog(file, directory);
-                        }
-                    }
-                });
-        } else {
-            this.loadDirectory(this.directoryPath);
-            this.loading = false;
-            this.statusText = "";
-            this._("#replace_mode_all").checked = false;
-            this.forAll = false;
-            this.customFilename = '';
-            const event = new CustomEvent("dbp-nextcloud-file-picker-file-uploaded-finished",
-                {bubbles: true, composed: true, detail: this.uploadCount});
-            this.uploadCount = 0;
-            this.abortUpload = false;
-            this.abortUploadButton = false;
-            this.dispatchEvent(event);
-
-        }
-    }
-
-    /**
-     * Upload a file after a conflict happens on webdav side
-     *
-     */
-    async uploadFileAfterConflict() {
-        if (this.abortUpload) {
-            this.abortUpload = false;
-            this.abortUploadButton = false;
-            this.forAll = false;
-            this.loading = false;
-            this.statusText = i18n.t('nextcloud-file-picker.abort-message');
-            this._("#replace_mode_all").checked = false;
-            return;
-        }
-        let path = "";
-        let overwrite = false;
-        let file = this.uploadFileObject;
-        let directory = this.uploadFileDirectory;
-
-        if (this._("input[name='replacement']:checked").value === "ignore") {
-            MicroModal.close(this._("#replace-modal"));
-            this.forAll ? this.fileList = [] : this.fileList.shift();
-            this.uploadFile(directory);
-            return true;
-        } else if (this._("input[name='replacement']:checked").value === "new-name") {
-            if (this.generatedFilename !== this._("#replace-filename").value) {
-                this.customFilename = this._("#replace-filename").value;
-            }
-            path = directory + "/" + this._("#replace-filename").value;
-            MicroModal.close(this._("#replace-modal"));
-            this.replaceFilename = this._("#replace-filename").value;
-        } else {
-            path = directory + "/" + this.uploadFileObject.name;
-            overwrite = true;
-        }
-
-        this.loading = true;
-        this.statusText = i18n.t('nextcloud-file-picker.upload-to', {path: path});
-
-        let that = this;
-        // https://github.com/perry-mitchell/webdav-client#putfilecontents
-        await this.webDavClient
-            .putFileContents(path, file, {
-                overwrite: overwrite, onUploadProgress: progress => {
-                    /*console.log(`Uploaded ${progress.loaded} bytes of ${progress.total}`);*/
-                }
-            }).then(content => {
-                MicroModal.close(this._("#replace-modal"));
-                this.uploadCount += 1;
-                that.fileList.shift();
-                that.uploadFile(directory);
-            }).catch(error => {
-                if (error.message.search("412") !== -1) {
-                    MicroModal.close(that._("#replace-modal"));
-                    this.generatedFilename = this.getNextFilename();
-                    this._("#replace-filename").value = this.generatedFilename;
-                    if (this.forAll) {
-                        this.uploadFileObject = file;
-                        this.uploadFileDirectory = directory;
-                        this.abortUploadButton = true;
-                        this.uploadFileAfterConflict();
-                    } else {
-                        this.replaceModalDialog(file, directory);
-                    }
-                }
-            });
-
-        this.fileNameCounter = 1;
-    }
-
-    /**
-     * Check permissions of a given file in the active directory
-     * no rename: if you dont have create permissions
-     * no replace: if you dont have write permissions
-     *
-     * R = Share, S = Shared Folder, M = Group folder or external source, G = Read, D = Delete, NV / NVW = Write, CK = Create
-     *
-     * @param file
-     * @returns {number}
-     */
-    checkRights(file) {
-
-        // nextcloud permissions
-        let file_perm = 0;
-        let active_directory_perm = this.activeDirectoryRights;
-        let rows = this.tabulatorTable.searchRows("basename", "=", this.replaceFilename);
-        if (typeof rows[0] !== 'undefined' && rows[0]) {
-            file_perm = rows[0].getData().props.permissions;
-        } else {
-            file_perm = "";
-        }
-
-        /* ACL permissions: If ACL > permssions comment this in
-        if (this.activeDirectoryACL !== '') {
-            console.log("ACL SET");
-            active_directory_perm = "MG";
-            if (this.activeDirectoryACL & (1 << (3 - 1))) {
-                active_directory_perm = "CK";
-                console.log("ACL CREATE");
-            }
-            if (this.activeDirectoryACL & (1 << (2 - 1))) {
-                active_directory_perm += "NV";
-                console.log("ACL WRITE");
-            }
-        }
-
-        // if file has acl rights take that
-        if (typeof rows[0].getData().props['acl-list'] !== 'undefined' && rows[0].getData().props['acl-list'] &&
-            rows[0].getData().props['acl-list']['acl']['acl-permissions'] !== '') {
-            console.log("FILE HAS ACL");
-            file_perm = "MG";
-
-            if (rows[0].getData().props['acl-list']['acl']['acl-permissions'] & (1 << (3 - 1))) {
-                file_perm = "CK";
-                console.log("FILE ACL CREATE");
-            }
-            if (rows[0].getData().props['acl-list']['acl']['acl-permissions'] & (1 << (2 - 1))) {
-                file_perm += "NV";
-                console.log("FILE ACL WRITE");
-            }
-        }
-        */
-
-        // all allowed
-        if (active_directory_perm.includes("CK") && file_perm.includes("NV")) {
-            return -1;
-        }
-
-        // read only file but you can write to directory = only create and no edit
-        if (active_directory_perm.includes("CK") && !file_perm.includes("NV")) {
-            return 1;
-        }
-
-        // only edit and no create
-        if (!active_directory_perm.includes("CK") && file_perm.includes("NV")) {
-            return 2;
-        }
-
-        // read only directory and read only file
-        return 0;
-
-    }
-
-    /**
-     * Open the replace Modal Dialog with gui where forbidden actions are disabled
-     *
-     * @param file
-     * @param directory
-     */
-    replaceModalDialog(file, directory) {
-        this.uploadFileObject = file;
-        this.uploadFileDirectory = directory;
-        let rights = this.checkRights(file);
-        // read only directory or read only file
-        if (rights === 0) {
-            this.loading = false;
-            this.statusText = i18n.t('nextcloud-file-picker.readonly');
-            return;
-        }
-        // read only file but you can write to directory = only create and no edit
-        else if (rights === 1) {
-            this.loading = false;
-            this.statusText = i18n.t('nextcloud-file-picker.onlycreate');
-            this._("#replace-replace").setAttribute("disabled", "true");
-            this._("#replace-new-name").removeAttribute("disabled");
-            this._("#replace-replace").checked = false;
-            this._("#replace-new-name").checked = true;
-            this.setInputFieldVisibility();
-            this._("#replace-new-name").focus();
-        }
-        // only edit and no create
-        else if (rights === 2) {
-            this.loading = false;
-            this.statusText = i18n.t('nextcloud-file-picker.onlyedit');
-            this._("#replace-new-name").setAttribute("disabled", "true");
-            this._("#replace-replace").removeAttribute("disabled");
-            this._("#replace-new-name").checked = false;
-            this._("#replace-replace").checked = true;
-            this.setInputFieldVisibility();
-            this._("#replace-replace").focus();
-        }
-        // all allowed
-        else {
-            this._("#replace-new-name").removeAttribute("disabled");
-            this._("#replace-replace").removeAttribute("disabled");
-            this._("#replace-replace").checked = false;
-            this._("#replace-new-name").checked = true;
-            this.setInputFieldVisibility();
-            this._("#replace-new-name").focus();
-        }
-        MicroModal.show(this._('#replace-modal'), {
-            disableScroll: true,
-            onClose: modal => {
-                this.statusText = "";
-                this.loading = false;
-            },
-        });
-    }
-
-    closeDialog(e) {
-        if (this.tabulatorTable) {
-            this.tabulatorTable.deselectRow();
-        }
-        if (this._("#select_all")) {
-            this._("#select_all").checked = false;
-        }
-        MicroModal.close(this._('#modal-picker'));
-    }
-
-    /**
-     * Returns a filename with the next counter number.
-     *
-     * @returns {string} The next filename
-     */
-    getNextFilename() {
-        let nextFilename = "";
-        let splitFilename;
-        if (this.forAll && this.customFilename !== '') {
-            splitFilename = this.customFilename.split(".");
-        } else {
-            splitFilename = this.replaceFilename.split(".");
-        }
-
-        let splitBracket = splitFilename[0].split('(');
-        if (splitBracket.length > 1) {
-            let numberString = splitBracket[1].split(')');
-            if (numberString.length > 1 && !isNaN(parseInt(numberString[0]))) {
-                let number = parseInt(numberString[0]);
-                this.fileNameCounter = number + 1;
-                nextFilename = splitBracket[0] + "(" + this.fileNameCounter + ")";
-            } else {
-                nextFilename = splitFilename[0] + "(" + this.fileNameCounter + ")";
-            }
-        } else {
-            nextFilename = splitFilename[0] + "(" + this.fileNameCounter + ")";
-        }
-        if (splitFilename.length > 1) {
-            for (let i = 1; i < splitFilename.length; i++) {
-                nextFilename = nextFilename + "." + splitFilename[i];
-            }
-        }
-        this.fileNameCounter++;
-        return nextFilename;
-    }
-
-    /**
-     * Disables or enables the input field for the new file name
-     */
-    setInputFieldVisibility() {
-        this._("#replace-filename").disabled = !this._("#replace-new-name").checked;
-    }
-
-    /**
-     * Returns text for the cancel button depending on number of files
-     *
-     * @returns {string} correct cancel text
-     */
-    getCancelText() {
-        if (this.fileList.length > 1) {
-            return i18n.t('nextcloud-file-picker.replace-cancel-all');
-        }
-        return i18n.t('nextcloud-file-picker.replace-cancel');
-    }
-
-    /**
-     *
-     */
-    cancelOverwrite() {
-        this.statusText = "";
-        this.loading = false;
-        this.fileList = [];
-    }
-
-    /**
-     *
-     */
-    setRepeatForAllConflicts() {
-        this.forAll = this._("#replace_mode_all").checked;
-    }
-
-    /**
-     * Add new folder with webdav
-     *
-     */
-    openAddFolderDialogue() {
-        if (this._('.addRowAnimation')) {
-            this._('.addRowAnimation').classList.remove('addRowAnimation');
-        }
-        this._('#new-folder-wrapper').classList.toggle('hidden');
-        if (this._('#new-folder-wrapper').classList.contains('hidden')) {
-            this._('#add-folder-button').setAttribute("name", "plus");
-            this._('#add-folder-button').setAttribute("title", i18n.t('nextcloud-file-picker.add-folder-open'));
-        } else {
-            this._('#add-folder-button').setAttribute("name", "close");
-            this._('#add-folder-button').setAttribute("title", i18n.t('nextcloud-file-picker.add-folder-close'));
-            this._('#new-folder').focus();
-        }
-    }
-
-    /**
-     * Add new folder with webdav
-     *
-     */
-    addFolder() {
-        if (this._('#new-folder').value !== "") {
-            let folderName = this._('#new-folder').value;
-            if (typeof this.directoryPath === 'undefined') {
-                this.directoryPath = '';
-            }
-            let folderPath = this.directoryPath + "/" + folderName;
-            this.webDavClient.createDirectory(folderPath).then(contents => {
-                // this.loadDirectory(this.directoryPath);
-                const d = new Date();
-                let props = {permissions: 'RGDNVCK'};
-                this.tabulatorTable.addRow({
-                    type: "directory",
-                    filename: folderPath,
-                    basename: folderName,
-                    lastmod: d,
-                    props: props
-                }, true);
-                this.statusText = i18n.t('nextcloud-file-picker.add-folder-success', {folder: folderName});
-                this.loading = false;
-            }).catch(error => {
-                this.loading = false;
-                if (error.message.search("405") !== -1) {
-                    this.statusText = html`<span
-                            class="error"> ${i18n.t('nextcloud-file-picker.add-folder-error', {folder: folderName})} </span>`;
-                } else {
-                    this.statusText = html`<span
-                            class="error"> ${i18n.t('nextcloud-file-picker.webdav-error', {error: error.message})} </span>`;
-                }
-            });
-
-            this._('#new-folder').value = '';
-            this.openAddFolderDialogue();
-        }
-    }
-
-    /**
-     * Select or deselect all files from tabulator table
-     *
-     */
-    selectAllFiles() {
-        let allSelected = this.checkAllSelected();
-        if (allSelected) {
-            this.tabulatorTable.getSelectedRows().forEach(row => row.deselect());
-        } else {
-            this.tabulatorTable.selectRow(this.tabulatorTable.getRows().filter(row => row.getData().type != 'directory' && this.checkFileType(row.getData(), this.allowedMimeTypes)));
-        }
-    }
-
-    checkAllSelected() {
-        if (this.tabulatorTable) {
-            let maxSelected = this.tabulatorTable.getRows().filter(row => row.getData().type != 'directory' && this.checkFileType(row.getData(), this.allowedMimeTypes)).length;
-            let selected = this.tabulatorTable.getSelectedRows().length;
-            if (selected === maxSelected) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns the parent directory path
-     *
-     * @returns {string} parent directory path
-     */
-    getParentDirectoryPath() {
-        if (typeof this.directoryPath === 'undefined') {
-            this.directoryPath = '';
-        }
-        let path = this.directoryPath.replace(/\/$/, "");
-        path = path.replace(path.split("/").pop(), "").replace(/\/$/, "");
-
-        return (path === "") ? "/" : path;
-    }
-
-    /**
-     * Returns the directory path as clickable breadcrumbs
-     *
-     * @returns {string} clickable breadcrumb path
-     */
-    getBreadcrumb() {
-        if (typeof this.directoryPath === 'undefined') {
-            this.directoryPath = '';
-        }
-        let htmlpath = [];
-        htmlpath[0] = html`<span class="breadcrumb"><a class="home-link" @click="${() => {
-            this.loadDirectory("");
-        }}" title="${i18n.t('nextcloud-file-picker.folder-home')}"><dbp-icon name="home"></dbp-icon> </a></span>`;
-        const directories = this.directoryPath.split('/');
-        if (directories[1] === "") {
-            return htmlpath;
-        }
-        for (let i = 1; i < directories.length; i++) {
-            let path = "";
-            for (let j = 1; j <= i; j++) {
-                path += "/";
-                path += directories[j];
-            }
-
-            htmlpath[i] = html`<span> › </span><span class="breadcrumb"><a @click="${() => {
-                this.loadDirectory(path);
-            }}" title="${i18n.t('nextcloud-file-picker.load-path-link', {path: directories[i]})}">${directories[i]}</a></span>`;
-        }
-
-        return htmlpath;
-    }
-
-    /**
-     * Returns Link to Nextcloud with actual directory
-     *
-     * @returns {string} actual directory Nextcloud link
-     */
-    getNextCloudLink() {
-        return this.nextcloudFileURL + this.directoryPath;
-    }
-
-    static get styles() {
-        // language=css
-        return css`
-            ${commonStyles.getGeneralCSS()}
-            ${commonStyles.getButtonCSS()}
-            ${commonStyles.getTextUtilities()}
-            ${commonStyles.getModalDialogCSS()}
-            ${commonStyles.getRadioAndCheckboxCss()}
-            ${fileHandlingStyles.getFileHandlingCss()}
-            .visible {
-                display: unset;
-            }
-
-            .block {
-                margin-bottom: 10px;
-            }
-
-            .error {
-                color: var(--dbp-danger-bg-color);
-            }
-
-
-            .nextcloud-header {
-                margin-bottom: 2rem;
-                display: inline-grid;
-                width: 100%;
-                grid-template-columns: auto auto;
-            }
-
-            .nextcloud-header div button {
-                justify-self: start;
-            }
-
-            .nextcloud-intro {
-                text-align: center;
-            }
-
-            .nextcloud-logo {
-                width: 80px;
-                height: 95px;
-                justify-self: end;
-                transition: all 0.5s ease;
-                margin: auto;
-            }
-
-            .nextcloud-logo-image {
-                height: 100%;
-                width: 100%;
-                background-image: var(--dbp-override-image-nextcloud, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath d='M69.3 86.1l-46.1 0C11 85.9 1.1 75.9 1.1 63.7c0-11.8 9.1-21.4 20.6-22.4 0.5-15.2 13-27.4 28.3-27.4 3.4 0 6.6 0.5 9.2 1.6 6.2 2.1 11.4 6.4 14.8 12 6.5 1 12.7 4.3 16.9 9.1 5 5.5 7.8 12.6 7.8 19.9C98.8 72.8 85.6 86.1 69.3 86.1zM23.6 80.6h45.7c13.3 0 24-10.8 24-24 0-6-2.3-11.8-6.4-16.2 -3.7-4.2-9.1-6.9-14.9-7.5l-1.4-0.2L70 31.4c-2.8-5.1-7.2-8.9-12.6-10.7l-0.1 0c-2-0.8-4.5-1.2-7.2-1.2 -12.6 0-22.9 10.3-22.9 22.9v4.5h-3.6c-9.3 0-17 7.6-17 17C6.6 73 14.3 80.6 23.6 80.6z'/%3E%3C/svg%3E"));
-                background-repeat: no-repeat;
-                background-position: center;
-            }
-
-            .nextcloud-logo-sm {
-                width: 40px;
-                justify-self: inherit;
-                margin-right: 70px;
-                display: none;
-            }
-
-            .m-inherit {
-                margin: inherit;
-            }
-
-            .wrapper {
-                width: 100%;
-                height: 100%;
-                display: flex;
-                flex-direction: column;
-                justify-content: center;
-                position: relative;
-            }
-
-            .wrapper-select {
-                justify-content: inherit;
-            }
-
-            .select-button {
-                justify-self: end;
-                justify-self: end;
-            }
-
-            .nextcloud-content {
-                width: 100%;
-                height: 100%;
-                overflow-y: auto;
-                -webkit-overflow-scrolling: touch;
-            }
-
-
-            .nextcloud-nav {
-                display: flex;
-                justify-content: space-between;
-            }
-
-
-            .nextcloud-footer {
-                background-color: white;
-                width: 100%;
-                padding-top: 10px;
-            }
-
-            .nextcloud-footer-grid {
-                width: 100%;
-                display: flex;
-                align-items: center;
-                flex-direction: row-reverse;
-                justify-content: space-between;
-            }
-
-
-            .add-folder {
-                white-space: nowrap;
-                align-self: end;
-                height: 33px;
-            }
-
-            .nextcloud-nav p {
-                align-self: center;
-            }
-
-            #replace-modal-box {
-                display: flex;
-                flex-direction: column;
-                justify-content: center;
-                padding: 30px;
-                max-height: 450px;
-                min-height: 450px;
-                min-width: 380px;
-                max-width: 190px;
-            }
-
-            #replace-modal-box .modal-header {
-                display: flex;
-                justify-content: space-evenly;
-                align-items: baseline;
-            }
-
-            #replace-modal-box .modal-header h2 {
-                font-size: 1.2rem;
-                padding-right: 5px;
-            }
-
-            #replace-modal-box .modal-content {
-                display: flex;
-                flex-direction: column;
-                height: 100%;
-                justify-content: space-evenly;
-            }
-
-            #replace-modal-box .radio-btn {
-                margin-right: 5px;
-            }
-
-            #replace-modal-box .modal-content label {
-                display: block;
-                width: 100%;
-                text-align: left;
-            }
-
-            #replace-modal-box #replace-filename {
-                display: block;
-                width: 100%;
-                margin-top: 8px;
-            }
-
-            #replace-modal-box input[type="text"]:disabled {
-                color: #aaa;
-            }
-
-            #replace-modal-box .modal-content div {
-                display: flex;
-            }
-
-            #replace-modal-box .modal-footer {
-                padding-top: 15px;
-            }
-
-            #replace-modal-box .modal-footer .modal-footer-btn {
-                display: flex;
-                justify-content: space-between;
-                padding-bottom: 15px;
-            }
-
-            .breadcrumb {
-                border-bottom: 1px solid black;
-            }
-
-            .breadcrumb:last-child, .breadcrumb:first-child {
-                border-bottom: none;
-            }
-
-            .breadcrumb a {
-                display: inline-block;
-                height: 33px;
-                vertical-align: middle;
-                line-height: 33px;
-
-            }
-
-            input:disabled + label {
-                color: #aaa;
-            }
-
-            .inline-block {
-                display: inline-block;
-            }
-
-            .nextcloud-nav h2 {
-                padding-top: 10px;
-            }
-
-            .no-select, .tabulator-row.tabulator-selected.no-select:hover, .tabulator-row.no-select:hover, .tabulator-row.tabulator-selectable.no-select:hover {
-                cursor: unset;
-                color: #333;
-                background-color: white;
-            }
-
-            .nextcloud-nav {
-                position: relative;
-            }
-
-            .inline-block {
-                position: absolute;
-                right: 0px;
-                z-index: 1;
-                background-color: white;
-                bottom: -45px;
-            }
-
-            .addRowAnimation {
-                animation: added 0.4s ease;
-            }
-
-            #abortButton {
-                color: var(--dbp-danger-bg-color);
-            }
-
-            #abortButton:hover {
-                color: white;
-            }
-
-            @keyframes added {
-                0% {
-                    background-color: white;
-                }
-                50% {
-                    background-color: var(--dbp-success-bg-color);
-                }
-                100% {
-                    background-color: white;
-                }
-            }
-
-            .spinner {
-                font-size: 0.7em;
-            }
-
-            .nextcloud-picker-icon-disabled {
-                opacity: 0.4;
-            }
-
-            .button.button, .button, button.dt-button {
-                background-color: white;
-            }
-
-            #new-folder {
-                padding-right: 50px;
-            }
-
-            .nextcloud-nav a {
-                white-space: nowrap;
-                overflow: hidden;
-                text-overflow: ellipsis;
-                max-width: 130px;
-            }
-
-            #replace-modal-box .modal-header {
-                padding: 0px;
-            }
-
-            #replace-modal-content {
-                padding: 0px;
-                align-items: baseline;
-            }
-
-            #replace-modal-box .modal-header h2 {
-                text-align: left;
-            }
-
-            .table-wrapper {
-                position: relative;
-            }
-
-            .button-container .checkmark::after {
-                left: 8px;
-                top: 3px;
-                width: 4px;
-                height: 11px;
-            }
-
-            .select-all-icon {
-                height: 30px;
-            }
-
-            .checkmark {
-                height: 20px;
-                width: 20px;
-                left: 11px;
-                top: 4px;
-            }
-            
-            #replace-modal .checkmark {
-                height: 20px;
-                width: 20px;
-                left: 1px;
-                top: 0px;
-            }
-            
-            .remember-container{
-                display: inline-block;
-                line-height: 28px;
-                padding-left: 44px;
-            }
-
-
-            @media only screen
-            and (orientation: portrait)
-            and (max-width: 768px) {
-                .add-folder button {
-                    float: right;
-                }
-
-                .add-folder {
-                    position: absolute;
-                    right: 0px;
-                }
-
-                .nextcloud-nav {
-                    display: block;
-                }
-
-                .add-folder {
-                    position: inherit;
-                }
-
-                .inline-block {
-                    width: inherit;
-                    position: absolute;
-                    right: 52px;
-                    z-index: 1;
-                    background-color: white;
-                    bottom: 0px;
-                }
-
-                .add-folder-button {
-                    right: 0px;
-                    position: absolute;
-                }
-
-                .nextcloud-nav h2 > a {
-                    font-size: 1.3rem;
-                }
-
-                .nextcloud-nav h2 {
-                    padding-top: 8px;
-                }
-
-                .nextcloud-nav a {
-                    font-size: 1rem;
-                }
-
-                .nextcloud-nav .home-link {
-                    font-size: 1.2rem;
-                }
-
-                .nextcloud-logo-sm {
-                    display: none;
-                }
-
-                .nextcloud-logo {
-                    margin: 0 auto;
-                }
-
-
-                .button-wrapper {
-                    justify-self: start;
-                }
-
-                .wrapper {
-                    display: flex;
-                    justify-content: space-between;
-                }
-
-                .nextcloud-header {
-                    grid-area: header-l;
-                    margin-bottom: 0px;
-                }
-
-                .nextcloud-content, .nextcloud-intro {
-                    grid-area: content;
-                    height: 100%;
-                    justify-content: center;
-                }
-
-                .nextcloud-intro {
-                    text-align: center;
-                    display: flex;
-                    flex-direction: column;
-                }
-
-                .nextcloud-footer {
-                    bottom: 0px;
-                    width: 100%;
-                    left: 0px;
-                }
-
-                .mobile-hidden {
-                    display: none;
-                }
-
-                .info-box {
-                    position: relative;
-                }
-
-                .nextcloud-footer-grid {
-                    display: flex;
-                    justify-content: center;
-                    flex-direction: column-reverse;
-                }
-
-                .select-button {
-                    margin: 0px;
-                }
-
-                #new-folder {
-                    width: 100%;
-                }
-
-                #replace-modal-box {
-                    min-width: 100%;
-                    max-width: 100%;
-                }
-
-                .hidden {
-                    display: none;
-                }
-
-                .button-container .checkmark::after {
-                    left: 8px;
-                    top: 2px;
-                    width: 8px;
-                    height: 15px;
-                }
-
-                .select-all-icon {
-                    height: 32px;
-                }
-
-                .checkmark {
-                    height: 25px;
-                    width: 25px;
-                    left: 9px;
-                    top: 2px;
-                }
-
-            }
-        `;
-    }
-
-    render() {
-        const tabulatorCss = commonUtils.getAssetURL(pkgName, 'tabulator-tables/css/tabulator.min.css');
-
-        return html`
-            <div class="wrapper">
-                <link rel="stylesheet" href="${tabulatorCss}">
-                <div class="nextcloud-intro ${classMap({hidden: this.isPickerActive})}">
-                    <div class="nextcloud-logo ${classMap({"nextcloud-logo-sm": this.isPickerActive})}">
-                        <div class="nextcloud-logo-image"></div>
-                    </div>
-                    <div class="block text-center ${classMap({hidden: this.isPickerActive})}">
-                        <h2 class="m-inherit">
-                            ${this.nextcloudName}
-                        </h2>
-                        <p class="m-inherit">
-                            ${i18n.t('nextcloud-file-picker.init-text-1', {name: this.nextcloudName})} <br>
-                            ${i18n.t('nextcloud-file-picker.init-text-2')} <br><br>
-
-                        </p>
-                    </div>
-                    <div class="block ${classMap({hidden: this.isPickerActive})}">
-                        <button class="button  is-primary"
-                                title="${i18n.t('nextcloud-file-picker.open-nextcloud-file-picker', {name: this.nextcloudName})}"
-                                @click="${async () => {
-                                    this.openFilePicker();
-                                }}">${i18n.t('nextcloud-file-picker.connect-nextcloud', {name: this.nextcloudName})}
-                        </button>
-                    </div>
-                    <div class="block text-center m-inherit ${classMap({hidden: this.isPickerActive})}">
-                        <label class="button-container remember-container">
-                            Remember me
-                            <input type="checkbox" id="remember-checkbox" name="remember">
-                            <span class="checkmark"></span>
-                        </label>
-                    </div>
-                    <div class="block text-center m-inherit ${classMap({hidden: this.isPickerActive})}">
-                        <p class="m-inherit"><br>
-                            ${i18n.t('nextcloud-file-picker.auth-info')}
-                            <slot name="auth-info"><br/>${this.authInfo}</slot>
-                        </p>
-                        
-                    </div>
-                </div>
-                <div class="nextcloud-content ${classMap({hidden: !this.isPickerActive})}">
-                    <div class="nextcloud-nav">
-                        <p>${this.getBreadcrumb()}</p>
-                        <div class="add-folder ${classMap({hidden: !this.directoriesOnly})}">
-                            <div class="inline-block">
-                                <div id="new-folder-wrapper" class="hidden">
-                                    <input type="text"
-                                           placeholder="${i18n.t('nextcloud-file-picker.new-folder-placeholder')}"
-                                           name="new-folder" class="input" id="new-folder"/>
-                                    <button class="button add-folder-button"
-                                            title="${i18n.t('nextcloud-file-picker.add-folder')}"
-                                            @click="${() => {
-                                                this.addFolder();
-                                            }}">
-                                        <dbp-icon name="checkmark-circle" class="nextcloud-add-folder"></dbp-icon>
-                                    </button>
-                                </div>
-                            </div>
-                            <button class="button"
-                                    title="${i18n.t('nextcloud-file-picker.add-folder-open')}"
-                                    @click="${() => {
-                                        this.openAddFolderDialogue();
-                                    }}">
-                                <dbp-icon name="plus" class="nextcloud-add-folder" id="add-folder-button"></dbp-icon>
-                            </button>
-                        </div>
-
-                    </div>
-                    <div class="table-wrapper">
-                        <table id="directory-content-table" class="force-no-select"></table>
-                    </div>
-                </div>
-
-                <div class="nextcloud-footer ${classMap({hidden: !this.isPickerActive})}">
-                    <div class="nextcloud-footer-grid">
-                        <button id="download-button"
-                                class="button select-button is-primary ${classMap({hidden: ((!this.directoriesOnly) || (this.directoriesOnly && this.abortUploadButton && this.forAll))})}"
-                                @click="${() => {
-                                    this.sendDirectory(this.tabulatorTable.getSelectedData());
-                                }}"
-                                ?disabled="${this.selectBtnDisabled}">
-                            <dbp-icon class="nav-icon" name="cloud-upload"></dbp-icon>
-                            ${this.folderIsSelected}
-                        </button>
-                        <button class="button select-button is-primary ${classMap({hidden: this.directoriesOnly})}"
-                                @click="${() => {
-                                    this.downloadFiles(this.tabulatorTable.getSelectedData());
-                                }}"
-                                ?disabled="${this.selectBtnDisabled}">
-                            ${(this.tabulatorTable && this.tabulatorTable.getSelectedRows().filter(row => row.getData().type != 'directory' && this.checkFileType(row.getData(), this.allowedMimeTypes)).length === 0) ? i18n.t('nextcloud-file-picker.select-files') : i18n.t('nextcloud-file-picker.select-files-btn', {count: this.tabulatorTable ? this.tabulatorTable.getSelectedRows().length : 0})}
-                        </button>
-                        <button id="abortButton"
-                                class="button select-button hidden ${classMap({"visible": (this.directoriesOnly && this.forAll && this.abortUploadButton)})}"
-                                title="${i18n.t('nextcloud-file-picker.abort')}" @click="${() => {
-                            this.abortUpload = true;
-                        }}">${i18n.t('nextcloud-file-picker.abort')}
-                        </button>
-
-                        <div class="block info-box ${classMap({hidden: this.statusText === ""})}">
-                            <dbp-mini-spinner
-                                    class="spinner ${classMap({hidden: this.loading === false})}"></dbp-mini-spinner>
-                            <span>${this.statusText}</span>
-                        </div>
-
-                    </div>
-                </div>
-            </div>
-
-            <div class="modal micromodal-slide" id="replace-modal" aria-hidden="true">
-                <div class="modal-overlay" tabindex="-2" data-micromodal-close>
-                    <div class="modal-container" id="replace-modal-box" role="dialog" aria-modal="true"
-                         aria-labelledby="replace-modal-title">
-                        <header class="modal-header">
-                            <button title="${i18n.t('file-sink.modal-close')}" class="modal-close"
-                                    aria-label="Close modal" @click="${() => {
-                                this.closeDialog();
-                            }}">
-                                <dbp-icon title="${i18n.t('file-sink.modal-close')}" name="close"
-                                          class="close-icon"></dbp-icon>
-                            </button>
-                            <h2 id="replace-modal-title">
-                                ${i18n.t('nextcloud-file-picker.replace-title-1')}
-                                <span style="word-break: break-all;">${this.replaceFilename}</span>
-                                ${i18n.t('nextcloud-file-picker.replace-title-2')}.
-                            </h2>
-                        </header>
-                        <main class="modal-content" id="replace-modal-content">
-                            <h3>
-                                ${i18n.t('nextcloud-file-picker.replace-text')}?
-                            </h3>
-                            <div>
-                                <label class="button-container">
-                                    <span> 
-                                        ${i18n.t('nextcloud-file-picker.replace-new_name')}:
-
-                                    </span>
-                                    <input type="radio" id="replace-new-name" class="radio-btn" name="replacement"
-                                           value="new-name" checked @click="${() => {
-                                        this.setInputFieldVisibility();
-                                    }}">
-                                    <span class="radiobutton"></span>
-                                    <input type="text" id="replace-filename" class="input" name="replace-filename"
-                                           value="" onClick="this.select();">
-                                </label>
-
-                            </div>
-
-
-                            <div>
-                                <label class="button-container">
-                                    <span>${i18n.t('nextcloud-file-picker.replace-replace')}</span>
-                                    <input type="radio" id="replace-replace" name="replacement" value="replace"
-                                           @click="${() => {
-                                               this.setInputFieldVisibility();
-                                           }}">
-                                    <span class="radiobutton"></span>
-                                </label>
-                            </div>
-                            <div>
-                                <label class="button-container">
-                                    <span>${i18n.t('nextcloud-file-picker.replace-skip')}</span>
-                                    <input type="radio" class="radio-btn" name="replacement" value="ignore"
-                                           @click="${() => {
-                                               this.setInputFieldVisibility();
-                                           }}">
-                                    <span class="radiobutton"></span>
-                                </label>
-                            </div>
-                        </main>
-                        <footer class="modal-footer">
-                            <div class="modal-footer-btn">
-                                <button class="button" data-micromodal-close aria-label="Close this dialog window"
-                                        @click="${() => {
-                                            this.cancelOverwrite();
-                                        }}">${this.getCancelText()}
-                                </button>
-                                <button class="button select-button is-primary" @click="${() => {
-                                    this.uploadFileAfterConflict();
-                                }}">OK
-                                </button>
-                            </div>
-                            <div>
-                                <label class="button-container">
-                                    ${i18n.t('nextcloud-file-picker.replace-mode-all')}
-                                    <input type="checkbox" id="replace_mode_all" name="replace_mode_all"
-                                           value="replace_mode_all" @click="${() => {
-                                        this.setRepeatForAllConflicts();
-                                    }}">
-                                    <span class="checkmark"></span>
-                                </label>
-                            </div>
-                        </footer>
-                    </div>
-                </div>
-            </div>
-        `;
-    }
-}
+commonUtils.defineCustomElement('dbp-nextcloud-file-picker', NextcloudFilePicker);
diff --git a/packages/file-handling/src/file-sink.js b/packages/file-handling/src/file-sink.js
index 926d68c5..16b86316 100644
--- a/packages/file-handling/src/file-sink.js
+++ b/packages/file-handling/src/file-sink.js
@@ -5,7 +5,7 @@ import DBPLitElement from '@dbp-toolkit/common/dbp-lit-element';
 import * as commonUtils from "@dbp-toolkit/common/utils";
 import {Icon, MiniSpinner} from '@dbp-toolkit/common';
 import * as commonStyles from '@dbp-toolkit/common/styles';
-import {NextcloudFilePicker} from "./dbp-nextcloud-file-picker";
+import {NextcloudFilePicker} from "./nextcloud-file-picker";
 import {classMap} from 'lit-html/directives/class-map.js';
 import FileSaver from 'file-saver';
 import MicroModal from "./micromodal.es";
diff --git a/packages/file-handling/src/file-source.js b/packages/file-handling/src/file-source.js
index 32e6e62f..0a564b41 100644
--- a/packages/file-handling/src/file-source.js
+++ b/packages/file-handling/src/file-source.js
@@ -6,7 +6,7 @@ import * as commonUtils from "@dbp-toolkit/common/utils";
 import {Icon, MiniSpinner} from '@dbp-toolkit/common';
 import {send as notify} from '@dbp-toolkit/common/notification';
 import * as commonStyles from '@dbp-toolkit/common/styles';
-import {NextcloudFilePicker} from "./dbp-nextcloud-file-picker";
+import {NextcloudFilePicker} from "./nextcloud-file-picker";
 import {classMap} from 'lit-html/directives/class-map.js';
 import MicroModal from './micromodal.es';
 import * as fileHandlingStyles from './styles';
diff --git a/packages/file-handling/src/nextcloud-file-picker.js b/packages/file-handling/src/nextcloud-file-picker.js
new file mode 100644
index 00000000..65b7f12b
--- /dev/null
+++ b/packages/file-handling/src/nextcloud-file-picker.js
@@ -0,0 +1,1795 @@
+import {i18n} from './i18n';
+import {css, html} from 'lit-element';
+import {ScopedElementsMixin} from '@open-wc/scoped-elements';
+import DBPLitElement from '@dbp-toolkit/common/dbp-lit-element';
+import {Icon, MiniSpinner} from '@dbp-toolkit/common';
+import * as commonUtils from '@dbp-toolkit/common/utils';
+import * as commonStyles from '@dbp-toolkit/common/styles';
+import {createClient} from 'webdav/web';
+import {classMap} from 'lit-html/directives/class-map.js';
+import {humanFileSize} from '@dbp-toolkit/common/i18next';
+import Tabulator from 'tabulator-tables';
+import MicroModal from './micromodal.es';
+import {name as pkgName} from './../package.json';
+import * as fileHandlingStyles from './styles';
+
+/**
+ * NextcloudFilePicker web component
+ */
+export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
+    constructor() {
+        super();
+        this.lang = 'de';
+        this.authUrl = '';
+        this.webDavUrl = '';
+        this.nextcloudName = 'Nextcloud';
+        this.nextcloudFileURL = '';
+        this.loginWindow = null;
+        this.isPickerActive = false;
+        this.statusText = '';
+        this.lastDirectoryPath = '/';
+        this.directoryPath = '';
+        this.webDavClient = null;
+        this.tabulatorTable = null;
+        this.allowedMimeTypes = '*/*';
+        this.directoriesOnly = false;
+        this.maxSelectedItems = true;
+        this.loading = false;
+        this._onReceiveWindowMessage = this.onReceiveWindowMessage.bind(this);
+
+        this.folderIsSelected = i18n.t('nextcloud-file-picker.load-in-folder');
+        this.generatedFilename = '';
+        this.replaceFilename = '';
+        this.customFilename = '';
+        this.uploadFileObject = null;
+        this.uploadFileDirectory = null;
+        this.fileList = [];
+        this.fileNameCounter = 1;
+        this.activeDirectoryRights = 'RGDNVCK';
+        this.activeDirectoryACL = '';
+        this.forAll = false;
+        this.uploadCount = 0;
+        this.abortUploadButton = false;
+        this.abortUpload = false;
+        this.authInfo = '';
+        this.selectBtnDisabled = true;
+    }
+
+    static get scopedElements() {
+        return {
+            'dbp-icon': Icon,
+            'dbp-mini-spinner': MiniSpinner,
+        };
+    }
+
+    /**
+     * See: https://lit-element.polymer-project.org/guide/properties#initialize
+     */
+    static get properties() {
+        return {
+            ...super.properties,
+            lang: {type: String},
+            authUrl: {type: String, attribute: 'auth-url'},
+            webDavUrl: {type: String, attribute: 'web-dav-url'},
+            nextcloudFileURL: {type: String, attribute: 'nextcloud-file-url'},
+            nextcloudName: {type: String, attribute: 'nextcloud-name'},
+            isPickerActive: {type: Boolean, attribute: false},
+            statusText: {type: String, attribute: false},
+            folderIsSelected: {type: String, attribute: false},
+            authInfo: {type: String, attribute: 'auth-info'},
+            directoryPath: {type: String, attribute: 'directory-path'},
+            allowedMimeTypes: {type: String, attribute: 'allowed-mime-types'},
+            directoriesOnly: {type: Boolean, attribute: 'directories-only'},
+            maxSelectedItems: {type: Number, attribute: 'max-selected-items'},
+            loading: {type: Boolean, attribute: false},
+            replaceFilename: {type: String, attribute: false},
+            uploadFileObject: {type: Object, attribute: false},
+            uploadFileDirectory: {type: String, attribute: false},
+            activeDirectoryRights: {type: String, attribute: false},
+            activeDirectoryACL: {type: String, attribute: false},
+            abortUploadButton: {type: Boolean, attribute: false},
+            selectBtnDisabled: {type: Boolean, attribute: true},
+        };
+
+    }
+
+    update(changedProperties) {
+        changedProperties.forEach((oldValue, propName) => {
+            switch (propName) {
+                case "lang":
+                    i18n.changeLanguage(this.lang);
+                    break;
+                case "directoriesOnly":
+                    if (this.directoriesOnly && this._("#select_all_wrapper")) {
+                        this._("#select_all_wrapper").classList.remove("button-container");
+                        this._("#select_all_wrapper").classList.add("hidden");
+                    }
+                    if (!this.directoriesOnly && this._("#select_all_wrapper")) {
+                        this._("#select_all_wrapper").classList.add("button-container");
+                        this._("#select_all_wrapper").classList.remove("hidden");
+                    }
+            }
+        });
+
+        super.update(changedProperties);
+    }
+
+    disconnectedCallback() {
+        window.removeEventListener('message', this._onReceiveWindowMessage);
+        super.disconnectedCallback();
+    }
+
+    async firstUpdated() {
+        // Give the browser a chance to paint
+        await new Promise((r) => setTimeout(r, 0));
+        if (this._("#select_all")) {
+            let boundSelectHandler = this.selectAllFiles.bind(this);
+            this._("#select_all").addEventListener('click', boundSelectHandler);
+        }
+        if (this.directoriesOnly && this._("#select_all_wrapper")) {
+            this._("#select_all_wrapper").classList.remove("button-container");
+            this._("#select_all_wrapper").classList.add("hidden");
+        }
+
+    }
+
+    connectedCallback() {
+        super.connectedCallback();
+        const that = this;
+        this.updateComplete.then(() => {
+            // see: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
+            window.addEventListener('message', this._onReceiveWindowMessage);
+
+            // see: http://tabulator.info/docs/4.7
+            this.tabulatorTable = new Tabulator(this._("#directory-content-table"), {
+                layout: "fitColumns",
+                selectable: this.maxSelectedItems,
+                selectableRangeMode: "drag",
+                placeholder: this.directoriesOnly ? i18n.t('nextcloud-file-picker.no-data') : i18n.t('nextcloud-file-picker.no-data-type'),
+                responsiveLayout: "collapse",
+                responsiveLayoutCollapseStartOpen: false,
+                resizableColumns: false,
+                columns: [
+                    {
+                        formatter:"responsiveCollapse", width:32, minWidth:32, align:"center", resizable:false, headerSort:false},
+                    {
+                        title: '<label id="select_all_wrapper" class="button-container select-all-icon">' +
+                            '<input type="checkbox" id="select_all" name="select_all" value="select_all">' +
+                            '<span class="checkmark" id="select_all_checkmark"></span>' +
+                            '</label>',
+                        field: "type",
+                        align: "center",
+                        headerSort: false,
+                        width: 50,
+                        responsive: 1,
+                        formatter: (cell, formatterParams, onRendered) => {
+                            const icon_tag = that.getScopedTagName("dbp-icon");
+                            let disabled = this.directoriesOnly ? "nextcloud-picker-icon-disabled" : "";
+                            let icon = `<${icon_tag} name="empty-file" class="nextcloud-picker-icon ` + disabled + `"></${icon_tag}>`;
+                            return (cell.getValue() === "directory") ? `<${icon_tag} name="folder" class="nextcloud-picker-icon"></${icon_tag}>` : icon;
+                        }
+                    },
+                    {
+                        title: i18n.t('nextcloud-file-picker.filename'),
+                        responsive: 0,
+                        widthGrow: 5,
+                        minWidth: 150,
+                        field: "basename",
+                        sorter: "alphanum",
+                        formatter: (cell) => {
+                            var 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: 65,
+                        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: 35,
+                        field: "mime",
+                        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: 100,
+                        field: "lastmod",
+                        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 d = Date.parse(cell.getValue());
+                            const timestamp = new Date(d);
+                            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: "rights", field: "props.permissions", visible: false},
+                    {title: "acl", field: "props.acl-list.acl.acl-permissions", visible: false}
+                ],
+                initialSort: [
+                    {column: "basename", dir: "asc"},
+                    {column: "type", dir: "asc"},
+
+                ],
+                rowFormatter: (row) => {
+                    let data = row.getData();
+                    if (!this.checkFileType(data, this.allowedMimeTypes)) {
+                        row.getElement().classList.add("no-select");
+                        row.getElement().classList.remove("tabulator-selectable");
+                    }
+                    if (this.directoriesOnly && typeof data.mime !== 'undefined') {
+                        row.getElement().classList.add("no-select");
+                        row.getElement().classList.remove("tabulator-selectable");
+                    }
+                },
+                rowSelectionChanged: (data, rows) => {
+                    if (data.length > 0 && this.directoriesOnly) {
+                        this.folderIsSelected = i18n.t('nextcloud-file-picker.load-to-folder');
+                    } else {
+                        this.folderIsSelected = i18n.t('nextcloud-file-picker.load-in-folder');
+                    }
+                    if (this.tabulatorTable && this.tabulatorTable.getSelectedRows().filter(row => row.getData().type != 'directory' && this.checkFileType(row.getData(), this.allowedMimeTypes)).length > 0) {
+                        this.selectBtnDisabled = false;
+                    } else {
+                        this.selectBtnDisabled = true;
+                    }
+                    if (this._("#select_all_checkmark")) {
+                        this._("#select_all_checkmark").title = this.checkAllSelected() ? i18n.t('clipboard.select-nothing') : i18n.t('clipboard.select-all');
+                    }
+                    this.requestUpdate();
+                },
+                rowClick: (e, row) => {
+                    const data = row.getData();
+
+                    if (!row.getElement().classList.contains("no-select")) {
+                        if (this.directoriesOnly) {
+                            // comment out if you want to navigate through folders with double click
+                            const data = row.getData();
+                            this.directoryClicked(e, data);
+                            this.folderIsSelected = i18n.t('nextcloud-file-picker.load-in-folder');
+                        } else {
+                            switch (data.type) {
+                                case "directory":
+                                    this.directoryClicked(e, data);
+                                    break;
+                                case "file":
+                                    if (this.tabulatorTable !== null
+                                        && this.tabulatorTable.getSelectedRows().length === this.tabulatorTable.getRows().filter(row => row.getData().type != 'directory' && this.checkFileType(row.getData(), this.allowedMimeTypes)).length) {
+                                        this._("#select_all").checked = true;
+                                    } else {
+                                        this._("#select_all").checked = false;
+                                    }
+                                    break;
+                            }
+                        }
+                    } else {
+                        row.deselect();
+                    }
+                },
+                rowDblClick: (e, row) => {
+                    // comment this in for double click directory change
+                    /* if (this.directoriesOnly) {
+                         const data = row.getData();
+                         this.directoryClicked(e, data);
+                         this.folderIsSelected = i18n.t('nextcloud-file-picker.load-in-folder');
+                     }*/
+                },
+                rowAdded: (row) => {
+                    row.getElement().classList.toggle("addRowAnimation");
+                }
+            });
+
+
+            // Strg + click select mode on desktop
+            /*if (this.tabulatorTable.browserMobile === false) {
+                this.tabulatorTable.options.selectableRangeMode = "click";
+            }*/
+
+            if (typeof this.allowedMimeTypes !== 'undefined' && !this.directoriesOnly) {
+                this.tabulatorTable.setFilter(this.checkFileType, this.allowedMimeTypes);
+            }
+            // comment this in to show only directories in filesink
+            /*
+            if (typeof this.directoriesOnly !== 'undefined' && this.directoriesOnly) {
+                this.tabulatorTable.setFilter([
+                    {field:"type", type:"=", value:"directory"},
+                ]);
+            }
+            */
+
+            // add folder on enter
+            this._('#new-folder').addEventListener('keydown', function (e) {
+                if (e.keyCode === 13) {
+                    that.addFolder();
+                }
+            });
+
+            //this.checkSessionStorage();
+        });
+    }
+
+    /**
+     *
+     */
+    async checkSessionStorage() {
+        if (sessionStorage.getItem("nextcloud-webdav-username") && sessionStorage.getItem("nextcloud-webdav-password")) {
+            this.webDavClient = createClient(
+                this.webDavUrl + "/" + sessionStorage.getItem("nextcloud-webdav-username"),
+                {
+                    username: sessionStorage.getItem("nextcloud-webdav-username"),
+                    password: sessionStorage.getItem("nextcloud-webdav-password")
+                }
+            );
+            console.log("check");
+
+            this.loadDirectory(this.directoryPath);
+
+        }
+    }
+
+    /**
+     * check mime type of row
+     *
+     * @param data
+     * @param filterParams
+     */
+    checkFileType(data, filterParams) {
+        if (typeof data.mime === 'undefined') {
+            return true;
+        }
+        const [fileMainType, fileSubType] = data.mime.split('/');
+        const mimeTypes = filterParams.split(',');
+        let deny = true;
+
+        mimeTypes.forEach((str) => {
+            const [mainType, subType] = str.split('/');
+            deny = deny && ((mainType !== '*' && mainType !== fileMainType) || (subType !== '*' && subType !== fileSubType));
+        });
+
+        return !deny;
+    }
+
+    openFilePicker() {
+        if (this.webDavClient === null) {
+            this.loading = true;
+            this.statusText = i18n.t('nextcloud-file-picker.auth-progress');
+            const authUrl = this.authUrl + "?target-origin=" + encodeURIComponent(window.location.href);
+            this.loginWindow = window.open(authUrl, "Nextcloud Login",
+                "width=400,height=400,menubar=no,scrollbars=no,status=no,titlebar=no,toolbar=no");
+            //console.log("open nextcloud filepicker, no webdavclient");
+        } else {
+            this.loadDirectory(this.directoryPath, this.webDavClient);
+            //console.log("load in nextcloud webcomponent");
+        }
+    }
+
+    onReceiveWindowMessage(event) {
+        console.log("hui");
+        if (this.webDavClient === null) {
+            const data = event.data;
+
+            if (data.type === "webapppassword") {
+                if (this.loginWindow !== null) {
+                    this.loginWindow.close();
+                }
+                console.log("lala");
+
+                // see https://github.com/perry-mitchell/webdav-client/blob/master/API.md#module_WebDAV.createClient
+                this.webDavClient = createClient(
+                    data.webdavUrl || this.webDavUrl + "/" + data.loginName,
+                    {
+                        username: data.loginName,
+                        password: data.token
+                    }
+                );
+                console.log("tada");
+
+                if (this._("#remember-checkbox") && this._("#remember-checkbox").checked) {
+                    sessionStorage.setItem('nextcloud-webdav-username', data.loginName);
+                    sessionStorage.setItem('nextcloud-webdav-password', data.token);
+                    console.log("saved");
+
+                }
+                this.loadDirectory(this.directoryPath);
+            }
+        }
+    }
+
+    /**
+     * Loads the directory from WebDAV
+     *
+     * @param path
+     */
+    loadDirectory(path) {
+        if (typeof this.directoryPath === 'undefined' || this.directoryPath === undefined) {
+            this.directoryPath = '';
+        }
+        if (path === undefined) {
+            path = '';
+        }
+
+        // console.log("load nextcloud directory", path);
+        this.loading = true;
+        this.statusText = i18n.t('nextcloud-file-picker.loadpath-nextcloud-file-picker', {name: this.nextcloudName});
+        this.lastDirectoryPath = this.directoryPath;
+        this.directoryPath = path;
+        if (this._("#select_all"))
+            this._("#select_all").checked = false;
+
+        // see https://github.com/perry-mitchell/webdav-client#getdirectorycontents
+        if (this.webDavClient === null) {
+            // client is broken reload try to reset & reconnect
+            this.tabulatorTable.clearData();
+            this.webDavClient = null;
+            let reloadButton = html`${i18n.t('nextcloud-file-picker.something-went-wrong')}
+            <button class="button"
+                    title="${i18n.t('nextcloud-file-picker.refresh-nextcloud-file-picker')}"
+                    @click="${async () => {
+                        this.openFilePicker();
+                    }}">
+                <dbp-icon name="reload">
+            </button>`;
+            this.loading = false;
+            this.statusText = reloadButton;
+        }
+        this.webDavClient
+            .getDirectoryContents(path, {
+                details: true, data: "<?xml version=\"1.0\"?>" +
+                    "<d:propfind  xmlns:d=\"DAV:\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\"  xmlns:ocs=\"http://open-collaboration-services.org/ns\">" +
+                    "  <d:prop>" +
+                    "        <d:getlastmodified />" +
+                    "        <d:resourcetype />" +
+                    "        <d:getcontenttype />" +
+                    "        <d:getcontentlength />" +
+                    "        <d:getetag />" +
+                    "        <oc:permissions />" +
+                    "        <nc:acl-list>" +
+                    "           <nc:acl>" +
+                    "               <nc:acl-permissions />" +
+                    "           </nc:acl>" +
+                    "        </nc:acl-list>" +
+                    "  </d:prop>" +
+                    "</d:propfind>"
+            })
+            .then(contents => {
+                //console.log("------", contents);
+                this.loading = false;
+                this.statusText = "";
+                this.tabulatorTable.setData(contents.data);
+                this.isPickerActive = true;
+                this._(".nextcloud-content").scrollTop = 0;
+                if (!this.activeDirectoryRights.includes("CK") && !this.activeDirectoryRights.includes("NV")) {
+                    this._("#download-button").setAttribute("disabled", "true");
+                } else {
+                    this._("#download-button").removeAttribute("disabled");
+                }
+            }).catch(error => {
+            console.error(error.message);
+
+            // on Error: try to reload with home directory
+            if ((path !== "/" && path !== "") && this.webDavClient !== null && error.message.search("401") === -1) {
+                console.log("error in load directory");
+                this.directoryPath = "";
+                this.loadDirectory("");
+
+            } else {
+                this.loading = false;
+                this.statusText = html`<span
+                        class="error"> ${i18n.t('nextcloud-file-picker.webdav-error', {error: error.message})} </span>`;
+                this.isPickerActive = false;
+                this.tabulatorTable.clearData();
+                this.webDavClient = null;
+                let reloadButton = html`${i18n.t('nextcloud-file-picker.something-went-wrong')}
+                <button class="button"
+                        title="${i18n.t('nextcloud-file-picker.refresh-nextcloud-file-picker')}"
+                        @click="${async () => {
+                            this.openFilePicker();
+                        }}">
+                    <dbp-icon name="reload">
+                </button>`;
+                this.loading = false;
+                this.statusText = reloadButton;
+            }
+        });
+    }
+
+    /**
+     * Event Triggered when a directory in tabulator table is clicked
+     *
+     * @param event
+     * @param file
+     */
+    directoryClicked(event, file) {
+        // save rights of clicked directory
+        if (typeof file.props !== 'undefined') {
+            this.activeDirectoryRights = file.props.permissions;
+            if (typeof file.props['acl-list'] !== "undefined" &&
+                typeof file.props['acl-list']['acl']['acl-permissions'] !== "undefined" && file.props['acl-list']['acl']['acl-permissions']) {
+                this.activeDirectoryACL = file.props['acl-list']['acl']['acl-permissions'];
+            } else {
+                this.activeDirectoryACL = '';
+            }
+        } else {
+            this.activeDirectoryRights = 'SGDNVCK';
+        }
+        this.loadDirectory(file.filename);
+        event.preventDefault();
+    }
+
+    /**
+     * Download all files
+     *
+     * @param files
+     */
+    downloadFiles(files) {
+        files.forEach((fileData) => this.downloadFile(fileData));
+        this.tabulatorTable.deselectRow();
+        if (this._("#select_all")) {
+            this._("#select_all").checked = false;
+        }
+        const data = {"count": files.length};
+        const event = new CustomEvent("dbp-nextcloud-file-picker-number-files",
+            {"detail": data, bubbles: true, composed: true});
+        this.dispatchEvent(event);
+
+        if (files.length > 0) {
+            this.sendSetPropertyEvent(
+                'analytics-event',
+                {category: 'FileHandlingNextcloud', action: 'DownloadFiles', name: files.length});
+        }
+    }
+
+    /**
+     * Download a single file
+     *
+     * @param fileData
+     */
+    downloadFile(fileData) {
+        this.loading = true;
+        this.statusText = "Loading " + fileData.filename + "...";
+
+        // https://github.com/perry-mitchell/webdav-client#getfilecontents
+        this.webDavClient
+            .getFileContents(fileData.filename)
+            .then(contents => {
+                // create file to send via event
+                const file = new File([contents], fileData.basename, {type: fileData.mime});
+                // send event
+                const data = {"file": file, "data": fileData};
+                const event = new CustomEvent("dbp-nextcloud-file-picker-file-downloaded",
+                    {"detail": data, bubbles: true, composed: true});
+                this.dispatchEvent(event);
+                this.loading = false;
+                this.statusText = "";
+            }).catch(error => {
+            console.error(error.message);
+            this.loading = false;
+            this.statusText = html`<span
+                    class="error"> ${i18n.t('nextcloud-file-picker.webdav-error', {error: error.message})} </span>`;
+        });
+    }
+
+    /**
+     * Send the directory to filesink
+     *
+     * @param directory
+     */
+    sendDirectory(directory) {
+        this.tabulatorTable.deselectRow();
+        let path;
+
+        if (!directory[0]) {
+            path = this.directoryPath;
+        } else {
+            path = directory[0].filename;
+        }
+        this.loading = true;
+        this.statusText = i18n.t('nextcloud-file-picker.upload-to', {path: path});
+
+        const event = new CustomEvent("dbp-nextcloud-file-picker-file-uploaded",
+            {"detail": path, bubbles: true, composed: true});
+        this.dispatchEvent(event);
+    }
+
+
+    /**
+     * Upload Files to a directory
+     *
+     * @param files
+     * @param directory
+     */
+    uploadFiles(files, directory) {
+        this.loading = true;
+        this.statusText = i18n.t('nextcloud-file-picker.upload-to', {path: directory});
+        this.fileList = files;
+        this.forAll = false;
+        this.setRepeatForAllConflicts();
+        this.uploadFile(directory);
+
+        if (files.length > 0) {
+            this.sendSetPropertyEvent(
+                'analytics-event',
+                {category: 'FileHandlingNextcloud', action: 'UploadFiles', name: files.length});
+        }
+    }
+
+    /**
+     * Upload a single file from this.filelist to given directory
+     *
+     * @param directory
+     */
+    async uploadFile(directory) {
+        if (this.abortUpload) {
+            this.abortUpload = false;
+            this.abortUploadButton = false;
+            this.forAll = false;
+            this.loading = false;
+            this.statusText = i18n.t('nextcloud-file-picker.abort-message');
+            this._("#replace_mode_all").checked = false;
+            return;
+        }
+        if (this.fileList.length !== 0) {
+            let file = this.fileList[0];
+            this.replaceFilename = file.name;
+            let path = directory + "/" + file.name;
+            // https://github.com/perry-mitchell/webdav-client#putfilecontents
+            let that = this;
+            this.loading = true;
+            this.statusText = i18n.t('nextcloud-file-picker.upload-to', {path: path});
+            await this.webDavClient
+                .putFileContents(path, file, {
+                    overwrite: false, onUploadProgress: progress => {
+                        /* console.log(`Uploaded ${progress.loaded} bytes of ${progress.total}`);*/
+                    }
+                }).then(function () {
+                    that.uploadCount += 1;
+                    that.fileList.shift();
+                    that.uploadFile(directory);
+                }).catch(error => {
+                    if (error.message.search("412") !== -1 || error.message.search("403") !== -1) {
+                        this.generatedFilename = this.getNextFilename();
+                        this._("#replace-filename").value = this.generatedFilename;
+                        if (this.forAll) {
+                            this.uploadFileObject = file;
+                            this.uploadFileDirectory = directory;
+                            this.abortUploadButton = true;
+                            this.uploadFileAfterConflict();
+                        } else {
+                            this.replaceModalDialog(file, directory);
+                        }
+                    }
+                });
+        } else {
+            this.loadDirectory(this.directoryPath);
+            this.loading = false;
+            this.statusText = "";
+            this._("#replace_mode_all").checked = false;
+            this.forAll = false;
+            this.customFilename = '';
+            const event = new CustomEvent("dbp-nextcloud-file-picker-file-uploaded-finished",
+                {bubbles: true, composed: true, detail: this.uploadCount});
+            this.uploadCount = 0;
+            this.abortUpload = false;
+            this.abortUploadButton = false;
+            this.dispatchEvent(event);
+
+        }
+    }
+
+    /**
+     * Upload a file after a conflict happens on webdav side
+     *
+     */
+    async uploadFileAfterConflict() {
+        if (this.abortUpload) {
+            this.abortUpload = false;
+            this.abortUploadButton = false;
+            this.forAll = false;
+            this.loading = false;
+            this.statusText = i18n.t('nextcloud-file-picker.abort-message');
+            this._("#replace_mode_all").checked = false;
+            return;
+        }
+        let path = "";
+        let overwrite = false;
+        let file = this.uploadFileObject;
+        let directory = this.uploadFileDirectory;
+
+        if (this._("input[name='replacement']:checked").value === "ignore") {
+            MicroModal.close(this._("#replace-modal"));
+            this.forAll ? this.fileList = [] : this.fileList.shift();
+            this.uploadFile(directory);
+            return true;
+        } else if (this._("input[name='replacement']:checked").value === "new-name") {
+            if (this.generatedFilename !== this._("#replace-filename").value) {
+                this.customFilename = this._("#replace-filename").value;
+            }
+            path = directory + "/" + this._("#replace-filename").value;
+            MicroModal.close(this._("#replace-modal"));
+            this.replaceFilename = this._("#replace-filename").value;
+        } else {
+            path = directory + "/" + this.uploadFileObject.name;
+            overwrite = true;
+        }
+
+        this.loading = true;
+        this.statusText = i18n.t('nextcloud-file-picker.upload-to', {path: path});
+
+        let that = this;
+        // https://github.com/perry-mitchell/webdav-client#putfilecontents
+        await this.webDavClient
+            .putFileContents(path, file, {
+                overwrite: overwrite, onUploadProgress: progress => {
+                    /*console.log(`Uploaded ${progress.loaded} bytes of ${progress.total}`);*/
+                }
+            }).then(content => {
+                MicroModal.close(this._("#replace-modal"));
+                this.uploadCount += 1;
+                that.fileList.shift();
+                that.uploadFile(directory);
+            }).catch(error => {
+                if (error.message.search("412") !== -1) {
+                    MicroModal.close(that._("#replace-modal"));
+                    this.generatedFilename = this.getNextFilename();
+                    this._("#replace-filename").value = this.generatedFilename;
+                    if (this.forAll) {
+                        this.uploadFileObject = file;
+                        this.uploadFileDirectory = directory;
+                        this.abortUploadButton = true;
+                        this.uploadFileAfterConflict();
+                    } else {
+                        this.replaceModalDialog(file, directory);
+                    }
+                }
+            });
+
+        this.fileNameCounter = 1;
+    }
+
+    /**
+     * Check permissions of a given file in the active directory
+     * no rename: if you dont have create permissions
+     * no replace: if you dont have write permissions
+     *
+     * R = Share, S = Shared Folder, M = Group folder or external source, G = Read, D = Delete, NV / NVW = Write, CK = Create
+     *
+     * @param file
+     * @returns {number}
+     */
+    checkRights(file) {
+
+        // nextcloud permissions
+        let file_perm = 0;
+        let active_directory_perm = this.activeDirectoryRights;
+        let rows = this.tabulatorTable.searchRows("basename", "=", this.replaceFilename);
+        if (typeof rows[0] !== 'undefined' && rows[0]) {
+            file_perm = rows[0].getData().props.permissions;
+        } else {
+            file_perm = "";
+        }
+
+        /* ACL permissions: If ACL > permssions comment this in
+        if (this.activeDirectoryACL !== '') {
+            console.log("ACL SET");
+            active_directory_perm = "MG";
+            if (this.activeDirectoryACL & (1 << (3 - 1))) {
+                active_directory_perm = "CK";
+                console.log("ACL CREATE");
+            }
+            if (this.activeDirectoryACL & (1 << (2 - 1))) {
+                active_directory_perm += "NV";
+                console.log("ACL WRITE");
+            }
+        }
+
+        // if file has acl rights take that
+        if (typeof rows[0].getData().props['acl-list'] !== 'undefined' && rows[0].getData().props['acl-list'] &&
+            rows[0].getData().props['acl-list']['acl']['acl-permissions'] !== '') {
+            console.log("FILE HAS ACL");
+            file_perm = "MG";
+
+            if (rows[0].getData().props['acl-list']['acl']['acl-permissions'] & (1 << (3 - 1))) {
+                file_perm = "CK";
+                console.log("FILE ACL CREATE");
+            }
+            if (rows[0].getData().props['acl-list']['acl']['acl-permissions'] & (1 << (2 - 1))) {
+                file_perm += "NV";
+                console.log("FILE ACL WRITE");
+            }
+        }
+        */
+
+        // all allowed
+        if (active_directory_perm.includes("CK") && file_perm.includes("NV")) {
+            return -1;
+        }
+
+        // read only file but you can write to directory = only create and no edit
+        if (active_directory_perm.includes("CK") && !file_perm.includes("NV")) {
+            return 1;
+        }
+
+        // only edit and no create
+        if (!active_directory_perm.includes("CK") && file_perm.includes("NV")) {
+            return 2;
+        }
+
+        // read only directory and read only file
+        return 0;
+
+    }
+
+    /**
+     * Open the replace Modal Dialog with gui where forbidden actions are disabled
+     *
+     * @param file
+     * @param directory
+     */
+    replaceModalDialog(file, directory) {
+        this.uploadFileObject = file;
+        this.uploadFileDirectory = directory;
+        let rights = this.checkRights(file);
+        // read only directory or read only file
+        if (rights === 0) {
+            this.loading = false;
+            this.statusText = i18n.t('nextcloud-file-picker.readonly');
+            return;
+        }
+        // read only file but you can write to directory = only create and no edit
+        else if (rights === 1) {
+            this.loading = false;
+            this.statusText = i18n.t('nextcloud-file-picker.onlycreate');
+            this._("#replace-replace").setAttribute("disabled", "true");
+            this._("#replace-new-name").removeAttribute("disabled");
+            this._("#replace-replace").checked = false;
+            this._("#replace-new-name").checked = true;
+            this.setInputFieldVisibility();
+            this._("#replace-new-name").focus();
+        }
+        // only edit and no create
+        else if (rights === 2) {
+            this.loading = false;
+            this.statusText = i18n.t('nextcloud-file-picker.onlyedit');
+            this._("#replace-new-name").setAttribute("disabled", "true");
+            this._("#replace-replace").removeAttribute("disabled");
+            this._("#replace-new-name").checked = false;
+            this._("#replace-replace").checked = true;
+            this.setInputFieldVisibility();
+            this._("#replace-replace").focus();
+        }
+        // all allowed
+        else {
+            this._("#replace-new-name").removeAttribute("disabled");
+            this._("#replace-replace").removeAttribute("disabled");
+            this._("#replace-replace").checked = false;
+            this._("#replace-new-name").checked = true;
+            this.setInputFieldVisibility();
+            this._("#replace-new-name").focus();
+        }
+        MicroModal.show(this._('#replace-modal'), {
+            disableScroll: true,
+            onClose: modal => {
+                this.statusText = "";
+                this.loading = false;
+            },
+        });
+    }
+
+    closeDialog(e) {
+        if (this.tabulatorTable) {
+            this.tabulatorTable.deselectRow();
+        }
+        if (this._("#select_all")) {
+            this._("#select_all").checked = false;
+        }
+        MicroModal.close(this._('#modal-picker'));
+    }
+
+    /**
+     * Returns a filename with the next counter number.
+     *
+     * @returns {string} The next filename
+     */
+    getNextFilename() {
+        let nextFilename = "";
+        let splitFilename;
+        if (this.forAll && this.customFilename !== '') {
+            splitFilename = this.customFilename.split(".");
+        } else {
+            splitFilename = this.replaceFilename.split(".");
+        }
+
+        let splitBracket = splitFilename[0].split('(');
+        if (splitBracket.length > 1) {
+            let numberString = splitBracket[1].split(')');
+            if (numberString.length > 1 && !isNaN(parseInt(numberString[0]))) {
+                let number = parseInt(numberString[0]);
+                this.fileNameCounter = number + 1;
+                nextFilename = splitBracket[0] + "(" + this.fileNameCounter + ")";
+            } else {
+                nextFilename = splitFilename[0] + "(" + this.fileNameCounter + ")";
+            }
+        } else {
+            nextFilename = splitFilename[0] + "(" + this.fileNameCounter + ")";
+        }
+        if (splitFilename.length > 1) {
+            for (let i = 1; i < splitFilename.length; i++) {
+                nextFilename = nextFilename + "." + splitFilename[i];
+            }
+        }
+        this.fileNameCounter++;
+        return nextFilename;
+    }
+
+    /**
+     * Disables or enables the input field for the new file name
+     */
+    setInputFieldVisibility() {
+        this._("#replace-filename").disabled = !this._("#replace-new-name").checked;
+    }
+
+    /**
+     * Returns text for the cancel button depending on number of files
+     *
+     * @returns {string} correct cancel text
+     */
+    getCancelText() {
+        if (this.fileList.length > 1) {
+            return i18n.t('nextcloud-file-picker.replace-cancel-all');
+        }
+        return i18n.t('nextcloud-file-picker.replace-cancel');
+    }
+
+    /**
+     *
+     */
+    cancelOverwrite() {
+        this.statusText = "";
+        this.loading = false;
+        this.fileList = [];
+    }
+
+    /**
+     *
+     */
+    setRepeatForAllConflicts() {
+        this.forAll = this._("#replace_mode_all").checked;
+    }
+
+    /**
+     * Add new folder with webdav
+     *
+     */
+    openAddFolderDialogue() {
+        if (this._('.addRowAnimation')) {
+            this._('.addRowAnimation').classList.remove('addRowAnimation');
+        }
+        this._('#new-folder-wrapper').classList.toggle('hidden');
+        if (this._('#new-folder-wrapper').classList.contains('hidden')) {
+            this._('#add-folder-button').setAttribute("name", "plus");
+            this._('#add-folder-button').setAttribute("title", i18n.t('nextcloud-file-picker.add-folder-open'));
+        } else {
+            this._('#add-folder-button').setAttribute("name", "close");
+            this._('#add-folder-button').setAttribute("title", i18n.t('nextcloud-file-picker.add-folder-close'));
+            this._('#new-folder').focus();
+        }
+    }
+
+    /**
+     * Add new folder with webdav
+     *
+     */
+    addFolder() {
+        if (this._('#new-folder').value !== "") {
+            let folderName = this._('#new-folder').value;
+            if (typeof this.directoryPath === 'undefined') {
+                this.directoryPath = '';
+            }
+            let folderPath = this.directoryPath + "/" + folderName;
+            this.webDavClient.createDirectory(folderPath).then(contents => {
+                // this.loadDirectory(this.directoryPath);
+                const d = new Date();
+                let props = {permissions: 'RGDNVCK'};
+                this.tabulatorTable.addRow({
+                    type: "directory",
+                    filename: folderPath,
+                    basename: folderName,
+                    lastmod: d,
+                    props: props
+                }, true);
+                this.statusText = i18n.t('nextcloud-file-picker.add-folder-success', {folder: folderName});
+                this.loading = false;
+            }).catch(error => {
+                this.loading = false;
+                if (error.message.search("405") !== -1) {
+                    this.statusText = html`<span
+                            class="error"> ${i18n.t('nextcloud-file-picker.add-folder-error', {folder: folderName})} </span>`;
+                } else {
+                    this.statusText = html`<span
+                            class="error"> ${i18n.t('nextcloud-file-picker.webdav-error', {error: error.message})} </span>`;
+                }
+            });
+
+            this._('#new-folder').value = '';
+            this.openAddFolderDialogue();
+        }
+    }
+
+    /**
+     * Select or deselect all files from tabulator table
+     *
+     */
+    selectAllFiles() {
+        let allSelected = this.checkAllSelected();
+        if (allSelected) {
+            this.tabulatorTable.getSelectedRows().forEach(row => row.deselect());
+        } else {
+            this.tabulatorTable.selectRow(this.tabulatorTable.getRows().filter(row => row.getData().type != 'directory' && this.checkFileType(row.getData(), this.allowedMimeTypes)));
+        }
+    }
+
+    checkAllSelected() {
+        if (this.tabulatorTable) {
+            let maxSelected = this.tabulatorTable.getRows().filter(row => row.getData().type != 'directory' && this.checkFileType(row.getData(), this.allowedMimeTypes)).length;
+            let selected = this.tabulatorTable.getSelectedRows().length;
+            if (selected === maxSelected) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the parent directory path
+     *
+     * @returns {string} parent directory path
+     */
+    getParentDirectoryPath() {
+        if (typeof this.directoryPath === 'undefined') {
+            this.directoryPath = '';
+        }
+        let path = this.directoryPath.replace(/\/$/, "");
+        path = path.replace(path.split("/").pop(), "").replace(/\/$/, "");
+
+        return (path === "") ? "/" : path;
+    }
+
+    /**
+     * Returns the directory path as clickable breadcrumbs
+     *
+     * @returns {string} clickable breadcrumb path
+     */
+    getBreadcrumb() {
+        if (typeof this.directoryPath === 'undefined') {
+            this.directoryPath = '';
+        }
+        let htmlpath = [];
+        htmlpath[0] = html`<span class="breadcrumb"><a class="home-link" @click="${() => {
+            this.loadDirectory("");
+        }}" title="${i18n.t('nextcloud-file-picker.folder-home')}"><dbp-icon name="home"></dbp-icon> </a></span>`;
+        const directories = this.directoryPath.split('/');
+        if (directories[1] === "") {
+            return htmlpath;
+        }
+        for (let i = 1; i < directories.length; i++) {
+            let path = "";
+            for (let j = 1; j <= i; j++) {
+                path += "/";
+                path += directories[j];
+            }
+
+            htmlpath[i] = html`<span> › </span><span class="breadcrumb"><a @click="${() => {
+                this.loadDirectory(path);
+            }}" title="${i18n.t('nextcloud-file-picker.load-path-link', {path: directories[i]})}">${directories[i]}</a></span>`;
+        }
+
+        return htmlpath;
+    }
+
+    /**
+     * Returns Link to Nextcloud with actual directory
+     *
+     * @returns {string} actual directory Nextcloud link
+     */
+    getNextCloudLink() {
+        return this.nextcloudFileURL + this.directoryPath;
+    }
+
+    static get styles() {
+        // language=css
+        return css`
+            ${commonStyles.getGeneralCSS()}
+            ${commonStyles.getButtonCSS()}
+            ${commonStyles.getTextUtilities()}
+            ${commonStyles.getModalDialogCSS()}
+            ${commonStyles.getRadioAndCheckboxCss()}
+            ${fileHandlingStyles.getFileHandlingCss()}
+            .visible {
+                display: unset;
+            }
+
+            .block {
+                margin-bottom: 10px;
+            }
+
+            .error {
+                color: var(--dbp-danger-bg-color);
+            }
+
+
+            .nextcloud-header {
+                margin-bottom: 2rem;
+                display: inline-grid;
+                width: 100%;
+                grid-template-columns: auto auto;
+            }
+
+            .nextcloud-header div button {
+                justify-self: start;
+            }
+
+            .nextcloud-intro {
+                text-align: center;
+            }
+
+            .nextcloud-logo {
+                width: 80px;
+                height: 95px;
+                justify-self: end;
+                transition: all 0.5s ease;
+                margin: auto;
+            }
+
+            .nextcloud-logo-image {
+                height: 100%;
+                width: 100%;
+                background-image: var(--dbp-override-image-nextcloud, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Cpath d='M69.3 86.1l-46.1 0C11 85.9 1.1 75.9 1.1 63.7c0-11.8 9.1-21.4 20.6-22.4 0.5-15.2 13-27.4 28.3-27.4 3.4 0 6.6 0.5 9.2 1.6 6.2 2.1 11.4 6.4 14.8 12 6.5 1 12.7 4.3 16.9 9.1 5 5.5 7.8 12.6 7.8 19.9C98.8 72.8 85.6 86.1 69.3 86.1zM23.6 80.6h45.7c13.3 0 24-10.8 24-24 0-6-2.3-11.8-6.4-16.2 -3.7-4.2-9.1-6.9-14.9-7.5l-1.4-0.2L70 31.4c-2.8-5.1-7.2-8.9-12.6-10.7l-0.1 0c-2-0.8-4.5-1.2-7.2-1.2 -12.6 0-22.9 10.3-22.9 22.9v4.5h-3.6c-9.3 0-17 7.6-17 17C6.6 73 14.3 80.6 23.6 80.6z'/%3E%3C/svg%3E"));
+                background-repeat: no-repeat;
+                background-position: center;
+            }
+
+            .nextcloud-logo-sm {
+                width: 40px;
+                justify-self: inherit;
+                margin-right: 70px;
+                display: none;
+            }
+
+            .m-inherit {
+                margin: inherit;
+            }
+
+            .wrapper {
+                width: 100%;
+                height: 100%;
+                display: flex;
+                flex-direction: column;
+                justify-content: center;
+                position: relative;
+            }
+
+            .wrapper-select {
+                justify-content: inherit;
+            }
+
+            .select-button {
+                justify-self: end;
+                justify-self: end;
+            }
+
+            .nextcloud-content {
+                width: 100%;
+                height: 100%;
+                overflow-y: auto;
+                -webkit-overflow-scrolling: touch;
+            }
+
+
+            .nextcloud-nav {
+                display: flex;
+                justify-content: space-between;
+            }
+
+
+            .nextcloud-footer {
+                background-color: white;
+                width: 100%;
+                padding-top: 10px;
+            }
+
+            .nextcloud-footer-grid {
+                width: 100%;
+                display: flex;
+                align-items: center;
+                flex-direction: row-reverse;
+                justify-content: space-between;
+            }
+
+
+            .add-folder {
+                white-space: nowrap;
+                align-self: end;
+                height: 33px;
+            }
+
+            .nextcloud-nav p {
+                align-self: center;
+            }
+
+            #replace-modal-box {
+                display: flex;
+                flex-direction: column;
+                justify-content: center;
+                padding: 30px;
+                max-height: 450px;
+                min-height: 450px;
+                min-width: 380px;
+                max-width: 190px;
+            }
+
+            #replace-modal-box .modal-header {
+                display: flex;
+                justify-content: space-evenly;
+                align-items: baseline;
+            }
+
+            #replace-modal-box .modal-header h2 {
+                font-size: 1.2rem;
+                padding-right: 5px;
+            }
+
+            #replace-modal-box .modal-content {
+                display: flex;
+                flex-direction: column;
+                height: 100%;
+                justify-content: space-evenly;
+            }
+
+            #replace-modal-box .radio-btn {
+                margin-right: 5px;
+            }
+
+            #replace-modal-box .modal-content label {
+                display: block;
+                width: 100%;
+                text-align: left;
+            }
+
+            #replace-modal-box #replace-filename {
+                display: block;
+                width: 100%;
+                margin-top: 8px;
+            }
+
+            #replace-modal-box input[type="text"]:disabled {
+                color: #aaa;
+            }
+
+            #replace-modal-box .modal-content div {
+                display: flex;
+            }
+
+            #replace-modal-box .modal-footer {
+                padding-top: 15px;
+            }
+
+            #replace-modal-box .modal-footer .modal-footer-btn {
+                display: flex;
+                justify-content: space-between;
+                padding-bottom: 15px;
+            }
+
+            .breadcrumb {
+                border-bottom: 1px solid black;
+            }
+
+            .breadcrumb:last-child, .breadcrumb:first-child {
+                border-bottom: none;
+            }
+
+            .breadcrumb a {
+                display: inline-block;
+                height: 33px;
+                vertical-align: middle;
+                line-height: 33px;
+
+            }
+
+            input:disabled + label {
+                color: #aaa;
+            }
+
+            .inline-block {
+                display: inline-block;
+            }
+
+            .nextcloud-nav h2 {
+                padding-top: 10px;
+            }
+
+            .no-select, .tabulator-row.tabulator-selected.no-select:hover, .tabulator-row.no-select:hover, .tabulator-row.tabulator-selectable.no-select:hover {
+                cursor: unset;
+                color: #333;
+                background-color: white;
+            }
+
+            .nextcloud-nav {
+                position: relative;
+            }
+
+            .inline-block {
+                position: absolute;
+                right: 0px;
+                z-index: 1;
+                background-color: white;
+                bottom: -45px;
+            }
+
+            .addRowAnimation {
+                animation: added 0.4s ease;
+            }
+
+            #abortButton {
+                color: var(--dbp-danger-bg-color);
+            }
+
+            #abortButton:hover {
+                color: white;
+            }
+
+            @keyframes added {
+                0% {
+                    background-color: white;
+                }
+                50% {
+                    background-color: var(--dbp-success-bg-color);
+                }
+                100% {
+                    background-color: white;
+                }
+            }
+
+            .spinner {
+                font-size: 0.7em;
+            }
+
+            .nextcloud-picker-icon-disabled {
+                opacity: 0.4;
+            }
+
+            .button.button, .button, button.dt-button {
+                background-color: white;
+            }
+
+            #new-folder {
+                padding-right: 50px;
+            }
+
+            .nextcloud-nav a {
+                white-space: nowrap;
+                overflow: hidden;
+                text-overflow: ellipsis;
+                max-width: 130px;
+            }
+
+            #replace-modal-box .modal-header {
+                padding: 0px;
+            }
+
+            #replace-modal-content {
+                padding: 0px;
+                align-items: baseline;
+            }
+
+            #replace-modal-box .modal-header h2 {
+                text-align: left;
+            }
+
+            .table-wrapper {
+                position: relative;
+            }
+
+            .button-container .checkmark::after {
+                left: 8px;
+                top: 3px;
+                width: 4px;
+                height: 11px;
+            }
+
+            .select-all-icon {
+                height: 30px;
+            }
+
+            .checkmark {
+                height: 20px;
+                width: 20px;
+                left: 11px;
+                top: 4px;
+            }
+            
+            #replace-modal .checkmark {
+                height: 20px;
+                width: 20px;
+                left: 1px;
+                top: 0px;
+            }
+            
+            .remember-container{
+                display: inline-block;
+                line-height: 28px;
+                padding-left: 44px;
+            }
+
+
+            @media only screen
+            and (orientation: portrait)
+            and (max-width: 768px) {
+                .add-folder button {
+                    float: right;
+                }
+
+                .add-folder {
+                    position: absolute;
+                    right: 0px;
+                }
+
+                .nextcloud-nav {
+                    display: block;
+                }
+
+                .add-folder {
+                    position: inherit;
+                }
+
+                .inline-block {
+                    width: inherit;
+                    position: absolute;
+                    right: 52px;
+                    z-index: 1;
+                    background-color: white;
+                    bottom: 0px;
+                }
+
+                .add-folder-button {
+                    right: 0px;
+                    position: absolute;
+                }
+
+                .nextcloud-nav h2 > a {
+                    font-size: 1.3rem;
+                }
+
+                .nextcloud-nav h2 {
+                    padding-top: 8px;
+                }
+
+                .nextcloud-nav a {
+                    font-size: 1rem;
+                }
+
+                .nextcloud-nav .home-link {
+                    font-size: 1.2rem;
+                }
+
+                .nextcloud-logo-sm {
+                    display: none;
+                }
+
+                .nextcloud-logo {
+                    margin: 0 auto;
+                }
+
+
+                .button-wrapper {
+                    justify-self: start;
+                }
+
+                .wrapper {
+                    display: flex;
+                    justify-content: space-between;
+                }
+
+                .nextcloud-header {
+                    grid-area: header-l;
+                    margin-bottom: 0px;
+                }
+
+                .nextcloud-content, .nextcloud-intro {
+                    grid-area: content;
+                    height: 100%;
+                    justify-content: center;
+                }
+
+                .nextcloud-intro {
+                    text-align: center;
+                    display: flex;
+                    flex-direction: column;
+                }
+
+                .nextcloud-footer {
+                    bottom: 0px;
+                    width: 100%;
+                    left: 0px;
+                }
+
+                .mobile-hidden {
+                    display: none;
+                }
+
+                .info-box {
+                    position: relative;
+                }
+
+                .nextcloud-footer-grid {
+                    display: flex;
+                    justify-content: center;
+                    flex-direction: column-reverse;
+                }
+
+                .select-button {
+                    margin: 0px;
+                }
+
+                #new-folder {
+                    width: 100%;
+                }
+
+                #replace-modal-box {
+                    min-width: 100%;
+                    max-width: 100%;
+                }
+
+                .hidden {
+                    display: none;
+                }
+
+                .button-container .checkmark::after {
+                    left: 8px;
+                    top: 2px;
+                    width: 8px;
+                    height: 15px;
+                }
+
+                .select-all-icon {
+                    height: 32px;
+                }
+
+                .checkmark {
+                    height: 25px;
+                    width: 25px;
+                    left: 9px;
+                    top: 2px;
+                }
+
+            }
+        `;
+    }
+
+    render() {
+        const tabulatorCss = commonUtils.getAssetURL(pkgName, 'tabulator-tables/css/tabulator.min.css');
+
+        return html`
+            <div class="wrapper">
+                <link rel="stylesheet" href="${tabulatorCss}">
+                <div class="nextcloud-intro ${classMap({hidden: this.isPickerActive})}">
+                    <div class="nextcloud-logo ${classMap({"nextcloud-logo-sm": this.isPickerActive})}">
+                        <div class="nextcloud-logo-image"></div>
+                    </div>
+                    <div class="block text-center ${classMap({hidden: this.isPickerActive})}">
+                        <h2 class="m-inherit">
+                            ${this.nextcloudName}
+                        </h2>
+                        <p class="m-inherit">
+                            ${i18n.t('nextcloud-file-picker.init-text-1', {name: this.nextcloudName})} <br>
+                            ${i18n.t('nextcloud-file-picker.init-text-2')} <br><br>
+
+                        </p>
+                    </div>
+                    <div class="block ${classMap({hidden: this.isPickerActive})}">
+                        <button class="button  is-primary"
+                                title="${i18n.t('nextcloud-file-picker.open-nextcloud-file-picker', {name: this.nextcloudName})}"
+                                @click="${async () => {
+                                    this.openFilePicker();
+                                }}">${i18n.t('nextcloud-file-picker.connect-nextcloud', {name: this.nextcloudName})}
+                        </button>
+                    </div>
+                    <div class="block text-center m-inherit ${classMap({hidden: this.isPickerActive})}">
+                        <label class="button-container remember-container">
+                            Remember me
+                            <input type="checkbox" id="remember-checkbox" name="remember">
+                            <span class="checkmark"></span>
+                        </label>
+                    </div>
+                    <div class="block text-center m-inherit ${classMap({hidden: this.isPickerActive})}">
+                        <p class="m-inherit"><br>
+                            ${i18n.t('nextcloud-file-picker.auth-info')}
+                            <slot name="auth-info"><br/>${this.authInfo}</slot>
+                        </p>
+                        
+                    </div>
+                </div>
+                <div class="nextcloud-content ${classMap({hidden: !this.isPickerActive})}">
+                    <div class="nextcloud-nav">
+                        <p>${this.getBreadcrumb()}</p>
+                        <div class="add-folder ${classMap({hidden: !this.directoriesOnly})}">
+                            <div class="inline-block">
+                                <div id="new-folder-wrapper" class="hidden">
+                                    <input type="text"
+                                           placeholder="${i18n.t('nextcloud-file-picker.new-folder-placeholder')}"
+                                           name="new-folder" class="input" id="new-folder"/>
+                                    <button class="button add-folder-button"
+                                            title="${i18n.t('nextcloud-file-picker.add-folder')}"
+                                            @click="${() => {
+                                                this.addFolder();
+                                            }}">
+                                        <dbp-icon name="checkmark-circle" class="nextcloud-add-folder"></dbp-icon>
+                                    </button>
+                                </div>
+                            </div>
+                            <button class="button"
+                                    title="${i18n.t('nextcloud-file-picker.add-folder-open')}"
+                                    @click="${() => {
+                                        this.openAddFolderDialogue();
+                                    }}">
+                                <dbp-icon name="plus" class="nextcloud-add-folder" id="add-folder-button"></dbp-icon>
+                            </button>
+                        </div>
+
+                    </div>
+                    <div class="table-wrapper">
+                        <table id="directory-content-table" class="force-no-select"></table>
+                    </div>
+                </div>
+
+                <div class="nextcloud-footer ${classMap({hidden: !this.isPickerActive})}">
+                    <div class="nextcloud-footer-grid">
+                        <button id="download-button"
+                                class="button select-button is-primary ${classMap({hidden: ((!this.directoriesOnly) || (this.directoriesOnly && this.abortUploadButton && this.forAll))})}"
+                                @click="${() => {
+                                    this.sendDirectory(this.tabulatorTable.getSelectedData());
+                                }}"
+                                ?disabled="${this.selectBtnDisabled}">
+                            <dbp-icon class="nav-icon" name="cloud-upload"></dbp-icon>
+                            ${this.folderIsSelected}
+                        </button>
+                        <button class="button select-button is-primary ${classMap({hidden: this.directoriesOnly})}"
+                                @click="${() => {
+                                    this.downloadFiles(this.tabulatorTable.getSelectedData());
+                                }}"
+                                ?disabled="${this.selectBtnDisabled}">
+                            ${(this.tabulatorTable && this.tabulatorTable.getSelectedRows().filter(row => row.getData().type != 'directory' && this.checkFileType(row.getData(), this.allowedMimeTypes)).length === 0) ? i18n.t('nextcloud-file-picker.select-files') : i18n.t('nextcloud-file-picker.select-files-btn', {count: this.tabulatorTable ? this.tabulatorTable.getSelectedRows().length : 0})}
+                        </button>
+                        <button id="abortButton"
+                                class="button select-button hidden ${classMap({"visible": (this.directoriesOnly && this.forAll && this.abortUploadButton)})}"
+                                title="${i18n.t('nextcloud-file-picker.abort')}" @click="${() => {
+                            this.abortUpload = true;
+                        }}">${i18n.t('nextcloud-file-picker.abort')}
+                        </button>
+
+                        <div class="block info-box ${classMap({hidden: this.statusText === ""})}">
+                            <dbp-mini-spinner
+                                    class="spinner ${classMap({hidden: this.loading === false})}"></dbp-mini-spinner>
+                            <span>${this.statusText}</span>
+                        </div>
+
+                    </div>
+                </div>
+            </div>
+
+            <div class="modal micromodal-slide" id="replace-modal" aria-hidden="true">
+                <div class="modal-overlay" tabindex="-2" data-micromodal-close>
+                    <div class="modal-container" id="replace-modal-box" role="dialog" aria-modal="true"
+                         aria-labelledby="replace-modal-title">
+                        <header class="modal-header">
+                            <button title="${i18n.t('file-sink.modal-close')}" class="modal-close"
+                                    aria-label="Close modal" @click="${() => {
+                                this.closeDialog();
+                            }}">
+                                <dbp-icon title="${i18n.t('file-sink.modal-close')}" name="close"
+                                          class="close-icon"></dbp-icon>
+                            </button>
+                            <h2 id="replace-modal-title">
+                                ${i18n.t('nextcloud-file-picker.replace-title-1')}
+                                <span style="word-break: break-all;">${this.replaceFilename}</span>
+                                ${i18n.t('nextcloud-file-picker.replace-title-2')}.
+                            </h2>
+                        </header>
+                        <main class="modal-content" id="replace-modal-content">
+                            <h3>
+                                ${i18n.t('nextcloud-file-picker.replace-text')}?
+                            </h3>
+                            <div>
+                                <label class="button-container">
+                                    <span> 
+                                        ${i18n.t('nextcloud-file-picker.replace-new_name')}:
+
+                                    </span>
+                                    <input type="radio" id="replace-new-name" class="radio-btn" name="replacement"
+                                           value="new-name" checked @click="${() => {
+                                        this.setInputFieldVisibility();
+                                    }}">
+                                    <span class="radiobutton"></span>
+                                    <input type="text" id="replace-filename" class="input" name="replace-filename"
+                                           value="" onClick="this.select();">
+                                </label>
+
+                            </div>
+
+
+                            <div>
+                                <label class="button-container">
+                                    <span>${i18n.t('nextcloud-file-picker.replace-replace')}</span>
+                                    <input type="radio" id="replace-replace" name="replacement" value="replace"
+                                           @click="${() => {
+                                               this.setInputFieldVisibility();
+                                           }}">
+                                    <span class="radiobutton"></span>
+                                </label>
+                            </div>
+                            <div>
+                                <label class="button-container">
+                                    <span>${i18n.t('nextcloud-file-picker.replace-skip')}</span>
+                                    <input type="radio" class="radio-btn" name="replacement" value="ignore"
+                                           @click="${() => {
+                                               this.setInputFieldVisibility();
+                                           }}">
+                                    <span class="radiobutton"></span>
+                                </label>
+                            </div>
+                        </main>
+                        <footer class="modal-footer">
+                            <div class="modal-footer-btn">
+                                <button class="button" data-micromodal-close aria-label="Close this dialog window"
+                                        @click="${() => {
+                                            this.cancelOverwrite();
+                                        }}">${this.getCancelText()}
+                                </button>
+                                <button class="button select-button is-primary" @click="${() => {
+                                    this.uploadFileAfterConflict();
+                                }}">OK
+                                </button>
+                            </div>
+                            <div>
+                                <label class="button-container">
+                                    ${i18n.t('nextcloud-file-picker.replace-mode-all')}
+                                    <input type="checkbox" id="replace_mode_all" name="replace_mode_all"
+                                           value="replace_mode_all" @click="${() => {
+                                        this.setRepeatForAllConflicts();
+                                    }}">
+                                    <span class="checkmark"></span>
+                                </label>
+                            </div>
+                        </footer>
+                    </div>
+                </div>
+            </div>
+        `;
+    }
+}
-- 
GitLab