Skip to content
Snippets Groups Projects
dbp-nextcloud-file-picker.js 63.56 KiB
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';

/**
 * 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 = null;
        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.selectAllButton = true;
        this.abortUploadButton = false;
        this.abortUpload = false;
    }

    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 },
            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 },
            selectAllButton: { type: Boolean, attribute: false },
            abortUploadButton: { type: Boolean, attribute: false },
        };

    }

    update(changedProperties) {
        changedProperties.forEach((oldValue, propName) => {
            switch (propName) {
                case "lang":
                    i18n.changeLanguage(this.lang);
                    break;
            }
        });

        super.update(changedProperties);
    }

    disconnectedCallback() {
        window.removeEventListener('message', this._onReceiveWindowMessage);
        super.disconnectedCallback();
    }

    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",
                responsiveLayout: true,
                placeholder:this.directoriesOnly ? i18n.t('nextcloud-file-picker.no-data') :  i18n.t('nextcloud-file-picker.no-data-type'),
                resizableColumns:false,
                columns: [
                    {title: "", field: "type", align:"center", headerSort:false, width:50, responsive:1, formatter: (cell, formatterParams, onRendered) => {
                            const icon_tag =  that.constructor.getScopedTagName("dbp-icon");
                            let 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: 50, field: "size", formatter: (cell, formatterParams, onRendered) => {
                            return cell.getRow().getData().type === "directory" ? "" : humanFileSize(cell.getValue());}},
                    {title: i18n.t('nextcloud-file-picker.mime-type'), responsive: 2, widthGrow:1, minWidth: 20, field: "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');
                    }
                },
                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.getSelectedRows().length === this.tabulatorTable.getRows().filter(row => row.getData().type != 'directory' && this.checkFileType(row.getData(), this.allowedMimeTypes)).length) {
                                        this.selectAllButton = false;
                                    }
                                    else {
                                        this.selectAllButton = true;
                                    }
                                    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();
                }
            });
        });
    }

    /**
     * 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) {
        if (this.webDavClient === null)
        {
            const data = event.data;

            if (data.type === "webapppassword") {
                if (this.loginWindow !== null) {
                    this.loginWindow.close();
                }

                // 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
                    }
                );
                this.loadDirectory(this.directoryPath);
            }
        }
    }

    /**
     * Loads the directory from WebDAV
     *
     * @param path
     */
    loadDirectory(path) {
        if ( typeof this.directoryPath === 'undefined' ) {
           this.directoryPath = '';
        }
        console.log("load nextcloud directory", path);
        this.selectAllButton = true;
        this.loading = true;
        this.statusText = i18n.t('nextcloud-file-picker.loadpath-nextcloud-file-picker', {name: this.nextcloudName});
        this.lastDirectoryPath = this.directoryPath;
        this.directoryPath = path;

        // 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();
    }

    /**
     * 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);
    }

    /**
     * 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) {
        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 all files from tabulator table
     *
     */
    selectAll() {
        this.tabulatorTable.selectRow(this.tabulatorTable.getRows().filter(row => row.getData().type != 'directory' && this.checkFileType(row.getData(), this.allowedMimeTypes)));
        if (this.tabulatorTable.getSelectedRows().length > 0) {
            this.selectAllButton = false;
        }
    }

    /**
     * Deselect files from tabulator table
     *
     */
    deselectAll() {
        this.selectAllButton = true;
        this.tabulatorTable.getSelectedRows().forEach(row => row.deselect());
    }

    /**
     * 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;
    }

    getCloudLogo() {
        let cloudLogo = html `<dbp-icon name="cloud" class="nextcloud-logo-icon"></dbp-icon>`;
        if (this.nextcloudName === "TU Graz cloud") {
            cloudLogo = html`
            <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 97.6 81.74">
                  <g>
                    <path d="M89.8,22.7a28.51,28.51,0,0,0-16.9-9.1,27.84,27.84,0,0,0-14.8-12A24,24,0,0,0,48.9,0,28.36,28.36,0,0,0,20.6,27.4,22.42,22.42,0,0,0,13,70.11v-6.3A16.7,16.7,0,0,1,5.5,50a17,17,0,0,1,17-17h3.6V28.5A23,23,0,0,1,49,5.6a19.75,19.75,0,0,1,7.2,1.2h.1A22.48,22.48,0,0,1,68.9,17.5l.6,1.3,1.4.2a23.07,23.07,0,0,1,14.9,7.5,23.85,23.85,0,0,1-1.23,33.74v7A29.56,29.56,0,0,0,89.8,22.7Z"/>
                    <g>
                      <path d="M16.39,71.61H36.65V51.36H16.39Z" style="fill: #e4154b"/>
                      <path d="M38.67,71.61H58.93V51.36H38.67Z" style="fill: #e4154b"/>
                      <path d="M61,71.61H81.21V51.36H61Z" style="fill: #e4154b"/>
                      <path d="M26.52,81.74H46.78V61.49H26.52Z" style="fill: #e4154b"/>
                      <path d="M50.83,61.49H71.08V41.23H50.83Z" style="fill: #e4154b"/>
                    </g>
                  </g>
            </svg>
        `;
        }

        return cloudLogo;
    }

    static get styles() {
        // language=css
        return css`
            ${commonStyles.getGeneralCSS()}
            ${commonStyles.getButtonCSS()}
            ${commonStyles.getTextUtilities()}
            ${commonStyles.getModalDialogCSS()}
            ${commonStyles.getRadioAndCheckboxCss()}
            
            .visible {
                display: unset;
            }
            
            .block {
                margin-bottom: 10px;
            }

            .error{
                color: var(--dbp-danger-bg-color);
            }

            .force-no-select{
                -webkit-user-select: none;
                -moz-user-select: none;
                -ms-user-select: none;
                user-select: none;
            }

            .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;
                justify-self: end;  
                transition: all 0.5s ease;
                margin: auto;
            }

            .nextcloud-logo-icon{
                height: 100%;
            }

            .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;
            }

            .tabulator .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title{
                padding-top: 4px;
                padding-bottom: 4px;
                font-weight: normal;
                font-size: 1rem;
            }

            .tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="asc"] .tabulator-col-content .tabulator-arrow, 
            .tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="none"] .tabulator-col-content .tabulator-arrow,
            .tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="desc"] .tabulator-col-content .tabulator-arrow{
                padding-bottom: 6px;
            }

            .tabulator .tabulator-header, .tabulator .tabulator-header, .tabulator .tabulator-header .tabulator-col, .tabulator, .tabulator-row .tabulator-cell, .tabulator-row.tabulator-row-even,
            .tabulator .tabulator-header .tabulator-col.tabulator-sortable:hover{
                background-color: unset;
                background: unset;
                color: unset;
                border: none;
                font-size: 1rem;
            }

            .tabulator-row, .tabulator-row.tabulator-row-even{
                background-color: white;
            }
                        
            .tabulator-row.tabulator-selectable.tabulator-selectable:hover{
                background-color: white;
                color: var(--dbp-dark);
            }
            
            .tabulator-row.tabulator-selectable.tabulator-selected:hover, .tabulator-row.tabulator-selected{
                background-color: var(--dbp-dark);
                color: var(--dbp-light);
            }
            
            .tabulator .tabulator-header .tabulator-col .tabulator-col-content{
                display: inline-flex;
            }

            .tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="desc"] .tabulator-col-content .tabulator-arrow{
                top: 16px;
            }

            .tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="asc"] .tabulator-col-content .tabulator-arrow{
                border-top: none;
                border-bottom: 4px solid #666;
            }

            .tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="none"] .tabulator-col-content .tabulator-arrow{
                border-top: none;
                border-bottom: 4px solid #bbb;
            }

            .tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-arrow{
                border-left: 4px solid transparent;
                border-right: 4px solid transparent;
            }

            .tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="desc"] .tabulator-col-content .tabulator-arrow,
            .tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort="desc"] .tabulator-col-content .tabulator-arrow{
                border-top: 4px solid #666;
                border-bottom: none;
            }

            .tabulator-row, .tabulator-row.tabulator-row-even{
                padding-top: 10px;
                padding-bottom: 10px;
                border-top: 1px solid #eee;
            }

            .tabulator-header{
                padding-top: 10px;
                padding-bottom: 10px;
            }

            .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;
            }

            .tabulator .tabulator-tableHolder{
                overflow: hidden;
            }

            .tabulator .tabulator-tableHolder .tabulator-placeholder span{
                font-size: inherit;
                font-weight: inherit;
                color: inherit;
            }

            .add-folder{
                white-space: nowrap;
                align-self: end;
            }
            
            #select-all-wrapper{
                white-space: nowrap;
                align-self: end;
            }
            
            .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%;
            }
            
            #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: 31px;
            }
            
            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: -40px;
            }
            
            .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;
                }
            }
            
            .nextcloud-picker-icon{
                top: 0px;
                font-size: 1.4rem;
            }
            
            .spinner{
                font-size: 0.7em;
            }
            
            .nextcloud-picker-icon-disabled{
                opacity: 0.4;
            }
           
            @media only screen
            and (orientation: portrait)
            and (max-device-width: 765px) {   
                .inline-block{    
                    width: 100%;
                }
                
                .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;
                }

                .tabulator .tabulator-tableHolder{
                    white-space: inherit;
                }
                .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;
                }
                
            }
        `;
    }

    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})}">
                             ${this.getCloudLogo()}
                        </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})}">
                    <p class="m-inherit"><br>
                         ${i18n.t('nextcloud-file-picker.auth-info')}<br>${i18n.t('nextcloud-file-picker.auth-info-2')}  
                    </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 id="select-all-wrapper" class="${classMap({hidden: this.directoriesOnly})}">
                            <button class="button ${classMap({hidden: !this.selectAllButton})}"
                                    title="${i18n.t('nextcloud-file-picker.select-all-title')}"
                                    @click="${() => { this.selectAll(); }}">
                                    ${i18n.t('nextcloud-file-picker.select-all')}
                            </button>
                            <button class="button ${classMap({hidden: this.selectAllButton})}"
                                    title="${i18n.t('nextcloud-file-picker.select-nothing-title')}"
                                    @click="${() => { this.deselectAll(); }}">
                                    ${i18n.t('nextcloud-file-picker.select-nothing')}
                            </button>
                           
                        </div>
                    </div>
                    <table id="directory-content-table" class="force-no-select"></table>
                </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()); }}">${this.folderIsSelected}</button>
                        <button class="button select-button is-primary ${classMap({hidden: this.directoriesOnly})}"
                                @click="${() => { this.downloadFiles(this.tabulatorTable.getSelectedData()); }}">${i18n.t('nextcloud-file-picker.select-files')}</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">
                            <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>
                            <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> 
                        </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>
        `;
    }
}