From 76cd7ddda0d5fa8f49e9010c0099631b223bc41f Mon Sep 17 00:00:00 2001 From: mwiegand Date: Sat, 9 May 2026 19:11:41 +0200 Subject: [PATCH] fix(files-overlay): fall back to getAsFile when webkitGetAsEntry returns null webkitGetAsEntry() only returns an Entry for real OS-originated drag-drops; synthetic DragEvents (and some browsers without folder-drop support) get null back. Per-item fallback to getAsFile() keeps single-file drops working in those cases without sacrificing the whole-folder upload path on real OS drops. Caught while end-to-end testing on the deploy box: a programmatically- dispatched drop fired the listener and reached preventDefault(), but no upload row appeared because the file collection loop never enqueued. Co-Authored-By: Claude Opus 4.7 (1M context) --- l4d2web/static/js/files-overlay.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/l4d2web/static/js/files-overlay.js b/l4d2web/static/js/files-overlay.js index 3740f1c..d3c500a 100644 --- a/l4d2web/static/js/files-overlay.js +++ b/l4d2web/static/js/files-overlay.js @@ -890,17 +890,30 @@ return; } - // External drop — collect entries via webkitGetAsEntry if available, - // else fall back to flat dataTransfer.files. + // External drop — collect entries via webkitGetAsEntry where it + // returns an Entry (real OS drag with folder support), and fall back + // to getAsFile() for any item whose entry is null (synthetic events, + // browsers without the API, or items that have no folder structure). const items = event.dataTransfer.items; const files = []; const tasks = []; - if (items && items[0] && typeof items[0].webkitGetAsEntry === "function") { + if (items && items.length) { for (let i = 0; i < items.length; i++) { - const entry = items[i].webkitGetAsEntry(); - if (entry) tasks.push(walkEntry(entry, "", files)); + const item = items[i]; + if (typeof item.webkitGetAsEntry === "function") { + const entry = item.webkitGetAsEntry(); + if (entry) { + tasks.push(walkEntry(entry, "", files)); + continue; + } + } + // Fallback: treat as a flat file. + if (typeof item.getAsFile === "function") { + const f = item.getAsFile(); + if (f) files.push({ file: f, rel: f.name }); + } } - } else { + } else if (event.dataTransfer.files) { for (let i = 0; i < event.dataTransfer.files.length; i++) { files.push({ file: event.dataTransfer.files[i], rel: event.dataTransfer.files[i].name }); }