The Dojo Toolkit Multi-file Uploader

By on September 2, 2008 12:02 am

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.

Comments

  • Pingback: Ajaxian » Dojo Multifile Uploader with Flash()

  • Dan

    Very nice. You should also include an example that has a progress bar.

  • Matthew

    Does this Multi-file uploader handle the Flash 10 changes that only allow the opening of the Flash File browse on Flash based click?

    http://theflashblog.com/?p=423

  • Hunter

    How are the files sent, and what are the post query parameters of the files?

    I need something like this, but I need to be able to plug into a specific upload API that needs inputs like

    ?image0=[]&image1=[]

  • @Matthew: In a word, no. I’ll probably implement the Google Gears uploader first before I fix Adobe’s security *enhancement*

    @Hunter: You’ll find in my test php file, UploadFile.php:
    Flash fieldname: Filedata
    HTML fieldname: uploadedfile
    HTML multi fieldname: uploadedfile[number]

    The HTML multi mode would handle what you request – the fieldname can be changed as a property.

    For Flash though, it’s a bit problematic. The fieldname can be changed, although that is not implemented here. Also, Flash actually uploads to the server one at a time, not all at once with numbered fieldnames. Not sure if it could be manipulated to change the fieldname on each upload. I’d think not.

  • Pingback: SitePen Blog » The State of File Uploaders()

  • vinu

    MultipleFileUpload widget is very nice. I have a question regarding this widget.
    Once we selected multiple files , can we remove some of them before uploading?

  • @vinu:
    Thanks, and that’s an interesting question. The short answer is no. Looking at the Flash documentation, there is a FileReference.cancel() method that stops the upload. Whether this stops it before it starts I’m not sure. It would require experimentation.

  • Rozik

    Hi there,

    i tried to use this widget but everytime i hit the upload button i get the following error:

    this.flashMovie is undefined

    any i dea whats wrong there?

    This is how i define the widget:

    fileUploader = new dojox.form.FileUploader({
    button:dijit.byId(“btn0″),
    degradable:true,
    uploadUrl:”content-flow?execution=${flowExecutionKey}&_eventId=uploadFile”,
    uploadOnChange:false,
    selectMultipleFiles:true,
    fileMask:[“All Files”, “*.*”],
    isDebug:true
    });

  • fgamador

    I’m having a similar problem. The demo (https://user.sitepen.com/~mwilcox/dojotoolkit/demos/uploader/demo.html) works fine for me, but if I copy it to my machine (along with src.js and demo.css), and I change the referenced Dojo to http://o.aolcdn.com/dojo/1.2.0/dojo/dojo.xd.js, it doesn’t work. FireBug gives errors:

    this.flashMovie.setFileMask is not a function
    this.flashMovie.openDialog is not a function
    this.flashMovie.doUpload is not a function

    The same thing happens if I try this with the nightly test (http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/form/tests/test_FileUploader.html)

  • Hi,
    I have tried to use your demo with dojo 1.2, but the onComplete event doesn’t seem to be fired.
    Is there a difference between dojo 1.1 et 1.2 ?
    thanks
    Pascall

  • @Rozik, fgamador, pascall:
    I’m having trouble reproducing your errors. It would be enormously helpful if you could create a test file or the steps to reproduce, and file a bug at http://bugs.dojotoolkit.org/ – cc: mwilcox.

    I assure you all that I am especially concerned with the communication errors to the flashMovie, and would like that part in particular to be as trouble-free as possible.

    @pascall:
    his has not been tested on the CDN – it may cause some timing issue with the load, I’m not sure. The Uploader is technically part of 1.2 and was not in 1.1 – it’s release date made it look like that though.

  • Hi,
    thanks for your answer,
    I have tried to connect to http://bugs.dojotoolkit.org/ , i cannot reach to connect myself.

    For my test, i use the same html and src.js as yours in https://user.sitepen.com/~mwilcox/dojotoolkit/demos/uploader/demo.html, so it’s easy to reproduce.

    thanks
    pascall

  • @pascall
    The Trac on Dojo is a little finicky. You may have to try a few times. Log in with user:guest, pass: guest.

    However, first check your permissions. I’m using the exact same code on my machine (sans the CDN) and it works – but I have to set the folder permissions for “uploader” and “UploadedFiles” to read, write and execute (execute may not be necessary) – and I also needed to set the owner (on my Mac) to _www. I can’t remember what it is, but there is a PC equivalent to give “system access”.

  • In fact, the upload works, files are uploaded on the server but which is not working, is the onComplete even after which, in your demo, the image appears on the right and its name appears in the textarea for removal.
    Progress event works fine, from 0 to 100%, but after 100% nothing appends.

  • Hi,
    i have another trouble. The same script (html,js) have 2 different behaviors at work or a home, with FF3.
    At work, uploader.swf is loaded and works fine, on click a window appears asking for images, but at home flash is not loaded, and i have and input type file instead of (as your example above )
    Both computers are on FF3, with the same flash plugin version.

    you can see it on http://test.mrbinr.com/testDojo/uploader/demo.html

    I still cannot reach to connect myself to http://bugs.dojotoolkit.org/ and i have the same problem with my identification on dojotoolkit for which i always have to ask for new password. (its really strange..)

  • oups, sorry, i check flash plugin version, and at work its Flash 9.0 r124 and at home it’s 10, i think it’s why behaviors are different.

  • hi, i have installed Flash player 10 at work, and your script does not work anymore on FF3.

    Into FF3, if you click on ‘Select images’, an error is sent into firebug :

    [Exception… “‘Error calling method on NPObject! [plugin exception: Error in Actionscript. Use a try/catch block to find error.].’ when calling method: [nsIDOMEventListener::handleEvent]” nsresult: “0x8057001e (NS_ERROR_XPC_JS_THREW_STRING)” location: “” data: no]
    Line 0

    May be it can help you…

    I have tried under IE7, and it works.

  • Nick

    Hi –

    I was wondering where I may be able to find the src.js source to your example since I cannot seem to find it. I am looking on simply using the multi-file html form handling mechanism that the dojox.form.FileInputOverlay provides.

    Thanks
    Nick

  • There are plans to make the Demos publicly available, but in the meantime, you can access them here:

    http://download.dojotoolkit.org/current-stable/dojo-release-1.2.0-demos.tar.gz

    BTW: The Uploader does not work with Flash Player 10. I mention that in my next blog but not this one. It’s a high priority for me to make it compatible, but I haven’t yet had a chance.

  • Hello !
    If you need to upload multiples files you can also use a flash uploader like NAS Uploader.
    examples and source codes here
    http://www.nasuploader.com
    bye

  • TobyM

    swfupload.org and digitarald.de/project/fancyupload/ have betas out for multi-uploaders with Flash 10 support.

  • ken

    demo only gives me javascript errors.

  • ken

    nice start … your demo throws javascript errors, but hey, whatever.

  • Yes, this blog was written before the new version was written to support the Flash 10 plugin with the new security, as pointed out here:
    http://www.sitepen.com/blog/2008/12/01/dojox-fileuploader-upgrade-to-support-flash-10/

    We’ll update this blog to point to the v10 code. The demo is here:
    http://mwilcox.dojotoolkit.org/dtk/demos/uploader/demo.html

  • Anurag kirpal

    i am using this comp
    but in src.js i need to capture file path not only names
    is there any attribute to capture filepath
    its urgent
    Pls let knw.

    Anurag Kirpal

  • @Anurag kirpal:
    The onComplete handler will return an array of file items. In each item there is a “file” property, with the file path.

  • Phil Bowles

    It’s getting weirder – I upgraded both IE7 and FF to flash 10. Now the FileUploader code chooses the “overlay” code rather than the “flash” code – so I set degradable:false to force the use of the “flash” codeand I get
    [Exception… “‘Error calling method on NPObject! [plugin exception: Error in Actionscript. Use a try/catch block to find error.].’ when calling method: [nsIDOMEventListener::handleEvent]” nsresult: “0x8057001e (NS_ERROR_XPC_JS_THREW_STRING)” location: “” data: no]
    from FF and some bizarre and useless error from IE7 (no change there then!) immediately before the swf open dialog in _openDialog()

    Does flash 10 need a different version of the swf uploader?

    (back to the “overlay” code…

  • Phil: yes, you are using the old code. I made the first version of the uploader just days before they released Flash 10 with an oppressive security feature that does not work with the old code.

    The new version doesn’t use “degradable” = it’s: force: flash / html / “” – the “” acts as degradable.

    Go to this page and download the 1.3 Beta. It has all the fixes in it (and 1.3 is very stable):

    http://download.dojotoolkit.org/

  • Problem with code on external loaded on TabContainer.
    When click on buttom, nothing appair, if use external (stand alone) all it’s right!
    any Idea?

  • @paladinux:
    There’s a Windows-Firefox bug that renders scrolling content over the top of Flash movies, so the button becomes unclickable. I’m sorry, but the fix is pretty difficult and will take some time. There is a ticket filed on this bug and has some possible workarounds:
    http://bugs.dojotoolkit.org/ticket/8784

  • Stefan

    For the “dead button” bug above:

    dojox.embed.Flash does not use the wmode parameter. I added + ‘wmode=”window” ‘ in there and that made the fileUpload to kick off from a tabContainer and a borderContainer. Guess wmode=opaque also works, but the default wmode=transparent does not.

  • @Stephan: I’m not sure what you are talking about. I use wmode all the time, and it’s the key to the transparent Flash movie that hovers over the button. Please email me at mwilcox AT sitepen.com to discuss.

  • Stefan

    Mike, I was talking about the bug paladinux mentioned – when fileUploader is loaded in a dojoContainer it sometimes does “feel” that the button is pressed. That is because the uploader.swf is rendered with ‘wmode=transparent’ (in FF, it might default to something else in another browser). With wmode transparent, the html can be rendered over the button and it will therefore be untouched by a click. So I thought that I send in the wmode parameter to dojox.embed.Flash and that is when I discovered that dojox.embed.Flash does not use wmode at all, it sends nothing for wmode and therefore it will always be the browser that decides wmode.

    In short:
    dojox.embed.Flash needs to handele wmode parameter
    dojox.form.FileUploader should also accept the wmode parameter and send it to dojox.embed.Flash

    I fixed it for me by manually adding wmode in my dojox.embed.Flash, but I guess best would be if it was changed to accept the parameter.

  • Clifford Cheng

    Is there an example for JSP?

  • How do i add additional request params to be recieved by server side code?

  • Mat

    I also have

    this.flashMovie.setFileMask is not a function
    (171 out of range 16)

    error.

    It works on one page but not on the other and both are using the same local dojo library :-/

    Any ideas?

  • Art

    hi,
    I am trying to use the “dojox.form.FileUploader” and using similar code as mentioned above but when I hit upload i get an error in firebug
    I am trying this on an https server.
    Would appreciate your help.
    Server failed to respond
    admin
    * doUpload File IMG_5793.jpg
    single file – do upload, fieldName flashUploadFiles
    ioErrorHandler: name=IMG_5793.jpg event=[IOErrorEvent type=”ioError” bubbles=false cancelable=false eventPhase=2 text=”Error #2038″]
    timerHandler: tick: 1 of: 5
    timerHandler: tick: 2 of: 5
    timerHandler: tick: 3 of: 5
    timerHandler: tick: 4 of: 5

  • Hi guys,

    I’ve developed something quite similar. It might help some of you.
    To be honest, your code helped me to develop MFU, thank you very much.
    You can take a look at a demo / screencast here http://developers.sirika.com/mfu/
    it using dojo framework, and PHP APC in order to have a file status.

  • Vijay

    hey,

    Could you please provide a working example along with this description?

    Regards,
    Vijay

  • Bharath

    Hi All,

    I am working on enhancement a project which required multiple file upload. As project uses DOJO 1.4.3 we opted for dojox.form.FileUploader.

    In order to get the basic understanding of the widget, I downloaded 1.4.3 demos along with 1.4.3 stable build, I deployed the scripts on server and opened demo.html in IE8 as well as Mozilla. I was able to select multiple files but dojo.connect is not firing on onChange, onProgress and onComplete.

    Would appreciate if any one can help, why demo provided by DOJO 1.4.3 for fileUploader is not working as desired in IE8 and Mozilla, but works fine with with IE6.

    Thanks,
    Bharath