Good Progress

I am happy to announce that Apache Cocoon now has (what seems like the Holy Grail of Web 2.0) a file-upload progress bar.

This was definitely no one-man effort.

I had a lot of help from members of the Apache Cocoon developers community, including Sylvain Wallez knew how to make it work, Upayavira had done part of the job, Vadim Gritsenko helped me get i18n working with JSON, Mark Lundquist supplied a patch to allow me to use nice namespaced JavaScript from the SiteMap, I had a commercial sponsor (thanks guys!!) and last but not least, I would not have considered the job without the fantastic Dojo Ajax Toolkit.

The most lengthy part of the job was not writing the code, but doing the research.

File-type input fields in HTML forms can be tricky beasts, they have a limited API for security reasons. Marrying those with the excellent (but internally complex) CForms framework in Cocoon, posed another set of problems. Making the CForms BrowserUpdate mechanism work via Dojo’s IframeIO cross-platform so that file-type input fields can be submitted via AJAX events in the background was the biggest hurdle, as it exposes you to the plethora of DOM bugs in the current browsers. It still does not work in Safari (but has been fixed in Webkit, so should work soon).

It is amazing, the shenanigans you have to go through to get something like an upload progress bar working. It amazes me that none of the browsers have this feature built-in to their native file-type input fields, as this is clearly the easiest place to do the job.

So, how does it work ?

You add the Widget to your form :

<div class="dojo-FormUploadProgress">Upload Progress :</div>

When the Widget instantiates, it attaches itself via an event-listener to the form submit.
When the form is submitted and the upload begins, Cocoon’s MultipartParser writes upload status info to the user’s Session, the Widget begins to poll a system-level URL in Cocoon to retrieve this info as a JSON Object and updates the page with it.

It sounds easy now, but the devil is in the details.

The Dojo library made the polling and updating really easy, but if only there was a decent API on the browser, we would not need to muck around asking the server how much data had been uploaded, I mean the browser knows this, you just cannot ask it.

You cannot find out how big the files are until the uploads are finished. There is only a single Content-Length in the request and this includes the size of the files and any other fields that may be in the form. My original usecase was for one progress bar per file, but this is impossible unfortunately, unless you want to get really deep and dirty and make a separate submit for each field.

Anyway, it has been a really interesting project and it is not over yet.
There has got to be a lot more testing on more Browsers than I can run here. Then I need to re-work the code to commit it to ‘trunk’ so that we have this in Cocoon 2.2 as well as 2.1.10-dev.

Thanks again to everyone who helped this become a reality.


As seen on Ajaxian.