Fix dropped folder uploads

This commit is contained in:
Mikei386
2026-06-23 21:37:36 +02:00
parent 07bcf157e0
commit dfd6bfec57
6 changed files with 100 additions and 13 deletions
+78 -6
View File
@@ -879,19 +879,19 @@ async function loadExplorer(win, targetPath) {
}
async function handleDrop(event, win, targetPath) {
const uploadItems = await getDroppedUploadItems(event);
recordDebug('html.drop', {
targetPath,
types: dataTransferTypes(event),
files: getDroppedFiles(event).map((file) => ({ name: file.name, size: file.size }))
files: uploadItems.map((item) => ({ name: item.path, size: item.file.size }))
});
if (state.config.readOnly) {
showError(new Error('Read-only mode ist aktiv.'));
return;
}
const files = getDroppedFiles(event);
if (files.length) {
await uploadFileList(win, files, targetPath);
if (uploadItems.length) {
await uploadFileList(win, uploadItems, targetPath);
}
}
@@ -902,8 +902,10 @@ async function uploadFileList(win, files, targetPath) {
}
if (!files.length) return;
const form = new FormData();
for (const file of files) {
form.append('files', file, file.webkitRelativePath || file.name);
const uploadItems = normalizeUploadItems(files);
for (const item of uploadItems) {
form.append('files[]', item.file, item.file.name);
form.append('paths[]', item.path);
}
appendCsrf(form);
await fetchChecked(apiUrl(`upload.php?path=${encodeURIComponent(targetPath)}`), {
@@ -913,6 +915,19 @@ async function uploadFileList(win, files, targetPath) {
await loadExplorer(win, targetPath);
}
function normalizeUploadItems(files) {
return files.map((item) => {
if (item?.file && item?.path) {
return item;
}
const file = item;
return {
file,
path: file.webkitRelativePath || file.name
};
}).filter((item) => item.file && item.path);
}
async function createJob(type, source, destination = null, refreshWindowIds = [], extra = {}) {
if (['move', 'copy', 'permissions'].includes(type) && isReadOnly()) {
showError(new Error('Read-only mode ist aktiv.'));
@@ -976,6 +991,63 @@ function hasDropPayload(event) {
return types.includes('Files') || getDroppedFiles(event).length > 0;
}
async function getDroppedUploadItems(event) {
const entries = getDroppedEntries(event);
if (entries.length) {
const items = [];
for (const entry of entries) {
items.push(...await readDroppedEntry(entry, ''));
}
if (items.length) {
return items;
}
}
return getDroppedFiles(event).filter((file) => file.size > 0 || file.type || file.name.includes('.')).map((file) => ({
file,
path: file.webkitRelativePath || file.name
}));
}
function getDroppedEntries(event) {
try {
return [...(event.dataTransfer?.items || [])]
.map((item) => item.webkitGetAsEntry?.())
.filter(Boolean);
} catch (error) {
recordDebug('dataTransfer.entries.error', serializeError(error));
return [];
}
}
async function readDroppedEntry(entry, parentPath) {
const path = parentPath ? `${parentPath}/${entry.name}` : entry.name;
if (entry.isFile) {
const file = await new Promise((resolve, reject) => entry.file(resolve, reject));
return [{ file, path }];
}
if (!entry.isDirectory) {
return [];
}
const reader = entry.createReader();
const children = await readAllDirectoryEntries(reader);
const results = [];
for (const child of children) {
results.push(...await readDroppedEntry(child, path));
}
return results;
}
async function readAllDirectoryEntries(reader) {
const entries = [];
while (true) {
const batch = await new Promise((resolve, reject) => reader.readEntries(resolve, reject));
if (!batch.length) {
return entries;
}
entries.push(...batch);
}
}
function showError(error) {
const debug = recordDebug('error.shown', serializeError(error));
const message = error?.message || String(error);