javascript - How to upload and list directories at firefox and chrome/chromium using change and drop events -


both mozilla , webkit browsers allow directory upload. when directory or directories selected @ <input type="file"> element or dropped @ element, how list directories , files in order appear in actual directory @ both firefox , chrome/chromium, , perform tasks on files when uploaded directories have been iterated?

you can set webkitdirectory , allowdirs attributes @ <input type="file"> element; attach change, drop events <input type="file"> element; use .getfilesanddirectories() @ mozilla, .createreader(), .readentries() @ webkit, array.prototype.reduce(), promise, recursion.

note @ firefox drop event not list selection directory, file object having size 0, dropping directory @ firefox not provide representation of dropped folder, event.datatransfer.getfilesanddirectories() utilized. firefox provides 2 input elements when allowdirs attribute set; first element allows single file uploads, second element allows directory upload. chrome/chromium provide single <input type="file"> element single or multiple directories can selected, not single file.

at directories containing both files , directories, directories read first.

<!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 files or folders here!\aor click 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";        // 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 , listed without       // creating nested list @ `html` 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) {           (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"                                   + " @ drop event @ firefox, upload folders @ 'choose folder...' input");                 }               }             }           }).catch(function(err) {             alert(err)           })       }        // 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


Comments

Popular posts from this blog

What is happening when Matlab is starting a "parallel pool"? -

angular - DownloadURL return null in below code -

php - Cannot override Laravel Spark authentication with own implementation -