Does HTML5 support drag and drop folder loading or folder tree?

I have not seen examples that do this. Is this allowed in the api specification?

I am looking for an easy drag and drop solution to load an entire tree of photo folders.

+68
html5 file-upload drag-and-drop
Aug 28 '10 at 8:33
source share
9 answers

Now it's possible thanks to Chrome> = 21.

function traverseFileTree(item, path) { path = path || ""; if (item.isFile) { // Get file item.file(function(file) { console.log("File:", path + file.name); }); } else if (item.isDirectory) { // Get folder contents var dirReader = item.createReader(); dirReader.readEntries(function(entries) { for (var i=0; i<entries.length; i++) { traverseFileTree(entries[i], path + item.name + "/"); } }); } } dropArea.addEventListener("drop", function(event) { event.preventDefault(); var items = event.dataTransfer.items; for (var i=0; i<items.length; i++) { // webkitGetAsEntry is where the magic happens var item = items[i].webkitGetAsEntry(); if (item) { traverseFileTree(item); } } }, false); 

Additional information: https://protonet.info/blog/html5-experiment-drag-drop-of-folders/

+67
Jul 10 2018-12-12T00:
source share
β€” -

Unfortunately, none of the existing answers is completely correct, because readEntries will not necessarily return ALL records (file or directory) for this directory.

As noted in a johnozbay comment , in Chrome, readEntries will return no more than 100 entries for a directory. Thus, in order to actually get all the files, we need readEntries to call readEntries (for the current directory) until it returns an empty array.

Xan also explains this pretty well in this answer (albeit without code).

readEntries is asynchronous, so use await and async to make things clearer:

 // Drop handler function async function getAllEntries(dataTransferItemList) { let entries = []; // Use BFS to traverse/get all entries let queue = []; // Unfortunately dataTransferItemList is not iterable ie no forEach for (let i = 0; i < dataTransferItemList.length; i++) { queue.push(dataTransferItemList[i].webkitGetAsEntry()); } // BFS traversal while (queue.length > 0) { let entry = queue.shift(); if (entry.isFile) { entries.push(entry); } else if (entry.isDirectory) { let reader = entry.createReader(); queue.push(...await readAll(reader)); } } return entries; } // Get all the entries in a directory async function readAll(directoryReader) { let entries = []; await new Promise((resolve, reject) => { directoryReader.readEntries(resolve, reject); }).then(async es => { if (es.length > 0) { entries.push(...es); // Recursively call to add all the entries from the given directory entries.push(...await readAll(directoryReader)); } // No more entries in directory/nothing to do }).catch(err => { // Extremely long file paths can cause errors console.log(err); }) return entries; } 

Full working example on Codepen: https://codepen.io/anon/pen/gBJrOP

See also the answer of Pablo BarrΓ­a Urenda, which does this asynchronously without BFS.

Documentation:

This behavior is described in FileSystemDirectoryReader (highlighted by me):

readEntries ()
Returns an array containing a number of entries in the directory . Each element of the array is an object based on FileSystemEntry β€” usually either FileSystemFileEntry or FileSystemDirectoryEntry.

But, in fairness, the MDN documentation can make this clearer in other sections. The readEntries () documentation just notes:

The readEntries () method retrieves the directory entries in the directory being read and delivers them to the array to the provided callback function

And the only mention / hint that several calls are required is the description of the successCallback parameter:

If there are no files, or you have already called readEntries () on this FileSystemDirectoryReader, the array is empty.

The API may be more intuitive, but as noted in the documentation, this is a non-standard function, not a standard track.

+21
Oct 30 '18 at 6:31
source share

In this post to the HTML 5 mailing list, Ian Hickson says:

HTML5 now uploads many files at once. Browsers can select several files at once, including through several directories; which is a bit out of specification.

(Also see the original sentence .)) Therefore, we can safely assume that he believes that loading folders using drag and drop is also beyond the scope. Apparently, it is up to the browser to serve individual files.

Downloading folders will also have some other difficulties, as described by Lars Gunther :

In this [...] sentence there should be two checks (if at all possible):

  • The maximum size so that someone cannot load the full catalog of several hundred uncompressed source images ...

  • Filtering even if the accept attribute is omitted. Metadata for Mac OS and Windows thumbnails, etc. must be omitted. All hidden files and directories should be excluded by default.

+13
Aug 28 2018-10-10T00:
source share

Now you can load directories with drag and drop.

 <input type='file' webkitdirectory > 

and for drag and drop (for web browsers).

Handling dragged folders.

 <div id="dropzone"></div> <script> var dropzone = document.getElementById('dropzone'); dropzone.ondrop = function(e) { var length = e.dataTransfer.items.length; for (var i = 0; i < length; i++) { var entry = e.dataTransfer.items[i].webkitGetAsEntry(); if (entry.isFile) { ... // do whatever you want } else if (entry.isDirectory) { ... // do whatever you want } } }; </script> 

Resources

http://updates.html5rocks.com/2012/07/Drag-and-drop-a-folder-onto-Chrome-now-available

+9
Jul 24 2018-12-12T00:
source share

Firefox now supports downloading folders as of November 15, 2016 in version 50.0: https://developer.mozilla.org/en-US/Firefox/Releases/50#Files_and_directories

You can drag and drop folders in Firefox or browse and select the local folder to download. It also supports folders subfolders.

This means that now you can use Chrome, Firefox, Edge or Opera to download folders. You cannot use Safari or Internet Explorer at this time.

+8
Nov 19 '16 at 16:47
source share

This function will give you a promise for an array of all discarded files, such as <input type="file"/>.files :

 function getFilesWebkitDataTransferItems(dataTransferItems) { function traverseFileTreePromise(item, path='') { return new Promise( resolve => { if (item.isFile) { item.file(file => { file.filepath = path + file.name //save full path files.push(file) resolve(file) }) } else if (item.isDirectory) { let dirReader = item.createReader() dirReader.readEntries(entries => { let entriesPromises = [] for (let entr of entries) entriesPromises.push(traverseFileTreePromise(entr, path + item.name + "/")) resolve(Promise.all(entriesPromises)) }) } }) } let files = [] return new Promise((resolve, reject) => { let entriesPromises = [] for (let it of dataTransferItems) entriesPromises.push(traverseFileTreePromise(it.webkitGetAsEntry())) Promise.all(entriesPromises) .then(entries => { //console.log(entries) resolve(files) }) }) } 

Using:

 dropArea.addEventListener("drop", function(event) { event.preventDefault(); var items = event.dataTransfer.items; getFilesFromWebkitDataTransferItems(items) .then(files => { ... }) }, false); 

npm package

https://www.npmjs.com/package/datatransfer-files-promise Not tested, create a problem if it does not work;)

+8
Jul 05 '17 at 6:45
source share

The HTML5 specification does NOT say that when you select a folder to download, the browser should recursively download all the contained files.

In fact, in Chrome / Chromium you can download a folder, but when you do this, it just downloads a meaningless 4 KB file that represents the directory. Some server applications, such as Alfresco , may detect this and warn the user that folders cannot be downloaded:

The following cannot be uploaded because they are either folders or are zero bytes in size: undefined

+2
Jun 12 2018-12-12T00:
source share

Here is a complete example of using the file and directory APIs :

 var dropzone = document.getElementById("dropzone"); var listing = document.getElementById("listing"); function scanAndLogFiles(item, container) { var elem = document.createElement("li"); elem.innerHTML = item.name; container.appendChild(elem); if (item.isDirectory) { var directoryReader = item.createReader(); var directoryContainer = document.createElement("ul"); container.appendChild(directoryContainer); directoryReader.readEntries(function(entries) { entries.forEach(function(entry) { scanAndLogFiles(entry, directoryContainer); }); }); } } dropzone.addEventListener( "dragover", function(event) { event.preventDefault(); }, false ); dropzone.addEventListener( "drop", function(event) { var items = event.dataTransfer.items; event.preventDefault(); listing.innerHTML = ""; for (var i = 0; i < items.length; i++) { var item = items[i].webkitGetAsEntry(); if (item) { scanAndLogFiles(item, listing); } } }, false ); 
 body { font: 14px "Arial", sans-serif; } #dropzone { text-align: center; width: 300px; height: 100px; margin: 10px; padding: 10px; border: 4px dashed red; border-radius: 10px; } #boxtitle { display: table-cell; vertical-align: middle; text-align: center; color: black; font: bold 2em "Arial", sans-serif; width: 300px; height: 100px; } 
 <p>Drag files and/or directories to the box below!</p> <div id="dropzone"> <div id="boxtitle"> Drop Files Here </div> </div> <h2>Directory tree:</h2> <ul id="listing"></ul> 

webkitGetAsEntry supported by Chrome 13+, Firefox 50+, and Edge.

Source: https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/webkitGetAsEntry

+2
Sep 14 '18 at 13:23
source share

Does HTML5 support drag and drop folder loading or folder tree?

Only Chrome supports this feature. It has no grip and is likely to be removed.

Link: https://developer.mozilla.org/en/docs/Web/API/DirectoryReader#readEntries

+1
03 Feb '16 at 13:25
source share



All Articles