#

Jump to Table of Contents

# Uploader

The YUI Uploader leverages HTML5+XMLHttpRequest 2 or Flash to provide file upload functionality beyond the basic HTTP `<input type='file'>` capabilities. Specifically, the Uploader allows for:

1. Multiple file selection in a single "Open File" dialog.
2. Dragging-and-dropping files into the browser (when used in HTML5 mode).
3. Automatic upload queue management with fine-grained control.
4. Upload progress tracking, both on a per-file and a per-queue basis.
5. A range of available file metadata: filename, size, date created, and date modified.
6. A set of events dispatched on various aspects of the file upload process: file selection, upload progress, upload completion, data return, and upload errors.
7. Inclusion of additional data in the file upload POST request, on a file-by-file basis.
8. Keyboard accessibility both in HTML5 and in Flash modes.

## Upgrading from version 3.4.1 or older?

Uploader has been refactored for 3.5.0. Parts of its API have changed in backward-incompatible ways.

Read the 3.5.0 Migration Guide for tips on a smooth transition. If you still run into issues, please file a ticket.

If you are unable to upgrade due to unresolvable issues, you can use the `uploader-deprecated` module suite, which is equivalent to the 3.4.1 implementation. But be aware that this module will be removed in a future version of YUI.

## Getting Started

To include the source files for Uploader and its dependencies, first load the YUI seed file if you haven't already loaded it.

    <script src="http://yui.yahooapis.com/3.10.3/build/yui/yui-min.js"></script>

Next, create a new YUI instance for your application and populate it with the modules you need by specifying them as arguments to the `YUI().use()` method. YUI will automatically load any dependencies required by the modules you specify.

    <script>
    // Create a new YUI instance and populate it with the required modules.
    YUI().use('uploader', function (Y) {
        // Uploader is available and ready for use. Add implementation
        // code here.
    });
    </script>

For more information on creating YUI instances and on the `use()` method, see the documentation for the YUI Global Object.

## Uploader Usage Notes for the Flash mode

- Because of security requirements of the Flash Player, the Uploader in Flash mode must receive a direct user input in order to initiate file browsing.
- The target server for file uploads must include a `crossdomain.xml` file that allows access from the location where the uploader SWF file is hosted. See more in the Backend Setup section below, or read the crossdomain specification on Adobe's website.
- The relative URLs to the target server are resolved differently in the Flash mode than they are in the HTML5 mode. In Flash mode, the URLs are resolved relatively to the location of the SWF file, whereas in HTML5 mode, they are resolved relatively to the location of the web page. It is best to avoid using relative URLs for upload targets and use absolute URLs instead.
- The body of the server response to the Flash upload must be greater than 0 bytes. If its length is 0, then the upload is not registered as complete.
- Because of limitations of the Flash Player, the Uploader in Flash mode does not transmit session data (cookies) in the header of the POST requests it sends to the server. In order to transmit the session data, the developer will need to programmatically extract it from the DOM and send as part of the body of the POST request.
- The Uploader SWF should always be served from an HTTP server due to Flash Player's restricted local security model.
- The Uploader control should not be placed in a container with `visibility` set to `hidden`, or `display` set to `none`, whether at initialization of the page, or at any subsequent time. Because of how the Flash Player is instantiated, setting these properties to these values will result in the loss of communication between the Flash player and the DOM. If it's necessary to hide the instance of the Uploader on the page, its width and height should be set to 0.
- The Uploader requires Flash Player 10.1 or higher. The latest version of Flash Player is available at the Adobe Flash Player Download Center.
- Because of a long-standing bug in Internet Explorer, the Uploader SWF does not function properly in IE when loaded from local cache. For that reason, in IE, the default URL for the SWF is appended with a random GET parameter to prevent loading from cache.

## Uploader Usage Notes for the HTML5 mode

- Because of security requirements of crossorigin requests in XMLHttpRequest Level 2, the Uploader in HTML5 mode sends out a preflight `OPTIONS` request to the target server for file uploads (if the target server is different from the one that is hosting the page originating the request). See the Backend Setup section below for more information, or read more about CORS on the HTML5Rocks website.
- Because of variations in browser support for multiple concurrent XMLHttpRequests, we recommend limiting the number of simultaneous uploads to 2.

## Using the Uploader

In this section, we'll describe how to use the uploader in detail. First, let's look at the structure of the uploader module under the hood.

### Anatomy of the Uploader

#### Progressive Enhancement

The Uploader consists of two classes, one of which is picked dynamically based on the functionality available on the end user's computer. For that reason, `Y.Uploader` is an alias that is dynamically assigned either to the `Y.UploaderHTML5` (for browsers that implement XMLHttpRequest Level 2) or `Y.UploaderFlash` (for browsers that include the Flash player plugin), or otherwise left as an unpopulated namespace when neither functionality is available. Before instantiating the Uploader, the developer can easily determine which of the three options has been loaded by checking the static `Y.Uploader.TYPE` property. This property resolves to either `"html5"`, `"flash"`, or `"none"`, and allows the developer to configure the uploader appropriately or otherwise load a different UI.

Due to the limitations of the Flash player, it is only possible to initiate the file selection dialog for Flash-supported file uploads with a direct user input to the Flash player. For that reason, and to maintain the API and configuration consistency, the Uploader is implemented as a "Select Files" button widget in both the HTML5 and the Flash modes. In case of HTML5 uploader, the interaction events are dispatched by the underlying UI control, whereas in case of the Flash uploader, a transparent Flash player overlay is placed on top of the control and captures all mouse events directly. The underlying UI control is customizable by the developer (the `selectFilesButton` attribute).

#### Hybrid structure

In Flash mode, the Uploader uses the native functionality of the widely adopted Adobe Flash player to provide methods for sending multiple files to the server and tracking the progress of the uploads. In order to control the Flash player, the Uploader uses the Flash player's built-in `ExternalInterface` class for communicating with JavaScript. `ExternalInterface` allows JavaScript to call exposed methods on an instance of a Flash player, and allows the instance of the Flash player to call arbitrary global methods in the global JavaScript space.

In order to properly instantiate the Flash player and communicate with it, the Uploader uses YUI SWF utility. The SWF utility encapsulates the instance of the Flash player and standardizes communication with it (e.g., all Flash player method calls are wrapped in SWF's `callSWF` function; correspondingly, all method calls from the Flash player are exposed as events dispatched by SWF.)

### Instantiating and Configuring the Uploader

#### Simple Instantiation

To place the Uploader on the page, simply create a new instance of `Y.Uploader` and render it to the container in which it should be placed. Since `Y.Uploader` may not resolve to a fully-featured module if the required functionality is missing, test that the `Y.Uploader.TYPE` property is not set to `"none"` first. It is recommended that you set fixed dimensions in the configurations for the uploader widget, because the underlying button UI control is by default sized to 100% of the width and height of its parent:

    YUI({...}).use('uploader',function (Y) {

     if (Y.Uploader.TYPE != "none") {
        var uploader = new Y.Uploader({width: "300px",
                                       height: "40px"}).render("#uploaderContainerID");
     }

    });

#### Manual Uploader Type Override

With the above instantiation, you are allowing the Uploader to automatically choose whether to use `UploaderHTML5` or `UploaderFlash` as the underlying module. You can always use those modules directly or manually override the alias as follows:

    YUI({...}).use('uploader','uploader-flash', function (Y) {

    Y.Uploader = Y.UploaderFlash;

    // or

    Y.Uploader = Y.UploaderHTML5;

    var uploader = new Y.Uploader(...);

    });

#### Features Based on Available Functionality

You can further use the `Y.Uploader.TYPE` property to add functionality-specific features to the Uploader based on whether HTML5 or Flash are available. For instance, in the following code snippet, if the Uploader is in HTML5 mode, we assign it a drag-and-drop area where files can be dragged directly into the browser (functionality which is unavailable in Flash). If it's in Flash mode, we provide a `fileFilters` configuration which allows the selection dialog to filter files by extension (functionality only available in Flash):

    YUI({...}).use('uploader', function (Y) {

       var uploader = new Y.Uploader(...);

       if (Y.Uploader.TYPE == "html5") {
           uploader.set("dragAndDropArea", "#divContainer");
           uploader.render("#selectFilesButtonContainer");
       }
       else if (Y.Uploader.TYPE == "flash") {
           uploader.set("fileFilters", [{description:"Images", extensions:"*.jpg;*.png;*.gif"},
                                        {description:"Videos", extensions:"*.avi;*.mov;*.mpg"}]);
           uploader.render("#selectFilesButtonContainer");
       }
       else {
           Y.log("No Flash or HTML5 capabilities detected.");
       }

    });

#### Uploader Configuration Attributes

The following configuration attributes are specific to the Uploader:

Attribute | Description | Default
--- | --- | ---
`appendNewFiles` | A Boolean indicating whether newly selected files should be appended to the existing file list, or whether they should replace it. | `true`
`buttonClassNames` | The names of CSS classes that correspond to different button states of the "Select Files" control. These classes are assigned to the "Select Files" control based on the mouse states reported by the Flash player or by the state of the HTML5 Uploader. The keys for the class names are: `hover`: the class corresponding to mouse hovering over the "Select Files" button.UploaderFlash `active`: the class corresponding to mouse down state of the "Select Files" button.UploaderFlash `disabled`: the class corresponding to the disabled state of the "Select Files" button. `focus`: the class corresponding to the focused state of the "Select Files" button.UploaderFlash |
    {
    hover:
    "yui3-button-hover",
    active:
    "yui3-button-active",
    disabled:
    "yui3-button-disabled",
    focus:
    "yui3-button-selected"
    }
`dragAndDropArea` UploaderHTML5 | The node that serves as the drop target for files. | `null`
`enabled` | A Boolean indicating whether the uploader is enabled or disabled for user input. | `true`
`errorAction` | The action performed when an upload error occurs for a specific file being uploaded. The possible values are: `Y.Uploader.Queue.CONTINUE`: the error is ignored and the upload process is continued. `Y.Uploader.Queue.STOP`: the upload process is stopped as soon as any other parallel file uploads are finished. `Y.Uploader.Queue.RESTART_ASAP`: the file is added back to the front of the queue. `Y.Uploader.Queue.RESTART_AFTER`: the file is added to the back of the queue. | `Y.Uploader.Queue.CONTINUE`
`fileFieldName` | A String specifying what should be the POST field name for the file content in the upload request. | `"Filedata"`
`fileFilters` UploaderFlash | An array indicating what fileFilters should be applied to the file selection dialog. Each element in the array should be an object with the following key-value pairs:
    { description : String,
      extensions: String of the form"."ext1;.ext2;*.ext3;..."
    }
| `null`
`fileList` | The array of files to be uploaded. All elements in the array must be instances of `Y.File` and be properly instantiated depending on whether `UploaderHTML5` or `UploaderFlash` is being used. | `[]`
`multipleFiles` | A Boolean indicating whether multiple file selection is enabled. | `false`
`postVarsPerFile` | An object, keyed by fileId, containing sets of key-value pairs that should be passed as POST variables along with each corresponding file. This attribute is only used if no POST variables are specified in the upload method call. | `{}`
`selectButtonLabel` | The label for the "Select Files" widget. This is the value that replaces the `{selectButtonLabel}` token in the `Y.Uploader.SELECT_FILES_BUTTON` template. | `"Select Files"`
`selectFilesButton` | The widget that serves as the "Select Files" control for the file uploader. | `HTML Button with YUI3 CSS Button skin`
`simLimit` | The number of files that can be uploaded simultaneously if the automatic queue management is used. This value can be in the range between 2 and 5, with the value of 1 or 2 recommended. | `2`
`swfURL` UploaderFlash | The URL to the SWF file of the flash uploader. A copy local to the server that hosts the page on which the uploader appears (rather than a CDN-sourced uploader) is recommended. | `CDN Prefix` + `uploader/assets/flashuploader.swf`
`tabElements` UploaderFlash | The `id`'s or Node references of the DOM elements that precede and follow the "Select Files" button in the tab order. Specifying these allows keyboard navigation to and from the Flash player layer of the uploader. The two keys corresponding to the DOM elements are: `from`: the id or the Node reference corresponding to the DOM element that precedes the Select Files button in the tab order. `to`: the id or the Node reference corresponding to the DOM element that follows the Select Files button in the tab order. | `null`
`uploadURL` | The URL to which file upload requested are POSTed. Only used if a different url is not passed to the upload method call. | `""`

#### Multiple file selection

While the file selection dialog in the Uploader is standard for the user's specific operating system, you can specify whether you want the user to be able to select multiple files, or just one:

    uploader.set("multipleFiles", true);

### The Upload Process

#### Automatic Queue Management

After the user has selected a file (or files) to be uploaded, the selected file list is places into the `fileList` attribute of the Uploader. At that point, you can either have the user initialize the actual upload process, or initialize it automatically, without any additional user action.

Each of the selected files is uploaded in its own POST request. You can either upload each file individually, and manage the queue on your own, or use the Uploader's built-in queue management. To upload a single file "manually" (without using automatic queue management), the following method call can be made:

    var firstFile = uploader.get("fileList")[0];
    uploader.upload(firstFile, "http://url.to/upload.php", {postvar1: "foo", postvar2: "bar"});

To upload all files using the built-in queue manager, you can call the `uploadAll()` method:

    uploader.uploadAll("http://url.to/upload.php");

You can also upload a subset of the provided files, using the `uploadThese()` method:

    var firstFive = uploader.get("fileList").slice(0,5);
    uploader.uploadThese(firstFive, "upload.php");

#### Monitoring Upload Progress

When using the automatic queue management, you can monitor the overall upload progress by subscribing to the `totaluploadprogress` event, which reports the number of bytes uploaded, the total number of bytes, and the percentage of the upload completed:

    uploader.on("totaluploadprogress", reportProgress);

    function reportProgress (event) {
    	Y.log("Bytes uploaded: " + event.bytesLoaded);
            Y.log("Bytes remaining: " + (event.bytesTotal - event.bytesLoaded));
            Y.log("Percent uploaded: " + event.percentLoaded);
    }

Individual file upload progress is also reported, via the `uploadprogress`, `uploadcomplete`, and `uploaderror` events described below.

#### Custom Queue Control

During the automatic queue management of multiple files, you can call various methods on the Uploader queue (available as `uploaderInstance.queue`) in order to control the file upload. The methods available to you include:

- addToQueueTop() and addToQueueBottom(): allow you to include additional files in the upload queue, either at the beginning or at the end.
- cancelUpload(): cancel a specific file's upload. If no arguments are passed, all of the uploads are cancelled.
- forceReupload(): if a particular file is stuck in an ongoing upload without any progress events, you can force its reupload. This method is equivalent to cancelling the file's upload and then adding it back to the queue.
- pauseUpload(): complete all currently ongoing uploads, but ceases starting new ones, until startUpload() is called.

For more information, see the API Docs for Uploader.Queue.

### Uploader events

Uploader fires the following events during operation:

Event | Cause | Payload
--- | --- | ---
`alluploadscomplete` | Signals that the upload process of the entire file list has been completed. | `None`
`click` UploaderFlash | Signals that a mouse has been clicked over the `Select Files` button. | `None`
`dragenter` UploaderHTML5 | Signals that a dragged object has entered into the uploader's associated drag-and-drop area (if one is specified). | `None`
`dragleave` UploaderHTML5 | Signals that a dragged object has entered into the uploader's associated drag-and-drop area (if one is specified). | `None`
`dragleave` UploaderHTML5 | Signals that an object has been dragged off of the uploader's associated drag-and-drop area (if one is specified). | `None`
`dragover` UploaderHTML5 | Signals that an object has been dragged over the uploader's associated drag-and-drop area (if one is specified). | `None`
`drop` UploaderHTML5 | Signals that an object has been dropped over the uploader's associated drag-and-drop area (if one is specified). | `None`
`fileselect` | Signals that files have been selected. | `fileList`: An Array of files selected by the user, encapsulated in `Y.File`
`fileuploadstart` | Signals that the upload of multiple files has been started. | `file`: A reference to the instance of `Y.File` that dispatched the event. `originEvent`: The original event dispatched by `Y.File`
`mousedown` UploaderFlash | Signals that a mouse has been pressed over the `Select Files` button. | `None`
`mouseenter` UploaderFlash | Signals that a mouse has begun hovering over the `Select Files` button. | `None`
`mouseleave` UploaderFlash | Signals that a mouse has stopped hovering over the `Select Files` button. | `None`
`mouseup` UploaderFlash | Signals that a mouse has been released over the `Select Files` button. | `None`
`totaluploadprogress` | Reports on the total upload progress of the file list. | `bytesLoaded`: The number of bytes of the file list that has been uploaded. `bytesTotal`: The total number of bytes in the file list. `percentLoaded`: The fraction of the file list that has been uploaded, out of 100.
`uploadcomplete` | Signals that a single file upload has been completed. | `originEvent`: The original event dispatched by the instance of `Y.File`. `file`: The pointer to the instance of `Y.File` that dispatched the event. `data`: The data returned by the server.
`uploaderror` | Signals that a error has occurred in a specific file's upload process. | `originEvent`: The original event dispatched by the Uploader. `file`: The pointer to the instance of `Y.File` that dispatched the event. `source`: Either 'io' or 'http'.UploaderFlash `message`: The message corresponding to the error. In case of HTTP errors contains the status code.UploaderFlash `status`: The status reported by the XMLHttpRequest object.UploaderHTML5 `statusText`: The status text reported by the XMLHttpRequest object.UploaderHTML5
`uploadprogress` | Reports on upload progress of a specific file. | `file`: The pointer to the instance of `Y.File` that dispatched the event. `bytesLoaded`: The number of bytes of the file that has been uploaded. `bytesTotal`: The total number of bytes in the file. `percentLoaded`: The fraction of the file that has been uploaded, out of 100. `originEvent`: The original event dispatched by the uploader transport.
`uploadstart` | Signals that an upload of multiple files has been started. | `None`

See the API documentation for UploaderHTML5 and UploaderFlash for a complete documentation of the Uploader events, methods, attributes, and properties.

### Backend Setup

#### Setting up the backend for Flash

Unless the server receiving the file uploads is located on the same domain as the SWF file that is dispatching the uploads, the receiving server must include a crossdomain.xml file allowing the server on which the SWF is located to make requests to it. Consider, for instance, the crossdomain.xml policy file on yahoo.com. It looks as follows:

    <cross-domain-policy>
    <allow-access-from domain="*.yahoo.com" secure="false"/>
    </cross-domain-policy>

The `allow-access-from` parameter specifies which domains hosting SWFs can access yahoo.com: in this case, only subdomains of yahoo.com are allowed to do so. Note, for instance, that CNN.com's list is considerably larger.

If you are planning on using the CDN-hosted Uploader SWF, your crossdomain.xml file might look something like this:

    <cross-domain-policy>
    <allow-access-from domain="yui.yahooapis.com" secure="false"/>
    </cross-domain-policy>

#### Setting up the backend for HTML5

The security policy for XMLHttpRequest Level 2 cross-domain requests is a little bit trickier. Instead of using separate files, XHR2 uses server-supplied headers to determine whether a request can be made. Before the regular POST request, XHR submits a preflight OPTIONS request with an `Origin` parameter. In response, it expects a `Access-Control-Allow-Origin` header with a wildcard or a URL matching the `Origin` parameter it sent. This header can be set either through the web server you are using, or directly by the script output. For instance, here is a PHP example that replies to the OPTIONS requests with a header allowing all origins:

    if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
     header('Access-Control-Allow-Origin: *');
     exit;
    }

Note that the actual response must also contain the `Access-Control-Allow-Origin` header.

To learn more about XHR2 cross-domain requests, read this helpful tutorial on html5rocks.com.