Add upload buttons and ZIP downloads
This commit is contained in:
+62
-10
@@ -270,6 +270,10 @@ function renderExplorer(body, win) {
|
||||
<input value="${escapeAttr(data.path || '')}" aria-label="Pfad">
|
||||
<button class="icon" data-action="go" title="Öffnen" aria-label="Öffnen">↵</button>
|
||||
<button class="icon" data-action="refresh" title="Neu laden" aria-label="Neu laden">↻</button>
|
||||
<button class="icon" data-action="upload-files" title="Dateien hochladen" aria-label="Dateien hochladen" ${isReadOnly() ? 'disabled' : ''}>⤴</button>
|
||||
<button class="icon" data-action="upload-folder" title="Ordner hochladen" aria-label="Ordner hochladen" ${isReadOnly() ? 'disabled' : ''}>⇪</button>
|
||||
<input class="upload-input" data-upload="files" type="file" multiple>
|
||||
<input class="upload-input" data-upload="folder" type="file" multiple webkitdirectory directory>
|
||||
<div class="view-toggle" aria-label="Ansicht">
|
||||
<button class="icon ${data.view !== 'icons' ? 'active' : ''}" data-action="view-list" title="Listenansicht" aria-label="Listenansicht">☰</button>
|
||||
<button class="icon ${data.view === 'icons' ? 'active' : ''}" data-action="view-icons" title="Symbolansicht" aria-label="Symbolansicht">▦</button>
|
||||
@@ -287,6 +291,19 @@ function renderExplorer(body, win) {
|
||||
body.querySelector('[data-action="up"]').addEventListener('click', () => loadExplorer(win, parentPath(data.path)));
|
||||
body.querySelector('[data-action="view-list"]').addEventListener('click', () => setExplorerView(win, 'list'));
|
||||
body.querySelector('[data-action="view-icons"]').addEventListener('click', () => setExplorerView(win, 'icons'));
|
||||
body.querySelector('[data-action="upload-files"]').addEventListener('click', () => body.querySelector('[data-upload="files"]').click());
|
||||
body.querySelector('[data-action="upload-folder"]').addEventListener('click', () => body.querySelector('[data-upload="folder"]').click());
|
||||
for (const inputEl of body.querySelectorAll('.upload-input')) {
|
||||
inputEl.addEventListener('change', async () => {
|
||||
try {
|
||||
await uploadFileList(win, [...inputEl.files], data.path);
|
||||
} catch (error) {
|
||||
showError(error);
|
||||
} finally {
|
||||
inputEl.value = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const dropZone = body.querySelector('.drop-zone');
|
||||
dropZone.addEventListener('dragenter', (event) => {
|
||||
@@ -872,19 +889,28 @@ async function handleDrop(event, win, targetPath) {
|
||||
|
||||
const files = getDroppedFiles(event);
|
||||
if (files.length) {
|
||||
const form = new FormData();
|
||||
for (const file of files) {
|
||||
form.append('files', file, file.name);
|
||||
}
|
||||
appendCsrf(form);
|
||||
await fetchChecked(apiUrl(`upload.php?path=${encodeURIComponent(targetPath)}`), {
|
||||
method: 'POST',
|
||||
body: form
|
||||
});
|
||||
await loadExplorer(win, targetPath);
|
||||
await uploadFileList(win, files, targetPath);
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadFileList(win, files, targetPath) {
|
||||
if (isReadOnly()) {
|
||||
showError(new Error('Read-only mode ist aktiv.'));
|
||||
return;
|
||||
}
|
||||
if (!files.length) return;
|
||||
const form = new FormData();
|
||||
for (const file of files) {
|
||||
form.append('files', file, file.webkitRelativePath || file.name);
|
||||
}
|
||||
appendCsrf(form);
|
||||
await fetchChecked(apiUrl(`upload.php?path=${encodeURIComponent(targetPath)}`), {
|
||||
method: 'POST',
|
||||
body: form
|
||||
});
|
||||
await loadExplorer(win, targetPath);
|
||||
}
|
||||
|
||||
async function createJob(type, source, destination = null, refreshWindowIds = [], extra = {}) {
|
||||
if (['move', 'copy', 'permissions'].includes(type) && isReadOnly()) {
|
||||
showError(new Error('Read-only mode ist aktiv.'));
|
||||
@@ -1034,6 +1060,25 @@ function openPermissionsDialog(win, entry) {
|
||||
render();
|
||||
}
|
||||
|
||||
function downloadEntries(win, entry = null) {
|
||||
const entries = entry && selectedPathSet(win).has(entry.path) ? selectedEntries(win) : (entry ? [entry] : [{
|
||||
path: win.data.path,
|
||||
name: basename(win.data.path),
|
||||
type: 'directory'
|
||||
}]);
|
||||
const paths = entries.map((item) => item.path);
|
||||
const query = paths.length === 1
|
||||
? `path=${encodeURIComponent(paths[0])}`
|
||||
: `paths=${encodeURIComponent(JSON.stringify(paths))}`;
|
||||
recordDebug('download.start', { paths });
|
||||
const link = document.createElement('a');
|
||||
link.href = apiUrl(`download.php?${query}`);
|
||||
link.download = '';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
}
|
||||
|
||||
function renderPermissionsDialog() {
|
||||
const dialog = state.permissionsDialog;
|
||||
const overlay = document.createElement('div');
|
||||
@@ -1250,6 +1295,7 @@ function renderContextMenu() {
|
||||
actions.push(['Vorschau', () => openPreview(entry, win.id)]);
|
||||
}
|
||||
actions.push(['Eigenschaften', () => showPropertiesForEntry(win, entry)]);
|
||||
actions.push(['Herunterladen', () => downloadEntries(win, entry)]);
|
||||
if (!isReadOnly()) {
|
||||
actions.push(['Umbenennen', () => renameEntry(win, entry)]);
|
||||
actions.push(['Berechtigungen...', () => openPermissionsDialog(win, entry)]);
|
||||
@@ -1257,6 +1303,7 @@ function renderContextMenu() {
|
||||
actions.push(['Verschieben nach...', () => promptTransfer(win, entry, 'move')]);
|
||||
}
|
||||
} else {
|
||||
actions.push(['Aktuellen Ordner herunterladen', () => downloadEntries(win, null)]);
|
||||
actions.push(['Neu laden', () => loadExplorer(win, win.data.path)]);
|
||||
}
|
||||
|
||||
@@ -1886,6 +1933,11 @@ function dirname(value) {
|
||||
return `/${parts.slice(0, -1).join('/')}`;
|
||||
}
|
||||
|
||||
function basename(value) {
|
||||
const parts = String(value || '').split('/').filter(Boolean);
|
||||
return parts[parts.length - 1] || '';
|
||||
}
|
||||
|
||||
function extensionOf(name) {
|
||||
const value = String(name || '');
|
||||
const index = value.lastIndexOf('.');
|
||||
|
||||
Reference in New Issue
Block a user