Skip to content
Snippets Groups Projects
nextcloud-file-picker.js 103.70 KiB
import {createInstance} from './i18n';
import {css, html} from 'lit';
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 {classMap} from 'lit/directives/class-map.js';
import {createClient, parseXML, parseStat} from 'webdav/web';
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 {encrypt, decrypt, parseJwt} from './crypto.js';


/**
 * NextcloudFilePicker web component
 */
export class NextcloudFilePicker extends ScopedElementsMixin(DBPLitElement) {
    constructor() {
        super();
        this._i18n = createInstance();
        this.lang = this._i18n.language;

        this.auth = {};
        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 = Number.MAX_VALUE;
        this.loading = false;
        this._onReceiveWindowMessage = this.onReceiveWindowMessage.bind(this);

        this.folderIsSelected = this._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;
        this.storeSession = false;
        this.showSubmenu = false;
        this.bounCloseSubmenuHandler = this.closeSubmenu.bind(this);
        this.initateOpensubmenu = false;
        this.showAdditionalMenu = false;
        this.isInFavorites = false;
        this.isInRecent = false;
        this.userName = '';
    }
    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},
            auth: {type: Object},
            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},
            storeSession: {type: Boolean, attribute: 'store-nextcloud-session'},
            showSubmenu: {type: Boolean, attribute: false},
            showAdditionalMenu: { type: Boolean, attribute: 'show-nextcloud-additional-menu' },
            userName: { type: Boolean, attribute: false },
            storeSession: {type: Boolean, attribute: 'store-nextcloud-session'},
            showSubmenu: {type: Boolean, attribute: false},
            showAdditionalMenu: { type: Boolean, attribute: 'show-nextcloud-additional-menu' },
            userName: { type: Boolean, attribute: false },
        };

    }

    update(changedProperties) {
        changedProperties.forEach((oldValue, propName) => {
            switch (propName) {
                case "lang":
                    this._i18n.changeLanguage(this.lang);
                    break;
                case "auth":
                    this._updateAuth();
                    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;
        const i18n = this._i18n;
        this._loginStatus = '';
        this._loginState = [];
        this._loginCalled = false;

        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: [
                    {
                        width: 32,
                        minWidth: 32,
                        align: "center",
                        resizable: false,
                        headerSort: false,
                        formatter: "responsiveCollapse"
                    },
                    {
                        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}>`;
                            let html =  (cell.getValue() === "directory") ? `<${icon_tag} name="folder" class="nextcloud-picker-icon"></${icon_tag}>` : icon;
                            let div = this.shadowRoot.createElement("div");
                            div.innerHTML = html;
                            return div;
                        }
                    },
                    {
                        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: 84,
                        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: 58,
                        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: 150,
                        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.directoriesOnly && 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");
                },
                dataLoaded: () => {
                    if (this.tabulatorTable !== null) {
                        const that = this;
                        setTimeout(function(){
                            if (that._('.tabulator-responsive-collapse-toggle-open')) {
                                that._a('.tabulator-responsive-collapse-toggle-open').forEach(element => element.addEventListener("click", that.toggleCollapse.bind(that)));
                            }

                            if (that._('.tabulator-responsive-collapse-toggle-close')) {
                                that._a('.tabulator-responsive-collapse-toggle-close').forEach(element => element.addEventListener("click", that.toggleCollapse.bind(that)));
                            }
                        }, 0);
                    }
                }
            });


            // Strg + click select mode on desktop
            /*if (this.tabulatorTable.browserMobile === false) {
                this.tabulatorTable.options.selectableRangeMode = "click";
            }*/

            if (typeof this.allowedMimeTypes !== 'undefined' && this.allowedMimeTypes !== '' && !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();
                }
            });
        });
    }

    /**
     *  Request a re-render every time isLoggedIn()/isLoading() changes
     */
    _updateAuth() {
        this._loginStatus = this.auth['login-status'];

        let newLoginState = [this.isLoggedIn(), this.isLoading()];

        if (this._loginState.toString() !== newLoginState.toString()) {
            this.requestUpdate();
        }

        this._loginState = newLoginState;

        if (this.isLoggedIn() && !this._loginCalled ) {
            this._loginCalled = true;
            this.loginCallback();
        }
    }

    loginCallback() {
        this.checkLocalStorage();
    }

    /**
     * Returns if a person is set in or not
     *
     * @returns {boolean} true or false
     */
    isLoggedIn() {
        return (this.auth.person !== undefined && this.auth.person !== null);
    }

    /**
     * Returns true if a person has successfully logged in
     *
     * @returns {boolean} true or false
     */
    isLoading() {
        if (this._loginStatus === "logged-out")
            return false;

        return (!this.isLoggedIn() && this.auth.token !== undefined);
    }


    /**
     *
     */
    async checkLocalStorage() {
        if (!this.isLoggedIn() || !this.auth) {
            for (let key of Object.keys(localStorage)) {
                if (key.includes("nextcloud-webdav-username-") || key.includes("nextcloud-webdav-password-")) {
                    localStorage.removeItem(key);
                }
            }
            return;
        }
        const publicId = this.auth['person-id'];
        const token = parseJwt(this.auth.token);
        const sessionId = token ? token.sid : "";

        if (this.storeSession && sessionId
            && localStorage.getItem('nextcloud-webdav-username-' + publicId)
            && localStorage.getItem('nextcloud-webdav-password-' + publicId) ){
                try {
                    const userName = await decrypt(sessionId, localStorage.getItem('nextcloud-webdav-username-' + publicId));
                    const password = await decrypt(sessionId, localStorage.getItem('nextcloud-webdav-password-' + publicId));
                    this.webDavClient = createClient(
                        this.webDavUrl + '/' + userName,
                        {
                            username: userName,
                            password: password
                        }
                    );

                    this.isPickerActive = true;
                    this.loadDirectory(this.directoryPath);
                } catch (e) {
                    localStorage.removeItem('nextcloud-webdav-username-' + publicId);
                    localStorage.removeItem('nextcloud-webdav-password-' + publicId);
                    return;
                }
        }
    }


    /**
     * check mime type of row
     *
     * @param data
     * @param filterParams
     */
    checkFileType(data, filterParams) {
        if (filterParams === '')
            return true;
        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;
    }

    async openFilePicker() {
        const i18n = this._i18n;
        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");
        } else {
            this.loadDirectory(this.directoryPath, this.webDavClient);
        }
    }

    _a(selector) {
        return this.shadowRoot === null ? this.querySelectorAll(selector) : this.shadowRoot.querySelectorAll(selector);
    }

    async 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
                    }
                );


                if (this.storeSession && this.isLoggedIn() && this._("#remember-checkbox") && this._("#remember-checkbox").checked) {
                    const publicId = this.auth['person-id'];
                    const token = parseJwt(this.auth.token);
                    const sessionId = token ? token.sid : "";
                    if (sessionId) {
                        const encrytedName = await encrypt(sessionId, data.loginName);
                        const encrytedToken = await encrypt(sessionId, data.token);
                        localStorage.setItem('nextcloud-webdav-username-' + publicId, encrytedName);
                        localStorage.setItem('nextcloud-webdav-password-' + publicId, encrytedToken);
                    }
                }

                this.loadDirectory(this.directoryPath);
                this.userName = data.loginName;
            }
        }
    }

    /**
     * 
     * @param {*} data 
     * @returns reduced list of objects, including users files
     */
    filterUserFilesOnly(data) { //TODO verify
        // R = Share, S = Shared Folder, M = Group folder or external source, G = Read, D = Delete, NV / NVW = Write, CK = Create
        let result = [];
        for (let i = 0; i < data.length; i++) {
            if (data) {
                let file_perm = data[i].props.permissions;
                if (!file_perm.includes('M') && !file_perm.includes('S')) {
                    result.push(data[i]);
                }
            }
        }
        return result;
    }

    /**
     * 
     * @param {*} path 
     * @returns array including file path and base name
     */
    parseFileAndBaseName(path) {
        if (path[0] !== "/") { //TODO verify
            path = "/" + path;
        }
        while (/^.+\/$/.test(path)) {
            path = path.substr(0, path.length - 1);
        }
        path = decodeURIComponent(path);

        let array1 = this.webDavUrl.split('/');
        let array2 = path.split('/');
        for (let i = 0; i < array2.length; i++) {
            let item2 = array2[i];
            array1.forEach(item1 => {
                if (item1 === item2) {
                    array2.shift();
                    i--;
                }
            });
        }
        array2.shift();

        let basename = array2[array2.length - 1];
        let filename = '/' + array2.join('/');
        
        return [ filename, basename ];
    }

    /**
     * 
     * @param {*} response 
     * @returns list of file objects containing corresponding information
     */
    mapResponseToObject(response) {
        let results = [];

        response.forEach(item => {
            const [ filePath, baseName ] = this.parseFileAndBaseName(item.href);

            const prop = item.propstat.prop;
            let etag = typeof prop.getetag === 'string' ? prop.getetag.replace(/"/g, '') : null;
            let sizeVal = prop.getcontentlength ? prop.getcontentlength : '0';
            let fileType = prop.resourcetype && typeof prop.resourcetype === 'object' && typeof prop.resourcetype.collection !== 'undefined' ? 'directory' : 'file';
            
            let mimeType;
            if (fileType === 'file') {
                mimeType = prop.getcontenttype && typeof prop.getcontenttype === 'string' ? prop.getcontenttype.split(';')[0] : '';
            }

            let propsObject =  { getetag: etag, getlastmodified: prop.getlastmodified, getcontentlength: sizeVal, 
                                permissions: prop.permissions, resourcetype: fileType, getcontenttype: prop.getcontenttype };

            let statObject = { basename: baseName, etag: etag, filename: filePath, lastmod: prop.getlastmodified, 
                mime: mimeType, props: propsObject, size: parseInt(sizeVal, 10), type: fileType };

            results.push(statObject);
        });

        return results;
    }
    


    /**
     * 
     * @param {*} path 
     * @returns array including file path and base name
     */
    parseFileAndBaseName(path) {
        if (path[0] !== "/") { //TODO verify
            path = "/" + path;
        }
        while (/^.+\/$/.test(path)) {
            path = path.substr(0, path.length - 1);
        }
        path = decodeURIComponent(path);

        let array1 = this.webDavUrl.split('/');
        let array2 = path.split('/');
        for (let i = 0; i < array2.length; i++) {
            let item2 = array2[i];
            array1.forEach(item1 => {
                if (item1 === item2) {
                    array2.shift();
                    i--;
                }
            });
        }
        array2.shift();

        let basename = array2[array2.length - 1];
        let filename = '/' + array2.join('/');
        
        return [ filename, basename ];
    }

    /**
     * 
     * @param {*} response 
     * @returns list of file objects containing corresponding information
     */
    mapResponseToObject(response) {
        let results = [];

        response.forEach(item => {
            const [ filePath, baseName ] = this.parseFileAndBaseName(item.href);

            const prop = item.propstat.prop;
            let etag = typeof prop.getetag === 'string' ? prop.getetag.replace(/"/g, '') : null;
            let sizeVal = prop.getcontentlength ? prop.getcontentlength : '0';
            let fileType = prop.resourcetype && typeof prop.resourcetype === 'object' && typeof prop.resourcetype.collection !== 'undefined' ? 'directory' : 'file';
            
            let mimeType;
            if (fileType === 'file') {
                mimeType = prop.getcontenttype && typeof prop.getcontenttype === 'string' ? prop.getcontenttype.split(';')[0] : '';
            }

            let propsObject =  { getetag: etag, getlastmodified: prop.getlastmodified, getcontentlength: sizeVal, 
                                permissions: prop.permissions, resourcetype: fileType, getcontenttype: prop.getcontenttype };

            let statObject = { basename: baseName, etag: etag, filename: filePath, lastmod: prop.getlastmodified, 
                mime: mimeType, props: propsObject, size: parseInt(sizeVal, 10), type: fileType };

            results.push(statObject);
        });

        return results;
    }
    
    /**
     * Loads the favorites from WebDAV
     *
     */
    loadFavorites() {
        this.hideMoreMenu();
        const i18n = this._i18n;

        if (typeof this.directoryPath === 'undefined' || this.directoryPath === undefined) {
            this.directoryPath = '';
        }

        console.log("load nextcloud favorites");
        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 = '';
        this.isInRecent = false;
        this.isInFavorites = true;

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

        //see https://github.com/perry-mitchell/webdav-client#customRequest
        this.webDavClient
            .customRequest('/', {method: 'REPORT', responseType: "text/xml", details: true, data: "<?xml version=\"1.0\"?>" +
                    "   <oc:filter-files  xmlns:d=\"DAV:\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">" +
                    "       <oc:filter-rules>" +
                    "           <oc:favorite>1</oc:favorite>" +
                    "       </oc:filter-rules>" +
                    "       <d:prop>" +
                    "           <d:getlastmodified />" +
                    "           <d:resourcetype />" +
                    "           <d:getcontenttype />" +
                    "           <d:getcontentlength />" +
                    "           <d:getetag />" +
                    "           <oc:permissions />" +
                    "        </d:prop>" +
                    "   </oc:filter-files>"
                })
            .then(contents => {
                parseXML(contents.data).then(davResp => {
                    // console.log("-contents.data-----", davResp);
                    let dataObject = this.mapResponseToObject(davResp.multistatus.response);

                    this.loading = false;
                    this.statusText = "";
                    this.tabulatorTable.setData(dataObject);
                    this.isPickerActive = true;
                    this._(".nextcloud-content").scrollTop = 0;
                    this._("#download-button").setAttribute("disabled", "true");
                });
            }).catch(error => { //TODO verify error catching
                console.error(error.message);

                // on Error: try to reload with home directory
                if (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;
                }
                this.isInFavorites = false;
        });
    }

    /**
     * Loads recent files and folders from WebDAV
     *
     */
    loadRecent() {
        this.hideMoreMenu();
        const i18n = this._i18n;

        if (typeof this.directoryPath === 'undefined' || this.directoryPath === undefined) {
            this.directoryPath = '';
        }

        console.log("load recent files");
        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 = '';
        this.isInFavorites = false;
        this.isInRecent = true;

        let date = new Date();
        date.setMonth(date.getMonth() - 3);
        let searchDate = date.toISOString().split('.')[0] + 'Z';

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

        //see https://github.com/perry-mitchell/webdav-client#customRequest
        this.webDavClient
            .customRequest('../..', { method: 'SEARCH', responseType: "text/xml", headers: { 'Content-Type': "text/xml" }, details: true, data: "<?xml version=\"1.0\" encoding='UTF-8'?>" +
                "   <d:searchrequest xmlns:d=\"DAV:\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">" +
                "       <d:basicsearch>" +
                "           <d:select>" +
                "               <d:prop>" +
                "                   <d:getlastmodified />" +
                "                   <d:resourcetype />" +
                "                   <d:getcontenttype />" +
                "                   <d:getcontentlength />" +
                "                   <d:getetag />" +
                "                   <oc:permissions />" +
                "                   <oc:size/>"+
                "                   <oc:owner-id/>" +
                "                   <oc:owner-display-name/>" +
                "               </d:prop>" +
                "           </d:select>" +
                "           <d:from>" +
                "               <d:scope>" +
                "                   <d:href>/files/" + this.userName + "/</d:href>" +
                "                   <d:depth>infinity</d:depth>" +
                "               </d:scope>" + 
                "           </d:from>" +
                "           <d:where> " +
                "               <d:gte>" +
                "                   <d:prop>" +
                "                      <d:getlastmodified/>" +
                "                   </d:prop>" +
                "                   <d:literal>" + searchDate + "</d:literal>" +
                "               </d:gte>" +
                "           </d:where>" +
                "           <d:orderby>" +
                "               <d:order>" +
                "                   <d:prop>" +
                "                       <d:getlastmodified/>" +
                "                   </d:prop>" +
                "                   <d:descending/>" +
                "               </d:order>" +
                "           </d:orderby>" +
                "           <d:limit>"+
                "               <d:nresults>100</d:nresults>" +
                "           </d:limit>"+
                "       </d:basicsearch>" +
                "   </d:searchrequest>"
            })
            .then(contents => {
                parseXML(contents.data).then(davResp => {
                    console.log('davResp', davResp);

                    let dataObject = this.mapResponseToObject(davResp.multistatus.response);
                    console.log("-contents.data-----", dataObject);

                    if (this._("#user_files_only") && this._("#user_files_only").checked) {
                        dataObject = this.filterUserFilesOnly(dataObject);
                        // console.log('show only my files');
                    }

                    this.loading = false;
                    this.statusText = "";
                    this.tabulatorTable.setData(dataObject);
                    this.tabulatorTable.setSort([
                        {column: "lastmod", dir: "desc"}
                    ]);
                    this.isPickerActive = true;
                    this._(".nextcloud-content").scrollTop = 0;
                    this._("#download-button").setAttribute("disabled", "true");
                });
            }).catch(error => {
                console.error(error.message);

                // on Error: try to reload with home directory
                if (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;
                }

                this.isInRecent = false;
        });
    }

    toggleCollapse(e) {
        const table = this.tabulatorTable;
        setTimeout(function() {
            table.redraw();
        }, 0);
    }

    /**
     * Loads the directory from WebDAV
     *
     * @param path
     */
    loadDirectory(path) {
        const i18n = this._i18n;
        if (typeof this.directoryPath === 'undefined' || this.directoryPath === undefined) {
            this.directoryPath = '';
        }
        if (path === undefined) {
            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"></dbp-icon>
            </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 => {
                this.loading = false;
                this.statusText = "";
                this.tabulatorTable.setData(contents.data);
                this.isPickerActive = true;
                this.isInFavorites = false;
                this.isInRecent = false;
                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"></dbp-icon>
                </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, files.length));

        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
     * @param maxUpload
     */
    downloadFile(fileData, maxUpload) {

        const i18n = this._i18n;
        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, "maxUpload": maxUpload};
                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) {
        if (this.isInFavorites) {
            this.statusText = html`<span class="error"> ${ i18n.t('nextcloud-file-picker.error-save-to-favorites') } </span>`;
            return;
        } else if (this.isInRecent) { //TODO verify
            this.statusText = html`<span class="error"> ${ i18n.t('nextcloud-file-picker.error-save-to-recent') } </span>`;
            return;
        }
        
        const i18n = this._i18n;
        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) {
        const i18n = this._i18n;
        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) {
        const i18n = this._i18n;
        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});
            // contentLength: https://github.com/perry-mitchell/webdav-client/issues/266
            await this.webDavClient
                .putFileContents(path, file, {
                    contentLength: file.size,
                    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 {
                        throw error;
                    }
                });
        } 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() {
        const i18n = this._i18n;
        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
        // contentLength: https://github.com/perry-mitchell/webdav-client/issues/266
        await this.webDavClient
            .putFileContents(path, file, {
                contentLength: file.size,
                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);
                    }
                } else {
                    throw error;
                }
            });

        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) {
        const i18n = this._i18n;
        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() {
        const i18n = this._i18n;
        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() {
        const i18n = this._i18n;
        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() {
        const i18n = this._i18n;
        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;
    }

    closeSubmenu() {
        if (this.initateOpensubmenu && this.showSubmenu) {
            this.initateOpensubmenu = false;
            return;
        }
        if (this.showSubmenu){
            document.removeEventListener('click', this.bounCloseSubmenuHandler);
            this.showSubmenu = false;
        }
    }

    toggleSubmenu() {
        if (!this.showSubmenu) {
            this.initateOpensubmenu = true;
            this.showSubmenu = true;
            document.addEventListener('click', this.bounCloseSubmenuHandler);
        }
    }

    logOut() {
        this.webDavClient = null;
        this.isPickerActive = false;
        if (this.auth) {
            const publicId = this.auth['person-id'];
            localStorage.removeItem('nextcloud-webdav-username' + publicId);
            localStorage.removeItem('nextcloud-webdav-password' + publicId);
        }
    }

    /**
     * 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() {
        const i18n = this._i18n;
        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;
    }

    toggleMoreMenu() {
        const menu = this.shadowRoot.querySelector("ul.extended-menu");
        const menuStart = this.shadowRoot.querySelector("a.extended-menu-link");

        if (menu === null || menuStart === null) {
            return;
        }

        menu.classList.toggle('hidden');

        if (this.menuHeight === -1) {
            this.menuHeight = menu.clientHeight;
        }

        let topValue = menuStart.getBoundingClientRect().bottom;
        let isMenuOverflow = this.menuHeight + topValue >= window.innerHeight ? true : false;
        
        if (isMenuOverflow && !menu.classList.contains('hidden')) {
            menu.setAttribute('style', 'position: fixed;top: ' + topValue + 'px;bottom: 0;border-bottom: 0;overflow-y: auto;');
            menu.scrollTop = 0;
            document.body.setAttribute('style', 'overflow:hidden;');
        } else if (isMenuOverflow && menu.classList.contains('hidden')) {
            document.body.removeAttribute('style', 'overflow:hidden;');
            menu.removeAttribute('style');
        }
    }

    hideMoreMenu() {
        const menu = this.shadowRoot.querySelector("ul.extended-menu");
        if (menu && !menu.classList.contains('hidden'))
            this.toggleMoreMenu();
    }

    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 {
                background-color: var(--dbp-base-light);
                color: var(--dbp-danger-dark);
            }

            .filter-options-wrapper {
                padding-right: 0px;
                padding-top: 10px;
                padding-bottom: 10px;
                padding-left: 0px;
            }

            .extended-menu li {
                padding: 7px;
                padding-right: 46px;
                border-bottom: 1px solid #f3f3f3;
            }

            .extended-menu li.active {
                background-color: var(--dbp-dark);
                color: var(--dbp-light);
            }
            .extended-menu li.active a:hover {
                color: var(--dbp-light);
            }

            .extended-menu a.inactive {
                color: var(--dbp-muted-text);
                pointer-events: none;
                cursor: default;
            }

            .extended-menu a {
                padding: 8px;
            }

            .extended-menu {
                list-style: none;
                border: black 1px solid;
                position: absolute;
                background-color: white;
                z-index: 1000;
                right: 0px;
            }

            .extended-menu a:hover {
                color: #E4154B;
            }

            ul.extended-menu li.close {
                display: block;
                padding: 7px 15px 7px 15px;
                text-align: right;
                cursor: pointer;
            }

            .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: var(--dbp-base-light);
                width: 100%;
                padding-top: 10px;
            }

            .nextcloud-footer-grid {
                width: 100%;
                display: flex;
                align-items: center;
                flex-direction: row-reverse;
                justify-content: space-between;
            }


            .additional-menu {
                white-space: nowrap;
                align-self: end;
                height: 33px;
                margin-right: 5px;
            }

            .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: var(--dbp-text-muted-light);
            }

            #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: var(--dbp-border-dark);
            }

            .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: var(--dbp-text-muted-light);
            }

            .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: var(--dbp-text-dark);
                background-color: var(--dbp-base-light);
            }

            .nextcloud-nav {
                position: relative;
            }

            .inline-block {
                position: absolute;
                right: 0px;
                z-index: 1;
                background-color: var(--dbp-base-light);
                bottom: -45px;
            }

            .addRowAnimation {
                color: var(--dbp-text-dark);
                animation: added 0.4s ease;
            }

            #abortButton {
                background-color: var(--dbp-base-light);
                color: var(--dbp-danger-dark);
            }

            #abortButton:hover {
                color: var(--dbp-text-light);
            }
            
            #submenu {
                height: 33px;
                width: 33px;
                justify-content: center;
                display: flex;
                align-items: center;
                cursor: pointer;
            }
            
            .submenu-icon {
                margin-top: -5px;
            }
            
            #submenu-content {
                position: absolute;
                right: 0px;
                top: 33px;
                z-index: 1;
            }

            #submenu-content button{
                border-radius: 0px;
            }
            
            .menu-buttons {
                display: flex;
                gap: 1em;
            }
            
            #submenu {
                height: 33px;
                width: 33px;
                justify-content: center;
                display: flex;
                align-items: center;
                cursor: pointer;
            }
            
            .submenu-icon {
                margin-top: -5px;
            }
            
            #submenu-content {
                position: absolute;
                right: 0px;
                top: 33px;
                z-index: 1;
            }
            
            .menu-buttons {
                display: flex;
                gap: 1em;
            }

            @keyframes added {
                0% {
                    background-color: var(--dbp-base-light);
                }
                50% {
                    background-color: var(--dbp-success-light);
                }
                100% {
                    background-color: var(--dbp-base-light);
                }
            }

            .spinner {
                font-size: 0.7em;
            }

            .nextcloud-picker-icon-disabled {
                opacity: 0.4;
            }

            .button.button, .button, button.dt-button {
                background-color: var(--dbp-base-light);
            }

            #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: 34px;
            }

            .remember-container .checkmark{
                left: 7px;
            }

            .more-menu {
                height: 22.4px;
                width: 22.4px;
                top: 8px;
            }

            .nextcloud-nav a.home-link {
                font-size: 1.4em;
            }

            @media only screen
            and (orientation: portrait)
            and (max-width: 768px) {
                .additional-menu button {
                    float: right;
                }

                .additional-menu {
                    position: absolute;
                    right: 0px;
                    margin-right: 10px;
                }

                /* .nextcloud-nav {
                    display: block; TODO verify if this is enough
                } */

                .additional-menu {
                    position: inherit;
                }

                .inline-block {
                    width: inherit;
                    position: absolute;
                    right: 52px;
                    z-index: 1;
                    background-color: var(--dbp-base-light);
                    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 i18n = this._i18n;
        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.storeSession || !this.isLoggedIn()})}">
                        <label class="button-container remember-container">
                            ${i18n.t('nextcloud-file-picker.remember-me', {name: this.nextcloudName})}
                            <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>
<!-- TODO -->
                        <div class="additional-menu ${classMap({hidden: !this.showAdditionalMenu})}">
                            
                            <a class="extended-menu-link" @click="${() => { this.toggleMoreMenu(); }}" title="${i18n.t('nextcloud-file-picker.more-menu')}">
                                <dbp-icon name="more-filled" class="more-menu"></dbp-icon>
                            </a>
                            <ul class='extended-menu hidden'>
                                <li class="${classMap({active: this.isInFavorites})}" id="favorites-item">
                                    <a class="" @click="${this.loadFavorites}">
                                        ${i18n.t('nextcloud-file-picker.favorites-link-text')}
                                    </a>
                                </li>
                                <li class="${classMap({active: this.isInRecent})}" id="recent-item">
                                    <a class="" @click="${this.loadRecent}">
                                        ${i18n.t('nextcloud-file-picker.recent-files-link-text')}
                                    </a>
                                </li>
                                <li class="${classMap({hidden: !this.directoriesOnly})}">
                                    <a class="${classMap({inactive: this.isInRecent || this.isInFavorites})}" @click="${() => { this.openAddFolderDialogue(); }}">
                                        ${i18n.t('nextcloud-file-picker.add-folder')}
                                    </a>
                                </li>
                            
                                <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>

                    <!-- TODO begin -->

                        <!-- <div class="menu-buttons">
                            <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> -->

<!-- TODO end -->
<!-- 
                        <div class="additional-menu ${classMap({hidden: !this.showAdditionalMenu})}">
                            
                            <a class="extended-menu-link" @click="${() => { this.toggleMoreMenu(); }}" title="${i18n.t('nextcloud-file-picker.more-menu')}">
                                <dbp-icon name="more-filled" class="more-menu"></dbp-icon>
                            </a>
                            <ul class='extended-menu hidden'>
                                <li class="${classMap({active: this.isInFavorites})}" id="favorites-item">
                                    <a class="" @click="${this.loadFavorites}">
                                        ${i18n.t('nextcloud-file-picker.favorites-link-text')}
                                    </a>
                                </li>
                                <li class="${classMap({active: this.isInRecent})}" id="recent-item">
                                    <a class="" @click="${this.loadRecent}">
                                        ${i18n.t('nextcloud-file-picker.recent-files-link-text')}
                                    </a>
                                </li>
                                <li class="${classMap({hidden: !this.directoriesOnly})}">
                                    <a class="${classMap({inactive: this.isInRecent || this.isInFavorites})}" @click="${() => { this.openAddFolderDialogue(); }}">
                                        ${i18n.t('nextcloud-file-picker.add-folder')}
                                    </a>
                                </li>
                            
                                <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>
-->
                                    <!-- TODO end -->
<!-- 
                                </div>
-->
                            <!-- <button class="button ${classMap({hidden: this.showAdditionalMenu})}"
                                    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> -->
<!--
                                <li class="close" @click="${this.hideMoreMenu}"><dbp-icon name="close" style="color: red"></dbp-icon></li>
                            </ul>
                        
                        </div>
                            <div id="submenu" class="${classMap({hidden: !this.storeSession})}"
                                title="${i18n.t('nextcloud-file-picker.open-submenu')}"
                                @click="${() => {
                                    this.toggleSubmenu();
                                }}">
                                <dbp-icon name="menu-dots" class="submenu-icon"></dbp-icon>
                                <div id="submenu-content" class="${classMap({hidden: !this.showSubmenu})}">
                                    <button class="button"
                                            title="${i18n.t('nextcloud-file-picker.log-out')}"
                                            @click="${() => {
                                                this.logOut();
                                            }}">
<<<<<<< HEAD
<<<<<<< HEAD
                                            ${i18n.t('nextcloud-file-picker.log-out')}
=======
                                        Abmelden
>>>>>>> Add sessionsaving in session storage to nextcloud filepicker, add encrypt and decrypt functionality
=======
                                            ${i18n.t('nextcloud-file-picker.log-out')}
>>>>>>> Change log out to disconnect in nextcloud filepicker
                                    </button>
                                </div>
                            </div>
                        </div>
                    </div> 
-->
                    <div class="filter-options-wrapper ${classMap({hidden: !this.isInRecent})}">
                        <label id="user_files_only_wrapper" class="button-container">
                        <!-- ${i18n.t('nextcloud-file-picker.replace-mode-all')} --> Show only my files <!--TODO-->
                            <input type="checkbox" id="user_files_only" name="user_files_only" value="user_files_only" > <!--@click="${() => { this.filterUserFilesOnly(); }}"-->
                            <span class="checkmark" id="user_files_only_checkmark"></span>
                        </label>
                    </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>
        `;
    }
}