2016-09-23 9 views
17

दोनों मोज़िला और वेबकिट ब्राउज़र अब निर्देशिका अपलोड करने की अनुमति देते हैं। जब निर्देशिका या निर्देशिका <input type="file"> तत्व पर चुनी जाती है या किसी तत्व पर गिरा दी जाती है, तो सभी निर्देशिकाओं और फ़ाइलों को क्रमशः फ़ायरफ़ॉक्स और क्रोम/क्रोमियम दोनों में वास्तविक निर्देशिका में दिखाई देने के लिए कैसे सूचीबद्ध करें, और सभी अपलोड निर्देशिकाओं पर फ़ाइलों पर कार्य निष्पादित करें दोहराया?परिवर्तन और ड्रॉप ईवेंट का उपयोग करके फ़ायरफ़ॉक्स और क्रोम/क्रोमियम पर निर्देशिका अपलोड और सूची कैसे करें

+0

जानकारी किस टुकड़ा आप अभी भी याद कर रहे हैं? –

+0

@KScandrett फ़ायरफ़ॉक्स या क्रोमियम पर निर्देशिकाओं से फ़ाइलों की एक सरणी बनाने के लिए कोई नहीं, जो मुझे पता है। उत्तर में 'listDirectory()' और 'listFile()' फ़ंक्शंस शायद प्रत्येक ब्राउज़र पर सटीक परिणाम प्राप्त करने और सूचीबद्ध करने के लिए अभी भी बेहतर हो सकते हैं। आखिरी बार उन कार्यों पर काम करते समय, अगर सही ढंग से याद किया जाता है, तो फ़ाइल ऑब्जेक्ट की सही मूल निर्देशिका प्राप्त करना चुनौतीपूर्ण था, जहां फ़ाइल वाली निर्देशिका में निर्देशिका भी शामिल थी। उत्तर में 'TODO' है, मुख्य रूप से क्रोमियम – guest271314

+0

@KScandrett पर 'listDirectories()' और' listFiles() 'की कोशिश की गई है यदि आपने आवश्यकता को पूरा करने के लिए वर्तमान उत्तर में मिलने से अलग दृष्टिकोण विकसित किया है, तो अपना उत्तर – guest271314

उत्तर

8

आप webkitdirectory और allowdirs<input type="file"> तत्व पर विशेषताएँ सेट कर सकते हैं; change, drop घटनाओं को <input type="file"> तत्व संलग्न करें; .getFilesAndDirectories() का उपयोग मोज़िला, .createReader(), .readEntries()webkit, Array.prototype.reduce(), Promise, रिकर्सन पर करें। फ़ायरफ़ॉक्स drop घटना में

नोट एक Directory के रूप में चयन की सूची नहीं है, लेकिन एक File वस्तु size0 होने, इस प्रकार फ़ायरफ़ॉक्स में निर्देशिका छोड़ने गिरा फ़ोल्डर के प्रतिनिधित्व प्रदान नहीं करता है, यहां तक ​​कि जहां event.dataTransfer.getFilesAndDirectories() उपयोग किया जाता है। allowdirs विशेषता सेट होने पर फ़ायरफ़ॉक्स भी दो इनपुट तत्व प्रदान करता है; पहला तत्व एकल फ़ाइल अपलोड की अनुमति देता है, दूसरा तत्व निर्देशिका अपलोड करने की अनुमति देता है। क्रोम/क्रोमियम एकल <input type="file"> तत्व प्रदान करता है जहां केवल एकल या एकाधिक निर्देशिकाएं चुनी जा सकती हैं, एकल फ़ाइल नहीं।

दोनों फाइलों और निर्देशिकाओं वाली निर्देशिकाओं में, निर्देशिकाओं को पहले पढ़ा जाता है।

<!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

+0

देखें [फ़ाइल और निर्देशिका प्रविष्टि एपीआई] (https://wicg.github.io/entries-api/) – guest271314

संबंधित मुद्दे