Uploader Header

The Dojo Toolkit now has support for multi-file uploads, thanks to the new Deft project. The dojox.form.FileUploader class embeds a hidden SWF file in the page which, when triggered, will open a system dialog that supports multiple file selection, and also file masks, which allows the user to filter their selection by file type.

Better yet, it’s fully degradable. If the user does not have version 9 or greater of the Flash Player installed it can, depending on the options you set, present the user with a standard HTML file input instead (or the option to install the latest Flash Player). The HTML form also supports multiple files, although due to browser restrictions, only one can be selected at a time. But they are all uploaded at once.

A major benefit to developers is the flexibility to supply your own styled upload button. For example, a paperclip icon toolbar button in an email application should not look like the standard file input with a text field followed by a “browse …” button. What inspired this design was working on projects where designers and clients would hand me a specification which would say, “the upload button looks like this“.

dojox.form.FileUploader will be in the new 1.2 version of the Dojo Toolkit, which will be released in September. In the meantime, it can be downloaded from one of the nightly builds.

dojox.form.FileUploader

dojox.form.FileUploader is a simple wrapper class. It accepts your parameters, does a little plugin detection, and determines which uploader is necessary: dojox.form.FileInputFlash or dojox.form.FileInputOverlay.

Here is the example usage instantiating the FileUploader:

var uploader = new dojox.form.FileInputFlash({
	uploadUrl:"http.localHost/FileUpload.php",
	button:myButton,
	uploadOnChange: false,
	selectMultipleFiles: true,
	fileMask: ["All Images", "*.jpg;*.jpeg;*.gif;*.png"],
	degradable: true
});

There is only one method: upload(), but there are also events:

  • onChange – Fires when a file or files are selected
  • onProgress – Supplies the current information of each file’s upload progress (Flash only)
  • onComplete – Fires when the file or files have been uploaded
  • onError – Fires during connection problems such as file not found, etc.

dojox.form.FileInputFlash

The FileInputFlash Deft component is installed with dojox.embed.Flash. It is displayed with the minimum 1 pixel x 1 pixel and tucked in the upper left hand corner, so it’s not noticeable but will still be activated by browsers that require the SWF to be on screen. Upon initialization, FileInputFlash connects your button to the browse method within the SWF, so clicking the button will open the system dialog.

dojox.form.FileInputOverlay

The FileInputOverlay API is identical to that of FileInputFlash. It has a couple of differences:

  • it does not fire onProgress (without some server side magic)
  • in the case of selectMultipleFiles = true, the user can’t select multiple files, but can continue to add to the file upload list by clicking the upload button.

Styling FileInputOverlay

The FileInputOverlay was filled with challenges. Standard browser file input fields can’t be modified or styled, and are engineered with security restrictions – restrictions that follow early browser implementations rather than the W3C specification or HTML5 drafts. The restriction is designed to prevent uploading a user’s files without their knowledge, like C:/passwords.txt — which is precisely where I keep all of my passwords.

My project started with the now-standard technique originated by quirksmode, of creating the desired button, then floating the real browse button over the desired button, set it’s opacity to zero, and then conform to the size of the desired button by applying the clip style to the browse button.

Browse Diagram

In order for this implementation to handle an upload button of any size, I needed to set the style of the file input equal to the size of the upload button. Enter Problems with Internet Explorer Mode. Although to be fair, all of the browsers have their challenges.

To accommodate large buttons, the size of the file input had to be big enough to cover the desired button. But again, due to restrictions, changing the height, width, and font-size yielded results like this:

Browse button example A
Figure A

The height, width, and font-size of the text field was changing, not that of the button (although it affected the height). However, after some trial and error, I discovered that setting the font-size using em units works (font-size:5em):

Browse button example B
Figure B

Bingo. So now all that’s left is to set the style, and we’re good, right? Wrong. It seemed that the em trick works only from a cssRule in a style sheet or style tag. Applying the em trick in JavaScript with the style property again leaves us with the results from Figure A. This wouldn’t be a problem in a legacy application, because we’d know what size we wanted the button to be. This is not the case for a JavaScript toolkit.

I could have just made every file input huge, with 10 ems or something, but that seemed dirty. To fix this, I reintroduced (and refactored) the dojo.style package from Dojo 0.4.3, as dojox.html.style. For this purpose, we only need the dojox.html.insertCssRule() method to create the style in a dynamic style sheet before creating the input element.

Final Note: button.click()

In several forums I’ve read that IE is capable of triggering a button through code, with the element’s click() method. I had a client with a requirement for Internet Explorer only. So I thought this would be a neat solution; avoiding the (as yet unwritten) complex patterns above.

It doesn’t work., although it appears to at first. The button triggers, the system dialog opens, the value is populated, and the onChange events fires. However, the field data does not get sent to the server. It gets swallowed by the browser after the submit, and there’s no error notice or warning. It took me quite a while to figure out that the browser security for this component had intervened once again. It’s definitely time for browsers to readdress what is secure and what is not, to allow for a native method for multi-file upload without using Flash.

Summary

It took a long time for the Dojo Toolkit to finally have it’s multi-uploader, but I think the wait was worth it. The Deft project make the FileUploader code for the SWF visible, and it can therefore be fixed or amended by contributors. The HTML portion of the uploader code has gone through months of iterations, so it should accommodate most situations.