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:
- Multiple file selection in a single "Open File" dialog.
- Dragging-and-dropping files into the browser (when used in HTML5 mode).
- Automatic upload queue management with fine-grained control.
- Upload progress tracking, both on a per-file and a per-queue basis.
- A range of available file metadata: filename, size, date created, and date modified.
- A set of events dispatched on various aspects of the file upload process: file selection, upload progress, upload completion, data return, and upload errors.
- Inclusion of additional data in the file upload POST request, on a file-by-file basis.
- 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.8.0/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 tohidden
, ordisplay
set tonone
, 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: "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 |
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:
|
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. |
|
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. |
|
uploadcomplete |
Signals that a single file upload has been completed. |
|
uploaderror |
Signals that a error has occurred in a specific file's upload process. |
|
uploadprogress |
Reports on upload progress of a specific file. |
|
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.