@digital-blueprint/lunchlottery-app
Version:
[GitHub Repository](https://github.com/digital-blueprint/lunchlottery-app) | [npmjs package](https://www.npmjs.com/package/@digital-blueprint/lunchlottery-app) | [Unpkg CDN](https://unpkg.com/browse/@digital-blueprint/lunchlottery-app/)
1,219 lines (1,122 loc) • 140 kB
JavaScript
import {createInstance} from './i18n';
import {css, html} from 'lit';
import {ScopedElementsMixin, LangMixin} from '@dbp-toolkit/common';
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 * as tabulatorStyles from '@dbp-toolkit/tabulator-table/src/tabulator-table-styles';
import {createClient, parseXML} from 'webdav/web';
import {classMap} from 'lit/directives/class-map.js';
import {humanFileSize} from '@dbp-toolkit/common/i18next';
import {TabulatorFull as 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';
/**
* A wrapper for the webdav putFileContents method that also handles Blob/File
* (inefficiently, but works). In theory this could be fixed upstream, if someone
* feels strongly about it.
*
* https://github.com/perry-mitchell/webdav-client#putfilecontents
*/
async function customPutFileContents(client, filename, data, options = {}) {
if (data instanceof Blob) {
// Broke with 4.x
// contentLength: https://github.com/perry-mitchell/webdav-client/issues/266
if (options.contentLength === true || options.contentLength === undefined) {
options.contentLength = data.size;
}
// Broke with 5.x
// Blob: https://github.com/perry-mitchell/webdav-client/issues/352
data = await data.arrayBuffer();
}
return client.putFileContents(filename, data, options);
}
/**
* NextcloudFilePicker web component
*/
export class NextcloudFilePicker extends LangMixin(
ScopedElementsMixin(DBPLitElement),
createInstance,
) {
constructor() {
super();
this.auth = {};
this.authUrl = '';
this.webDavUrl = '';
this.fullWebDavUrl = '';
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.boundCloseAdditionalMenuHandler = this.hideAdditionalMenu.bind(this);
this.initateOpenAdditionalMenu = false;
this.isInFavorites = false;
this.isInFilteredRecent = false;
this.isInRecent = false;
this.userName = '';
this.menuHeightBreadcrumb = -1;
this.boundCloseBreadcrumbMenuHandler = this.hideBreadcrumbMenu.bind(this);
this.initateOpenBreadcrumbMenu = false;
this.boundClickOutsideNewFolderHandler = this.deleteNewFolderEntry.bind(this);
this.initateOpenNewFolder = false;
this.disableRowClick = false;
this.boundRefreshOnWindowSizeChange = this.refreshOnWindowSizeChange.bind(this);
this.boundCancelNewFolderHandler = this.cancelNewFolder.bind(this);
this.boundSelectHandler = this.selectAllFiles.bind(this);
}
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,
auth: {type: Object},
authUrl: {type: String, attribute: 'auth-url'},
webDavUrl: {type: String, attribute: 'web-dav-url'},
fullWebDavUrl: {type: String, attribute: false},
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},
userName: {type: Boolean, attribute: false},
storeSession: {type: Boolean, attribute: 'store-nextcloud-session'},
disableRowClick: {type: Boolean, attribute: false},
};
}
update(changedProperties) {
changedProperties.forEach((oldValue, propName) => {
switch (propName) {
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');
}
break;
}
});
super.update(changedProperties);
}
disconnectedCallback() {
window.removeEventListener('message', this._onReceiveWindowMessage);
window.removeEventListener('resize', this.boundRefreshOnWindowSizeChange);
// deregister tabulator table callback events
this.tabulatorTable.off('tableBuilt');
this.tabulatorTable.off('rowSelectionChanged');
this.tabulatorTable.off('rowClick');
this.tabulatorTable.off('rowAdded');
this.tabulatorTable.off('dataLoaded');
super.disconnectedCallback();
}
connectedCallback() {
super.connectedCallback();
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/5.1
this.tabulatorTable = new Tabulator(this._('#directory-content-table'), {
layout: 'fitColumns',
selectableRows: this.maxSelectedItems,
placeholder: this.directoriesOnly
? i18n.t('nextcloud-file-picker.no-data')
: i18n.t('nextcloud-file-picker.no-data-type'),
responsiveLayout: 'collapse',
responsiveLayoutCollapseStartOpen: false,
columnHeaderVertAlign: 'middle',
columnDefaults: {
vertAlign: 'middle',
hozAlign: 'left',
resizable: false,
},
columns: [
{
minWidth: 40,
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',
hozAlign: 'center',
width: 40,
headerSort: false,
responsive: 1,
formatter: (cell, formatterParams, onRendered) => {
let disabled = this.directoriesOnly
? 'nextcloud-picker-icon-disabled'
: '';
let icon =
`<dbp-icon name="empty-file" class="nextcloud-picker-icon ` +
disabled +
`"></dbp-icon>`;
let html =
cell.getValue() === 'directory'
? `<dbp-icon name="folder" class="nextcloud-picker-icon"></dbp-icon>`
: icon;
let div = this.createScopedElement('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) => {
let div = this.createScopedElement('div');
div.classList.add('filename');
div.innerHTML = cell.getValue();
return div;
},
},
{
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'); // TODO check this
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');
}
if (!this.directoriesOnly && typeof data.mime === 'undefined') {
row.getElement().classList.add('no-select-styles');
}
},
});
this.tabulatorTable.on('tableBuilt', this.tableBuiltFunction.bind(this));
this.tabulatorTable.on(
'rowSelectionChanged',
this.rowSelectionChangedFunction.bind(this),
);
this.tabulatorTable.on('rowClick', this.rowClickFunction.bind(this));
this.tabulatorTable.on('rowAdded', this.rowAddedFunction.bind(this));
this.tabulatorTable.on('dataLoaded', this.dataLoadedFunction.bind(this));
if (
typeof this.allowedMimeTypes !== 'undefined' &&
this.allowedMimeTypes !== '' &&
!this.directoriesOnly
) {
this.tabulatorTable.setFilter(this.checkFileType, this.allowedMimeTypes);
}
window.addEventListener('resize', this.boundRefreshOnWindowSizeChange);
});
}
tableBuiltFunction() {
if (this._('#select_all')) {
this._('#select_all').addEventListener('click', this.boundSelectHandler);
}
if (this.directoriesOnly && this._('#select_all_wrapper')) {
this._('#select_all_wrapper').classList.remove('button-container');
this._('#select_all_wrapper').classList.add('hidden');
}
}
rowSelectionChangedFunction(data, rows) {
const i18n = this._i18n;
if (!this.disableRowClick) {
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();
}
}
rowClickFunction(e, row) {
const i18n = this._i18n;
const data = row.getData();
if (!row.getElement().classList.contains('no-select') && !this.disableRowClick) {
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();
}
}
rowAddedFunction(row) {
if (!this.disableRowClick) {
row.getElement().classList.toggle('addRowAnimation');
}
}
dataLoadedFunction(data) {
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);
}
}
/**
* 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.checkLocalStorage();
}
}
/**
* Returns if a person is set in or not
*
* @returns {boolean} true or false
*/
isLoggedIn() {
return this.auth && this.auth.token;
}
/**
* 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-') ||
key.includes('nextcloud-webdav-url-')
) {
localStorage.removeItem(key);
}
}
return;
}
const publicId = this.auth['user-id'];
const token = this.auth.token ? parseJwt(this.auth.token) : null;
const sessionId = token ? token.sid : '';
if (
this.storeSession &&
sessionId &&
localStorage.getItem('nextcloud-webdav-username-' + publicId) &&
localStorage.getItem('nextcloud-webdav-password-' + publicId) &&
localStorage.getItem('nextcloud-webdav-url-' + 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.fullWebDavUrl = await decrypt(
sessionId,
localStorage.getItem('nextcloud-webdav-url-' + publicId),
);
this.webDavClient = createClient(this.fullWebDavUrl, {
username: userName,
password: password,
});
this.userName = userName;
this.isPickerActive = true;
this.loadDirectory(this.directoryPath);
} catch {
localStorage.removeItem('nextcloud-webdav-username-' + publicId);
localStorage.removeItem('nextcloud-webdav-password-' + publicId);
localStorage.removeItem('nextcloud-webdav-url-' + 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;
this.disableRowClick = false;
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.renderRoot.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,
},
);
this.fullWebDavUrl = data.webdavUrl;
if (
this.storeSession &&
this.isLoggedIn() &&
this._('#remember-checkbox') &&
this._('#remember-checkbox').checked
) {
const publicId = this.auth['user-id'];
const token = this.auth.token ? parseJwt(this.auth.token) : null;
const sessionId = token ? token.sid : '';
if (sessionId) {
const encrytedName = await encrypt(sessionId, data.loginName);
const encrytedToken = await encrypt(sessionId, data.token);
const encryptedUrl = await encrypt(sessionId, data.webdavUrl);
localStorage.setItem('nextcloud-webdav-username-' + publicId, encrytedName);
localStorage.setItem(
'nextcloud-webdav-password-' + publicId,
encrytedToken,
);
localStorage.setItem('nextcloud-webdav-url-' + publicId, encryptedUrl);
}
}
this.loadDirectory(this.directoryPath);
this.userName = data.loginName;
}
}
}
toggleCollapse(e) {
const table = this.tabulatorTable;
// give a chance to draw the table
// this is for getting more hight in tabulator table, when toggle is called
setTimeout(function () {
table.redraw();
}, 0);
}
/**
*
* @param {*} data
* @returns {Array} reduced list of objects, including users files
*/
filterUserFilesOnly(data) {
// 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 {Array} 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.hideAdditionalMenu();
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.isInFilteredRecent = 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.tabulatorTable.setSort([
{column: 'basename', dir: 'asc'},
{column: 'type', dir: 'asc'},
]);
if (this._('.tabulator-placeholder-contents')) {
this._('.tabulator-placeholder-contents').innerText = i18n.t(
'nextcloud-file-picker.no-favorites',
{
name: this.nextcloudName,
},
);
}
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
*
*/
loadAllRecentFiles() {
this.hideAdditionalMenu();
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.isInFilteredRecent = false;
this.isInRecent = true;
let date = new Date();
date.setMonth(date.getMonth() - 3);
let searchDate = date.toISOString().split('.')[0] + 'Z';
if (this.webDavClient === null || this.userName === 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>' +
this.fullWebDavUrl +
'</d:href>' +
' <d:depth>infinity</d:depth>' +
' </d:scope>' +
' </d:from>' +
' <d:where> ' +
' <d:and>' +
' <d:gte>' +
' <d:prop>' +
' <d:getlastmodified/>' +
' </d:prop>' +
' <d:literal>' +
searchDate +
'</d:literal>' +
' </d:gte>' +
' <d:or>' +
this.getMimeTypes() +
' </d:or>' +
' </d:and>' +
' </d:where>' +
' <d:orderby>' +
' <d:order>' +
' <d:prop>' +
' <d:getlastmodified/>' +
' </d:prop>' +
' <d:descending/>' +
' </d:order>' +
' </d:orderby>' +
' <d:limit>' +
' <d:nresults>15</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);
this.loading = false;
this.statusText = '';
this.tabulatorTable.setData(dataObject);
this.tabulatorTable.setSort([{column: 'lastmod', dir: 'desc'}]);
if (this._('.tabulator-placeholder-contents')) {
this._('.tabulator-placeholder-contents').innerText = i18n.t(
'nextcloud-file-picker.no-recent-files',
{
name: this.nextcloudName,
},
);
}
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;
});
}
getMimeTypes() {
let mimePart = '';
if (
this.allowedMimeTypes &&
this.allowedMimeTypes !== 0 &&
this.allowedMimeTypes !== '*/*'
) {
const mimeTypes = this.allowedMimeTypes.split(',');
mimeTypes.forEach((str) => {
mimePart +=
' <d:like>' +
' <d:prop>' +
' <d:getcontenttype/>' +
' </d:prop>' +
' <d:literal>' +
str +
'</d:literal>' +
' </d:like>';
});
} else {
mimePart =
' <d:like>' +
' <d:prop>' +
' <d:getcontenttype/>' +
' </d:prop>' +
' <d:literal>application/%</d:literal>' +
' </d:like>' +
' <d:like>' +
' <d:prop>' +
' <d:getcontenttype/>' +
' </d:prop>' +
' <d:literal>text/%</d:literal>' +
' </d:like>' +
' <d:like>' +
' <d:prop>' +
' <d:getcontenttype/>' +
' </d:prop>' +
' <d:literal>image/%</d:literal>' +
' </d:like>' +
' <d:like>' +
' <d:prop>' +
' <d:getcontenttype/>' +
' </d:prop>' +
' <d:literal>video/%</d:literal>' +
' </d:like>' +
' <d:like>' +
' <d:prop>' +
' <d:getcontenttype/>' +
' </d:prop>' +
' <d:literal>audio/%</d:literal>' +
' </d:like>' +
' <d:like>' +
' <d:prop>' +
' <d:getcontenttype/>' +
' </d:prop>' +
' <d:literal>font/%</d:literal>' +
' </d:like>';
}
return mimePart;
}
/**
* Loads recent files and folders from WebDAV
*
*/
loadMyRecentFiles() {
this.hideAdditionalMenu();
const i18n = this._i18n;
if (typeof this.directoryPath === 'undefined' || this.directoryPath === undefined) {
this.directoryPath = '';
}
console.log('load only my 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 = false;
this.isInFilteredRecent = true;
let date = new Date();
date.setMonth(date.getMonth() - 3);
let searchDate = date.toISOString().split('.')[0] + 'Z';
if (this.webDavClient === null || this.userName === 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>' +
this.fullWebDavUrl +
'</d:href>' +
' <d:depth>infinity</d:depth>' +
' </d:scope>' +
' </d:from>' +
' <d:where> ' +
' <d:and>' +
' <d:gte>' +
' <d:prop>' +
' <d:getlastmodified/>' +
' </d:prop>' +
' <d:literal>' +
searchDate +
'</d:literal>' +
' </d:gte>' +
' <d:or>' +
this.getMimeTypes() +
' </d:or>' +
' </d:and>' +
' </d:where>' +
' <d:orderby>' +
' <d:order>' +
' <d:prop>' +
' <d:getlastmodified/>' +
' </d:prop>' +
' <d:descending/>' +
' </d:order>' +