Problem
I have following code snippet that is used to get file information during file drag and drop upload:
var files = event.dataT
You can read a little about this in here (including Firefix). Here is a function (not made by me but I edited maybe a half of it) that detects whether drop is file or folder and shows its name, size and what type (tested in FireFox):
function handleDrop(e)
{
e.stopPropagation();
e.preventDefault();
var filesInfo = "";
var files = e.dataTransfer.files,
folder;
for (var i = 0, f; f = files[i]; i++)
{
if (!f.type && f.size % 4096 == 0)
folder = true;
else
folder = false;
filesInfo += 'Name: ' + f.name;
filesInfo += '<br>Size: ' + f.size + ' bytes';
filesInfo += '<br>Type: ' + (folder ? 'folder ' : 'file');
output.innerHTML = filesInfo;
}
}
I hope that's what you were looking for. Good luck!
Solution
I came up with following dirty workaround that works on Firefox version - 46.0.1
It uses FileReader API to check if uploaded file is directory or not.
Code
<div id="dropArea" style="border: 1px solid; padding: 50px; text-align: center;">
Drop your files here!
</div>
<script>
// Get target elements.
var dropArea = document.getElementById("dropArea");
// To be defined.
function notDirectory(file) {
return new Promise(function(resolve, reject) {
var reader = new FileReader();
// Can read files, but not directories.
reader.onprogress = function(event) {
if ('progress' === event.type) {
resolve(file);
reader.abort();
}
};
// Wait for result.
reader.readAsDataURL(file);
});
}
// Attach drop listener.
dropArea.addEventListener("drop", function (event) {
// Stop propagation.
event.stopPropagation();
event.preventDefault();
// Loop files to filter out directories and print files.
var files = event.dataTransfer.files;
for (var i = 0; i < files.length; i++) {
var file = files[i];
// I need notDirectory(file) function.
notDirectory(file).then(function(file) {
// Print info.
console.log({
name: file.name,
size: file.size,
type: file.type
});
});
}
});
// Attach drag move listener.
dropArea.addEventListener("dragover", function (event) {
// Stop propagation.
event.stopPropagation();
event.preventDefault();
});
</script>
Related Links
My question would be is there any workaround for latest stable Firefox version to detect directories? Because on stable version that feature is disabled by default or do I miss something?
Directory upload was not enabled by default at firefox 47, where tried html
, javascript
at stacksnippets, jsfiddle.
See Firefox 42 for developers Interfaces/APIs/DOM
The
Directory
interface has been experimentally extended (bug 1177688). The two membersDirectory.path
andDirectory.getContents
can be exposed by setting thedom.input.dirpicker
preference totrue
.
A workaround to detect folder upload could include
<input type="file">
with directory
and allowdirs
attributes set, possibly including multiple
attribute, see Note, for drag and drop or user selection on click of container;prefs.js
or about:config
and set dom.input.dirpicker
preference to Boolean
true
;File
object, use if
with condition (filesAndDirs[0] && filesAndDirs[0].constructor.name === "Directory")
or (filesAndDirs[0] instanceof Directory)
inside of .then(function(filesAndDirectories){})
at chained to .getFilesAndDirectories();<label>
element for <div>
element as parent of <input type="file">
. Adjust css
of input type="file"
to fill parent droppable container and set opacity
to 0
; adjust css
at parent element of input type="file"
to display text at :before
pseudo-element, over input type="file"
child element.See also New API for directory picking and drag-and-drop.
Note, approach was tried at firefox 47, where both directories and individual files were successfully uploaded.
var dropArea = document.getElementById("dropArea");
var output = document.getElementById("result");
var ul = output.querySelector("ul");
function dragHandler(event) {
event.stopPropagation();
event.preventDefault();
dropArea.className = "area drag";
}
function filesDroped(event) {
event.stopPropagation();
event.preventDefault();
dropArea.className = "area";
var uploadFile = function(file, path) {
// handle file uploading
console.log(file, path);
var filesInfo = `<li>
Name: ${file.name}</br>
Size: ${file.size} bytes</br>
Type: ${file.type}</br>
Modified Date: ${file.lastModifiedDate}
</li>`;
ul.innerHTML += `${filesInfo}`;
};
var iterateFilesAndDirs = function(filesAndDirs, path) {
for (var i = 0; i < filesAndDirs.length; i++) {
if (typeof filesAndDirs[i].getFilesAndDirectories === 'function') {
var path = filesAndDirs[i].path;
// this recursion enables deep traversal of directories
filesAndDirs[i].getFilesAndDirectories()
.then(function(subFilesAndDirs) {
// iterate through files and directories in sub-directory
iterateFilesAndDirs(subFilesAndDirs, path);
});
} else {
uploadFile(filesAndDirs[i], path);
}
}
};
if ("getFilesAndDirectories" in event.target) {
event.target.getFilesAndDirectories()
.then(function(filesAndDirs) {
// if directory
var dir = filesAndDirs;
if (dir[0] && dir[0].constructor.name === "Directory") {
console.log(dir);
var directoryInfo = `<li>
Directory Name: ${dir[0].name}</br>
Path: ${dir[0].path}
</li>`;
ul.innerHTML += `${directoryInfo}`;
alert("isDirectory:true");
}
iterateFilesAndDirs(dir, "/");
})
} else {
// do webkit stuff
}
}
dropArea.addEventListener("dragover", dragHandler);
dropArea.addEventListener("change", filesDroped);
input[type="file"] {
width: 98%;
height: 180px;
}
label[for="file"] {
width: 98%;
height: 180px;
}
.area {
display:block;
border: 5px dotted #ccc;
text-align: center;
}
.area:after {
display: block;
border:none;
white-space: pre;
/*content: "Drop your files here!\aOr click to select files";*/
position: relative;
left: 0%;
top: -75px;
text-align:center;
}
.drag {
border: 5px dotted green;
background-color: yellow;
}
#result ul {
list-style: none;
margin-top: 20px;
}
#result ul li {
border-bottom: 1px solid #ccc;
margin-bottom: 10px;
}
<label id="dropArea" class="area">
<input id="file" type="file" allowdirs directory webkitdirectory/>
</label>
<output id="result">
<ul></ul>
</output>
jsfiddle https://jsfiddle.net/exs3ta25/31/