Mozilla

HTML5 adoption stories: box.net and html5 drag and drop

This is a guest post from Tomas Barreto, a developer who works at box.net. They recently adopted HTML5 drag and drop as a way to share files with other people using new features in Firefox. The included video is a pitch for the feature and service, but shows how easy it is to do simple HTML5-based upload progress even with multiple files. Tomas gives an overview of the relatively simple JavaScript required to do this, and how improvements in Firefox 4 will make things even easier. Also have a quick look at the bottom of the post for links to additional docs and resources.

At Box.net, we’re always exploring new ways to help users get content quickly and securely onto our cloud content management platform. So when asked, “What feature would make you use Box more?” during the Box Hack Olympics in April, my colleague CJ and I decided to tackle the most intuitive way to upload files: simply dragging them from the desktop into Box.

We considered technologies ranging from Gears to Firefox plugins, but only HTML5 had sufficient adoption. By using some of the JavaScript APIs defined in the HTML5 standard, CJ and I could create a seamless drag and drop experience for our users on supporting browsers. Furthermore, using an HTML5-based upload feature would allow us to enable users to select multiple files at once, and also display progress on the client without polling. And with HTML5 adoption across the latest versions of three of the top four browsers, we felt confident about building an upload method based on this new technology without the trade-offs of using a third-party plug-in.

We rolled out the first rev of our drag and drop feature a few weeks ago, and we’re impressed with how quickly it has been adopted. It’s already one of the most popular ways to get files onto Box, and in its first week it surpassed our old AJAX upload method. You can check out our demo video to get a feel for the feature:

To build this feature, we referenced a handful of online examples that explained how to use Firefox 3 FileReader object and the drag and drop file event support. Our first implementation used this object to load the file into memory and then took advantage of the latest XMLHttpRequest events to track progress on the client.

var files = event.originalEvent.dataTransfer.files; // drop event
var reader = new FileReader();
 
reader.onload = function(event) {
  var file_contents = event.target.result;
  var request = new XMLHttpRequest();
 
  ... // attach event listeners to monitor progress and detect errors
 
  var post_body = '';
 
  .. // build post body
 
  post_body += file_contents;
 
  .. // finish post body
 
  var url = 'http://example.com/file_upload';
 
  var request = new XMLHttpRequest();
 
  request.open("POST",  url, true); // open asynchronous post request
  request.setRequestHeader('content-type', 'multipart/form-data; boundary=""'); // make sure to set a boundary
  request.send(post_body);
}
 
reader.readAsBinaryString(files[0]);

This approach worked well because we could use the same server processing code that we previously used for uploads. The main disadvantage here is that the FileReader object reads the entire file into memory, which is not optimal for a general upload use case. Our current HTML5 implementation uses this logic and has forced us to restrict drag and drop uploads to just 25mb. However, thanks to recommendations from the Mozilla team, we’ll be taking an alternative approach for V2 of drag and drop, where the file is read chunks as needed by the request. Here’s how we’re going to do it:

var files = event.originalEvent.dataTransfer.files; // drop event
var url = 'http://example.com/file_upload';
 
var request = new XMLHttpRequest();
request.open("POST",  url, true); // open asynchronous post request
request.send(files[0]);

Since this approach is not formatted as a multipart form-data, it will require some adjustments on our back-end to support receiving file uploads in this way. However, it’s definitely worth the trade-off since we’ll get all the benefits of the previous method and we don’t need special file size restrictions. In the future, we’ll consider using yet another way to efficiently upload files that is supported in Firefox 4 and uses the traditional multi-part form:

var files = event.originalEvent.dataTransfer.files; // drop event
var url = 'http://example.com/file_upload';
 
var request = new XMLHttpRequest();
 
var fd = new FormData;
fd.append("myFile", files[0]);
 
request.open("POST",  url, true); // open asynchronous post request
request.send(fd);

We’re already exploring more ways to enrich the Box experience using HTML5. With HTML5, we can build faster, richer and more interactive features with native browser support, and bridge the traditional gap between desktop software and web applications. Here are just a few cool new upload-related features on our roadmap:

  • Pause/Resume uploads using the Blob slice API to split files into chunks (this will be a huge robustness boost, especially for large uploads)
  • Allowing uploads to resume even after the browser closes by caching the file using IndexedDB support (possibly in Firefox 4)

We’d also like to begin a discussion about supporting the reverse drag and drop use case: dragging files from the browser to the desktop. Based on our users’ enthusiasm around the drag and drop upload feature, we think the reverse functionality would well received. If you are interested in contributing to a specification for this feature, please let us know (html5 [-at$] box.net)!

Resources:

12 comments

Comments are now closed.

  1. wildanr05 wrote on June 24th, 2010 at 18:51:

    can’t wait to see the implementation of reverse drag and drop

  2. SanderT wrote on June 25th, 2010 at 02:14:

    I did implement the same V1 solution as described in this article (by using the FileReader) so I was surprised to see an easier solution as described in the V2 version (by using files[0] directly in request.send). But that solution doesn’t work, I think because the File object in the current Firefox implementation (3.6) doesn’t use the Blob object yet. So to use this solution we have to wait for Firefox 4.0. Can somebody confirm my conclusion??

    1. SanderT wrote on July 23rd, 2010 at 03:01:

      Oepsy.. Didn’t test it in 3.6 but in 3.5 :-( My fault.. In 3.6 the V2 solution is working like a charm… :-)

  3. arieff wrote on June 26th, 2010 at 23:07:

    where is the result??

  4. len wrote on July 1st, 2010 at 14:29:

    The V2 solution of sending the File object without using FileReader does work, but the content is not sent as multipart/form-data, so the back end needs to be slightly different In PHP the data is available via php://input rather than $_FILES.

  5. Ryan wrote on July 4th, 2010 at 22:40:

    Nice work it’s great to see drag and drop used on a real product.

  6. ardhan wrote on July 7th, 2010 at 22:55:

    i’m waiting html 6 to come

  7. det wrote on July 18th, 2010 at 23:04:

    it looks easy. just drag and drop

  8. Komrade Killjoy wrote on July 28th, 2010 at 05:52:

    HTtp is not meant for file sharing. That’s the role of that *other* protocol*

    Ftp

    :-P

  9. Dave Merrill wrote on March 17th, 2011 at 04:32:

    After getting an app of mine working in Firefox 3.6 using these techniques, it no longer works in Firefox 4 RC1. Drop areas now show a “cancel” cursor when you drag files over them. Is this intentional? Is there something we now need to do to enable drop from the file system? Or is this a pre-release bug?

    Thanks,
    Dave

  10. David wrote on July 6th, 2011 at 06:52:

    this save my live:

    var fd = new FormData;
    fd.append(“myFile”, files[0]);

    very good code :)

  11. Yasin wrote on December 24th, 2011 at 05:51:

    “i’m waiting html 6 to come” to me :)

Comments are closed for this article.