2

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?

user81993
  • 6,167
  • 6
  • 32
  • 64
  • Why the check? you want to only allow files to be uploaded or just do a different thing if its folder? – Art3mix Jan 17 '19 at 10:06
  • Well mostly because you cant actually upload a folder if you cant read it, it just clogs up the system without any errors or warnings. – user81993 Jan 17 '19 at 10:09
  • Note that there should be an error fired on your FileReader when you try to read this folder. – Kaiido Jan 17 '19 at 11:56

2 Answers2

1

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);
}
user81993
  • 6,167
  • 6
  • 32
  • 64
0

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>
Filippo Possenti
  • 1,300
  • 8
  • 18