#fileupload This project main focus is to create an EASY to use API to pick files and upload them using ajax requests. This project is compatible with IE 7+, Firefox 2+, Chrome, Safari, Opera and pretty much every other major browser thanks to the amazing moxie (https://github.com/moxiecode/moxie) which provides shims to the HTML5 File API by using Flash in older browsers.
##Dependencies
fileupload depends on jQuery (1.8+ - http://www.jquery.com) and moxie (https://github.com/moxiecode/moxie).
You can get jQuery directly from their website
As for moxie, we provide a precompiled version of moxie's js and SWF files in the 'moxie' folder, but please notice that these precompiled versions are probably not the latest ones so feel free to get the latest version at https://github.com/moxiecode/moxie
##Building
There is no building ;D
Really, besides the dependencies the only thing you need is the fileupload.js. We do not provide a minified version of it (it's just 15KB, or 3KB gziped), but if you really want to save some bandwidth you can easily minify it at http://refresh-sf.com/yui/
##Usage To use file upload you'll need to do 4 things:
- Add a reference to jQuery
- Add a reference to moxie
- Add a reference to fileupload
- Configure the path to the SWF file so that moxie can work on older browsers (optional if you don't need this kind of support)
###Configuring the SWF path To set the path to the SWF file you can use one of two ways:
fileupload.setFlashRuntimePath('path/to/the/swf/file.swf');
or
mOxie.Env.swf_url = 'path/to/the/swf/file.swf';
Both will do the exact same thing, but I do prefer the first way cause it looks 'cleaner' ;D
I think the easiest way to get started with fileupload is to clone this repository and open example.html in the sample folder.
There you'll find a sample page with all the references already in place and commented source code to that shows the most common use cases for this project.
There is also an ASP.NET server-side upload handler implementation in src/server/AspNet.FileUploadHandler.cs
##Components This project contains 4 distinct components that are build on top of moxie and jQuery
- An extension to the mOxie.File class that adds 3 new methods (upload, abort, generatePreview)
- A fileupload.FakeFile class that mimics the mOxie.File class through noops mehtods. This is useful for representing files that are on the server.
- A jQuery plugin to create a file picker 'button' that allows the user to select files to upload (depends on fileupload mOxie.File extensions)
- A fileupload.uploadQueue class to create an upload queue that can manage uploading multiple files and reporting upload progress, completion, failure, etc...
These are the 3 methods that are added to the mOxie.File class:
####upload(url, [options])
Uploads the file to the given url
Returns: a PROMISE where callbacks can be attached
promise callbacks
The promise returned by the upload method can have the done, fail, always and progress callbacks attached to it, by using the same syntax used in jQuery's promises (.done, .fail, .always and .progress)
These are the callback signatures:
progress = function(progress, item)
- progress: an object with total and loaded properties representing the upload progress (see progress status)
- item: an object with the following properties
- chunk: the chunk being uploaded
- file: the file being uploaded
- options: the options used for the upload
- serverResponse: and object which contains the server response. this object has the following properties
- status: the http status returned by the server
- responseText: the response from the server in text format
- totalChunks: the number of chunks the file was splitted into
- uid: the unique upload id
- url: the url where the file is being sent
done, fail and always = function(e, item)
- e: event info
- item: the same as described in the progress callback
Parameter | Description | Required | |||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
url | url to where the file will be uploaded | yes | |||||||||||||||||||||
options |
|
no |
####abort()
Cancels the upload
Returns: nothing
####generatePreview()
Try to generate a preview of the file by creating using window.URL.createObjectURL.
IMPORTANT: If createObjectURL is not supported previews won't be generated and the promise will be rejected with status 'error'.
If previews does not finish generating within 10 seconds the promise will be rejected with status 'aborted'.
Returns: a PROMISE where callbacks can be attached
promise callbacks
progress = function(progress)
- progress: an object with total and loaded properties representing the upload progress (see progress status)
done, fail and always = function(status, preview)
- status: either 'success', 'error' or 'aborted' depending on what happened during generation.
- preview: a String object that represents either the URLObject or dataURL. This String has a release method used to release resources used by the preview (this method has effect only when the preview is a URLObject and is the same as calling window.URL.revokeObjectURL)
This is a class that can be used to represent files that are on the server. To instantiate it you'll need to pass the path to the file that is being represented and, optionally, the generatePreview function.
var fakeFileNoPreview = new fileupload.FakeFile('path\to\my\file.png');
var fakeFilePreview = new fileupload.FakeFile('path\to\my\file.png', sampleGeneratePreviewForFakeFileFunction);
function sampleGeneratePreviewForFakeFileFunction() {
var r = $.Deferred();
r.resolve('success', 'GetPreviewFromServer.aspx?path=' + this.path);
return r.promise();
}
The fake file has the following properties and methods: ####name This is the name of the file. It will NOT contain the full path, just the name of the file. ####size This will always be 0 (zero) ####isFake This will always be true. This can be used to differentiate between a real mOxie.File and the fileupload.FakeFile ####path This will be the complete path to the file as passed in the first parameter for the constructor ####upload() This is a noop method just to keep interface compatibility between the mOxie.File and the fileupload.FakeFile ####abort() This is a noop method just to keep interface compatibility between the mOxie.File and the fileupload.FakeFile ####generatePreview() By default this will return a rejected promise with status 'aborted'. If you want you can pass in your own generatePreview function in the constructor. This custom function MUST return a promise that:
- if preview is generated the promise must be resolved with status 'success' and the url of the preview
- if an error occurs the promise must be rejected with status 'error'
- if preview generation is cancelled the promise must be rejected with status 'aborted'
This is the jQuery plugin that can be used to transform any DOM element into a 'button' that when clicked will open a file selection dialog (like an input type="file").
Moxie creates an element on top of the real element to be able to open file selection dialogs when a click happens. This can make some browser lose the ability to style :hover and :active css. To make it easier to deal with this scenario the 'hover' and 'pressed' css classes is added/removed to the element accordingly.
Usage is similar to other jQuery plugins:
...
<button type="button" id="btnFilePicker">Choose a file...</button>
...
<script type="text/javascript">
$('#btnFilePicker').fileinput({
multiple: false,
accept: []
});
</script>
option | description | default |
---|---|---|
multiple(bool) | allows the user to select multiple files from the file selection dialog | false |
accept(array) | filters which file extensions will be allowed by the file selection dialog. this parameter is an array and each item must be in the format _{ title: 'title to display in dialog', extensions: 'jpg,png,bmp' }_ | [] (accepts any extension) |
###events
To subscribe to events use jQuery's .on method
event | description | arguments |
---|---|---|
ready(e) | triggered when the file input is ready to be used | e = event info |
change(e, f) | triggered when a file selection is made | e = event info f = selected files array |
mouseenter(e) | triggered when the mouse cursor hover over the file picker | e = event info |
mouseleave(e) | triggered when the mouse cursor stops hovering over the file picker | e = event info |
mousedown(e) | triggered when the mouse buton is pressed over the file picker | e = event info |
mouseup(e) | triggered when the mouse buton is released over the file picker | e = event info |
##fileupload.uploadQueue([options])
This class can be used to control uploading multiple files to the server.
options | description | default |
---|---|---|
url(string) | default url to use when uploading files | null (no default URL) |
extras(object) | object in a 'key-value' format that will be sent to the server for EVERY file being uploaded by the uploadQueue. see mOxie.File extensions _upload_ method parameters for more info |
###methods
####addFile(key, file, [options])
Adds a file to the queue. Parameter 'options' is the same as the one used in mOxie.File extensions upload method.
Returns: nothing
####removeFile(key)
Removes the item with the given key from the queue if it is NOT being uploaded
Returns: nothing
####removeAll()
Removes all items from the queue that are NOT being uploaded
Returns: nothing
####getCount() Returns: The number of items in the queue
####getItems() Returns: An array with a COPY of all the items in the queue
####getItem(key) Returns: A COPY of the item if found, null otherwise
####containsKey(key) Returns: true if the key is present, false otherwise
####upload([url], [key])
If key is provided uploads the file with the given key to the server. If key is not provided uploads all files in the queue to the server.
If url is not provided the files will be sent to options.url (the default url for the queue).
Returns: a PROMISE where callbacks can be attached
promise callbacks
The promise returned by the upload method can have the done, fail, always and progress callbacks attached to it, by using the same syntax used in jQuery's promises (.done, .fail, .always and .progress)
The promise will end successfully if all uploads are successful, will fail if any upload fails.
Altough it is possible to add these callbacks to the promise it's far easier to use the queue events (see below) since these will have arguments that have already been pre-processed.
####abortUpload([key])
If a key is provided aborts the upload for the file with that key. If a key is not provided abort all current uploads.
Returns: nothing
####on() Use this method to subscribe to events raised by the uploadQueue. Internally this method calls jQuery.on upon the uploadQueue, which means that the parameters for these methods are exactly the same as jQuery's .on method.
####off() Use this method to unsubscribe to events raised by the uploadQueue. Internally this method calls jQuery.off upon the uploadQueue, which means that the parameters for these methods are exactly the same as jQuery's .off method.
###events To subscribe and unsubscribe to events use queue.on and queue.off. The syntax is similar to jQuery's .on and .off methods.
event | description | arguments |
---|---|---|
fileAdded(e, i) | triggered when a file is added to the queue | e = event info i = queue item (see below) |
fileRemoved(e, i) | triggered when a file is removed from the queue | e = event info i = queue item (see below) |
uploadStarted(e) | triggered when queue starts uploading | e = event info |
uploadProgress(e, p) | triggered to indicate queue progress (this is the general progress, for file-specific progress see fileProgress) | e = event info p = progress status (see below) |
uploadFinished(e, s) | triggered when queue finishes uploading | e = event info s = upload status (see below) |
fileSent(e, i) | triggered when a file starts uploading | e = event info i = queue item (see below) |
fileProgress(e, p, i) | triggered to indicate file upload progress | e = event info p = progress status (see below) i = queue item (see below) |
fileDone(e, i) | triggered when a file was successfully uploaded | e = event info i = queue item (see below) |
fileFailed(e, i) | triggered when a file failed to upload | e = event info i = queue item (see below) |
fileFinished(e, i) | triggered when a file finishes uploading (either when upload was sucessful or not) | e = event info i = queue item (see below) |
####queue item The queue item represents a file that has been enqueued and has the following properties:
- key: the key of this item in the queue
- file: the file that was enqueued
- options: the options passed to the addFile method
####progress status The progress status has the following properties:
- total: the total size that will be uploaded in bytes
- loaded: the amount of bytes that were already uploaded
####upload status The upload status has the following properties:
- total: total number of files that were sent to the server
- success: number of files that were uploaded successfuly
- error: number of files that were NOT uploaded sucessfuly
##Server-side upload handler
When you upload file to the server some extra information goes along with the file itself so that you can handle partial uploads (chunking).
The server-side upload handler is pretty straightforward: everything is sent as a standard multipart POST, which means that your web framework of choice
probably already parses the request into a more manageable format.
To simplify handling uploads each request that is made to the server contains a single file or chunk, even when uploading from an fileupload.uploadQueue or
using the 'multiple' option on jQuery.fileInput.
As said earlier in src/server/AspNet.FileUploadHandler.cs you'll find a C# implementation of a server-side upload handler for reference.
There are 2 variables that are always sent (using chunking or not):
- filename: this contains the name of the file that is being sent. generally the filename can be obtained directly, but when using chunking we lose the filename (it will be 'blob'), so to make thing simple we always send the original filename to the server in this variable
- uid: this is a unique upload identifier (UUID). this is used to diferentiate sequential uploads of the same file and also assists in handling chunked uploads
When using chunking is importante to notice that chunks will arrive as if they were regular files and that chunks can arrive out-of-order. Because you need to know if you're receiving a chunk or not and also the exact order you must rearrange these chunks in order to rebuild the file on server, there are 2 more variables that are sent when chunking: - chunk: this is the chunk number. the chunk number is used to define the order in which chunks must be arranged to reasemble the file on server
- totalChunks: this indicates the number of chunks that compose the file being uploaded. this information together with the uid can be used to determinate if all chunks were received, so that the file can be reassembled
The server can respond to an upload with anything it wants. Upload success or failure is based on the http status of the response (200 = success, anything else = failure). You can access the server response from the serverResponse object that is an argument received by the promises callbacks
##License This project is released under the "clone this repository and do whatever you want with it" license ;D