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
Directoryinterface has been experimentally extended (bug 1177688). The two membersDirectory.pathandDirectory.getContentscan be exposed by setting thedom.input.dirpickerpreference 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