Comment télécharger et répertorier les répertoires chez firefox et chrome / chrome en utilisant les événements de changement et de baisse

Les navigateurs Mozilla et Webkit permettent désormais le téléchargement de répertoire. Lorsque le répertoire ou les répertoires sont sélectionnés à l'élément <input type="file"> ou déposés sur un élément, comment répertorier tous les répertoires et les fichiers dans l'ordre qu'ils apparaissent dans le répertoire réel à la fois Firefox et Chrome / Chrome, et effectuer des tâches sur Fichiers lorsque tous les répertoires téléchargés ont été itérés?

    Vous pouvez définir les webkitdirectory et allowdirs à l' allowdirs <input type="file"> ; Attache le change , drop événements à <input type="file"> element; Utilisez .getFilesAndDirectories() à mozilla, .createReader() , .readEntries() au Array.prototype.reduce() , Array.prototype.reduce() , Promise , récursion.

    La note lors de l'événement dropfox de Firefox ne répertorie pas la sélection en tant Directory , mais un objet File ayant une size 0 , ce qui permet de supprimer le répertoire à Firefox ne fournit pas de représentation du dossier abandonné, même lorsque event.dataTransfer.getFilesAndDirectories() est utilisé. Firefox fournit également deux éléments d'entrée lorsque l'attribut allowdirs est défini; Le premier élément permet les téléchargements de fichiers uniques, le second élément permet le téléchargement de répertoire. Chrome / chromium fournissent un <input type="file"> élément où seules des répertoires simples ou multiples peuvent être sélectionnés, pas un seul fichier.

    Dans les répertoires contenant des fichiers et des répertoires, les répertoires sont lus en premier.

     <!DOCTYPE html> <html> <head> <style type="text/css"> 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 or folders here!\aOr click to select files folders"; 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; } #result li span { font-weight: bold; color: navy; } </style> </head> <body> <label id="dropArea" class="area"> <input id="file" type="file" directory allowdirs webkitdirectory/> </label> <output id="result"> <ul></ul> </output> <script> 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) { var webkitResult = []; var mozResult = []; var files; console.log(event); event.stopPropagation(); event.preventDefault(); dropArea.className = "area"; // do mozilla stuff // TODO adjust, call `listDirectory()`, `listFile()` function mozReadDirectories(entries, path) { console.log("dir", entries, path); return [].reduce.call(entries, function(promise, entry) { return promise.then(function() { return Promise.resolve(entry.getFilesAndDirectories() || entry) .then(function(dir) { return dir }) }) }, Promise.resolve()) .then(function(items) { var dir = items.filter(function(folder) { return folder instanceof Directory }); var files = items.filter(function(file) { return file instanceof File }); if (files.length) { // console.log("files:", files, path); files.forEach(function(file) { console.log(file) }); mozResult = mozResult.concat.apply(mozResult, files); } if (dir.length) { // console.log(dir, dir[0] instanceof Directory); return mozReadDirectories(dir, dir[0].path || path); } else { if (!dir.length) { return Promise.resolve(mozResult).then(function(complete) { return complete }) } } }) }; function handleEntries(entry) { let file = "webkitGetAsEntry" in entry ? entry.webkitGetAsEntry() : entry return Promise.resolve(file); } function handleFile(entry) { return new Promise(function(resolve) { if (entry.isFile) { entry.file(function(file) { listFile(file, entry.fullPath).then(resolve) }) } else if (entry.isDirectory) { var reader = entry.createReader(); reader.readEntries(webkitReadDirectories.bind(null, entry, handleFile, resolve)) } else { var entries = [entry]; return entries.reduce(function(promise, file) { return promise.then(function() { return listDirectory(file) }) }, Promise.resolve()) .then(function() { return Promise.all(entries.map(function(file) { return listFile(file) })).then(resolve) }) } }) function webkitReadDirectories(entry, callback, resolve, entries) { console.log(entries); return listDirectory(entry).then(function(currentDirectory) { console.log(`iterating ${currentDirectory.name} directory`, entry); return entries.reduce(function(promise, directory) { return promise.then(function() { return callback(directory) }); }, Promise.resolve()) }).then(resolve); } } // TODO: handle mozilla directories, additional directories being selected dropped and listed without // creating nested list at `html` where different directory selected or dropped function listDirectory(entry) { console.log(entry); var path = (entry.fullPath || entry.webkitRelativePath.slice(0, entry.webkitRelativePath.lastIndexOf("/"))); var cname = path.split("/").filter(Boolean).join("-"); console.log("cname", cname) if (!document.getElementsByClassName(cname).length) { var directoryInfo = `<li><ul class=${cname}> <li> <span> Directory Name: ${entry.name}<br> Path: ${path} <hr> </span> </li></ul></li>`; var curr = document.getElementsByTagName("ul"); var _ul = curr[curr.length - 1]; var _li = _ul.querySelectorAll("li"); if (!document.querySelector("[class*=" + cname + "]")) { if (_li.length) { _li[_li.length - 1].innerHTML += `${directoryInfo}`; } else { _ul.innerHTML += `${directoryInfo}` } } else { ul.innerHTML += `${directoryInfo}` } } return Promise.resolve(entry); } // TODO: handle mozilla files function listFile(file, path) { path = path || file.webkitRelativePath || "/" + file.name; var filesInfo = `<li> Name: ${file.name}</br> Size: ${file.size} bytes</br> Type: ${file.type}</br> Modified Date: ${file.lastModifiedDate}<br> Full Path: ${path} </li>`; var currentPath = path.split("/").filter(Boolean); currentPath.pop(); var appended = false; var curr = document.getElementsByClassName(`${currentPath.join("-")}`); if (curr.length) { for (li of curr[curr.length - 1].querySelectorAll("li")) { if (li.innerHTML.indexOf(path.slice(0, path.lastIndexOf("/"))) > -1) { li.querySelector("span").insertAdjacentHTML("afterend", `${filesInfo}`); appended = true; break; } } if (!appended) { curr[curr.length - 1].innerHTML += `${filesInfo}`; } } console.log(`reading ${file.name}, size: ${file.size}, path:${path}`); webkitResult.push(file); return Promise.resolve(webkitResult) }; function processFiles(files) { Promise.all([].map.call(files, function(file, index) { return handleEntries(file, index).then(handleFile) })) .then(function() { console.log("complete", webkitResult) }) .catch(function(err) { alert(err.message); }) } if ("getFilesAndDirectories" in event.target) { return (event.type === "drop" ? event.dataTransfer : event.target).getFilesAndDirectories() .then(function(dir) { if (dir[0] instanceof Directory) { console.log(dir) return mozReadDirectories(dir, dir[0].path || path) .then(function(complete) { console.log("complete:", complete); event.target.value = null; }); } else { if (dir[0] instanceof File && dir[0].size > 0) { return Promise.resolve(dir) .then(function(complete) { console.log("complete:", complete); }) } else { if (dir[0].size == 0) { throw new Error("could not process '" + dir[0].name + "' directory" + " at drop event at firefox, upload folders at 'Choose folder...' input"); } } } }).catch(function(err) { alert(err) }) } // do webkit stuff if (event.type === "drop" && event.target.webkitdirectory) { files = event.dataTransfer.items || event.dataTransfer.files; } else if (event.type === "change") { files = event.target.files; } if (files) { processFiles(files) } } dropArea.addEventListener("dragover", dragHandler); dropArea.addEventListener("change", filesDroped); dropArea.addEventListener("drop", filesDroped); </script> </body> </html> 

    Plnkr http://plnkr.co/edit/ff5vmuuIMzSapu6MiUJ3?p=preview