From 8370d9f06066dd808214b838551a29d24731bbd6 Mon Sep 17 00:00:00 2001 From: Johannes Zellner Date: Fri, 18 May 2018 22:29:34 +0200 Subject: [PATCH] Support dropping a folder for upload --- frontend/index.html | 5 ++++- frontend/js/app.js | 52 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index d2b526d..bb53ca4 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -101,7 +101,10 @@ - + +
Fetching file information for upload
+
+ Uploading files ({{ uploadStatus.done }} / {{ uploadStatus.count }}) diff --git a/frontend/js/app.js b/frontend/js/app.js index 9d7baca..df5043a 100644 --- a/frontend/js/app.js +++ b/frontend/js/app.js @@ -136,9 +136,6 @@ function uploadFiles(files) { app.uploadStatus.percentDone = 0; asyncForEach(files, function (file, callback) { - // do not handle directories (file.type is empty in such a case) - if (file.type === '') return callback(); - var path = encode(sanitize(app.path + '/' + (file.webkitRelativePath || file.name))); var formData = new FormData(); @@ -175,7 +172,51 @@ function dragOver(event) { function drop(event) { event.stopPropagation(); event.preventDefault(); - uploadFiles(event.dataTransfer.files || []); + + if (!event.dataTransfer.items[0]) return; + + // figure if a folder was dropped on a modern browser, in this case the first would have to be a directory + var folderItem; + try { + folderItem = event.dataTransfer.items[0].webkitGetAsEntry(); + if (folderItem.isFile) return uploadFiles(event.dataTransfer.files); + } catch (e) { + return uploadFiles(event.dataTransfer.files); + } + + // if we got here we have a folder drop and a modern browser + // now traverse the folder tree and create a file list + app.uploadStatus.busy = true; + app.uploadStatus.uploadListCount = 0; + + var fileList = []; + function traverseFileTree(item, path, callback) { + if (item.isFile) { + // Get file + item.file(function (file) { + fileList.push(file); + ++app.uploadStatus.uploadListCount; + callback(); + }); + } else if (item.isDirectory) { + // Get folder contents + var dirReader = item.createReader(); + dirReader.readEntries(function (entries) { + asyncForEach(entries, function (entry, callback) { + traverseFileTree(entry, path + item.name + '/', callback); + }, callback); + }); + } + } + + traverseFileTree(folderItem, '', function (error) { + app.uploadStatus.busy = false; + app.uploadStatus.uploadListCount = 0; + + if (error) return console.error(error); + + uploadFiles(fileList); + }); } var app = new Vue({ @@ -187,7 +228,8 @@ var app = new Vue({ busy: false, count: 0, done: 0, - percentDone: 50 + percentDone: 50, + uploadListCount: 0 }, path: '/', pathParts: [], -- 2.41.0