Zend certified PHP/Magento developer

HTML5 File Drag, Drop, Analyze, Read and Upload

It’s been a busy week. We’ve discovered how the new HTML5 APIs can help us open, read and upload files which the user dragged and dropped into the browser window. This article summarizes the techniques and the current level of browser support.

HTML5 API Support

Your JavaScript code should check for the existence of the File, FileList and FileReader objects prior to attaching event handlers. At the time of writing, these are supported by the latest versions of Chrome, Firefox and Opera:


if (window.File  window.FileList  window.FileReader) { ... }

Although Opera supports these objects, they can only be used via a standard file input — not drag and drop. Therefore, a further check is required; I suggest using the XMLHttpRequest2 upload method, e.g.


var xhr = new XMLHttpRequest();
if (xhr.upload) {
	... attach drag and drop events ...
}

File Drag Drop

All browsers (except those on the iPhone and iPad) support the file input type which displays the familiar “Browse” button. A “multiple” attribute has been introduced in HTML5 and we can attach a change event handler to the field:


document.getElementById("fileselect").addEventListener("change", FileSelectHandler, false);

Chrome and Firefox also allow users to drag one or more files on to a chosen element. You can attach event handlers including “dragover” and “dragleave” (for changing styles) and “drop” for detecting dropped files, e.g.


document.getElementById("filedrag").addEventListener("drop", FileSelectHandler, false);

Retrieving a FileList Object

The HTML5 FileList object is an array-like collection of File objects. File input fields return a FileList via a files property (event.target.files). Dropped files return a FileList object via the event’s dataTransfer.files property (event.dataTransfer.files).

We can therefore retrieve a FileList object using single event handler:


// cancel event default
e.preventDefault();
// fetch FileList object
var files = e.target.files || e.dataTransfer.files;
// process all File objects
for (var i = 0, file; file = files[i]; i++) {
	...
}

It’s important to cancel the default event. This prevents the browser attempting to display or handle a file when it’s dropped into the window.

Analyzing File Objects

FileList collections contain a number of File objects. Three useful File properties are provided:

  1. .name: the file name (it does not include path information)
  2. .type: the MIME type, e.g. image/jpeg, text/plain, etc.
  3. .size: the file size in bytes.

It’s possible to check a file type and size before further processing or uploads occur, e.g.


// process image files under 300,000 bytes
if (file.type.indexOf("image") == 0  file.size  300000) {
	...
}

For more information, refer to How to Open Dropped Files Using HTML5 and JavaScript.

Opening Files using FileReader

The HTML5 FileReader object allows you to open text or binary files in JavaScript. As you’d expect, the readAsText() method is used for retrieving text content, e.g.


if (file.type.indexOf("text") == 0) {
    var reader = new FileReader();
    reader.onload = function(e) {
		// get file content
		var text = e.target.result;
		...
    }
    reader.readAsText(file);
}

Similarly, the readAsDataURL() method retrieves binary image data as an encoded data URL which can be passed to an image src attribute or canvas element:


if (file.type.indexOf("image") == 0) {
    var reader = new FileReader();
    reader.onload = function(e) {
		document.getElementById("myimage").src = e.target.result;
    }
    reader.readAsDataURL(file);
}

For more information, refer to How to Open Dropped Files Using HTML5 and JavaScript.

Uploading Files using Ajax

Appropriate files can be uploaded to your server while the user remains on the page. It’s simply a matter of passing a File object to the send() method of XMLHttpRequest2:


var xhr = new XMLHttpRequest();
xhr.open("POST", "receivefile.php", true);
xhr.setRequestHeader("X_FILENAME", file.name);
xhr.send(file);

Note we’ve also sent the filename as an HTTP header. This is optional, but it allows us to recreate the file using its original name on the server using a language such as PHP:


file_put_contents(
	'uploads/' . $_SERVER['HTTP_X_FILENAME'],
	file_get_contents('php://input')
);

For more information, refer to How to Asynchronously Upload Files Using HTML5 and Ajax.

Creating Upload Progress Bars

We can also attach a “progress” event to XMLHttpRequest2 objects:


xhr.upload.addEventListener("progress", ProgressHandler);

The handler receives an event object with .loaded (the number of bytes transferred) and .total (the file size) properties. Therefore, the progress can be calculated and passed to an HTML5 progress tag or any other element, e.g.


function ProgressHandler(e) {
	var complete = Math.round(e.loaded / e.total * 100);
	console.log(complete + "% complete");
}

For more information, refer to How to Create Graphical File Upload Progress Bars in HTML5 and JavaScript.

I hope you enjoyed this series. File drag and drop is an important feature which can transform web application usability. HTML5 finally makes it easy.

Written By: