Problem
I have following code snippet that is used to get file information during file drag and drop upload:
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) {
output.innerHTML +=
`<p>
Name: ${file.name}</br>
Size: ${file.size} bytes</br>
Type: ${file.type}</br>
Modified Date: ${file.lastModifiedDate}
</p>`;
});
}
I did research and found that Firefox does not support directory uploads, but allows client to drag and drop them to drop area.
Question
How can I filter out directories from upload handler in Firefox?
Update
You can find working sample here: https://jsfiddle.net/gevorgha/exs3ta25/
Please consider that I need it to work on the latest stable Firefox version - 46.0.1 without enabling extra preferences from browser, because I don't want to ask users to enable preference to make upload work properly.
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
;Directory
and not a single 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/
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With