Reputation: 6613
I have an element that allows for dropping things on it like so
var div = document.createElement("div");
div.addEventListener("drop", (e)=>{
e.preventDefault();
if (!(("dataTransfer" in e) && ("files" in e.dataTransfer))) return;
for (var i = 0; i < e.dataTransfer.files.length; i++) {
var file = e.dataTransfer.files[i];
// magical check whether the file is a folder?
upload_file(file);
}
});
Problem is, folders show up in the FileList object just the same and they seem to be indisginguishable from files up until the point where you try to read them using FileReader.
They have a size which seems to be exactly the cluster size of whatever drive the file is from, they have no type but same is true for any uncommon file extension. When you try to read them with FileReader, the onload even is simply never raised.
I could try and do a test read with some kind of timeout mechanism in place to detect that its not a file but this seems like a dirty method bound to result in errors in any future browser update.
Is there any other way to figure out that the file provided is not in fact a file?
Upvotes: 3
Views: 995
Reputation: 1410
I stumbled upon an answer in another StackOverflow discussion that might be useful in relation to this.
Detecting folders/directories in javascript FileList objects
Basically you can detect if it's a file or a directory "indirectly" by seeing if reading it throws an exception. A snippet follows:
<html>
<head>
<title></title>
</head>
<body>
<div dropzone="copy" id="dropTarget" ondrop="handleDrop(event);" ondragover="event.preventDefault();" style="border: 1px solid gray; width: 300px; height: 50px;">
Drop your folder here
</div>
<script type="text/javascript">
var item = null;
var handle = null;
var file = null;
function handleDrop(e) {
e.preventDefault();
item = e.dataTransfer.items[0];
file = item.getAsFile();
file.slice(0,1).arrayBuffer().then(buf => console.log("file"), err => console.log("dir"));
item.getAsFileSystemHandle().then(h => { handle = h; console.log("done"); });
};
</script>
</body>
Upvotes: 1
Reputation: 6613
Searching far and wide, the only real option I found was using an experimental feature supported by edge, chrome and ff
For my implementation, before rendering the page, I do this test to check whether or not to allow for drops at all:
browser_support_drop() {
if (typeof DragEvent !== "function") return false;
if (!("dataTransfer" in DragEvent.prototype)) return false;
if (typeof DataTransferItem !== "function") return false;
if (!("webkitGetAsEntry" in DataTransferItem.prototype) && !("getAsEntry" in DataTransferItem.prototype)) return false;
return true;
}
and then in the drop handler (if applicable)
handle_drop(e) {
var items = [];
for (var i = 0; i < e.dataTransfer.items.length; i++) {
var item = e.dataTransfer.items[i];
if (item.kind !== "file") continue;
var entry = "getAsEntry" in DataTransferItem.prototype ? item.getAsEntry() : item.webkitGetAsEntry();
if (entry.isDirectory) continue;
items.push(item.getAsFile());
}
this.handle_files_added(items);
}
Upvotes: 1