API Docs for: 3.8.0
Show:

File: uploader/js/uploader-html5.js

  1. /**
  2. * This module provides a UI for file selection and multiple file upload capability using
  3. * HTML5 XMLHTTPRequest Level 2 as a transport engine.
  4. * The supported features include: automatic upload queue management, upload progress
  5. * tracking, drag-and-drop support, server response retrieval and error reporting.
  6. *
  7. * @module uploader-html5
  8. */

  9. // Shorthands for the external modules
  10. var  substitute  = Y.Lang.sub,
  11.      UploaderQueue = Y.Uploader.Queue;

  12. /**
  13. * This module provides a UI for file selection and multiple file upload capability using
  14. * HTML5 XMLHTTPRequest Level 2 as a transport engine.
  15. * @class UploaderHTML5
  16. * @extends Widget
  17. * @constructor
  18. */
  19. function UploaderHTML5() {
  20.     UploaderHTML5.superclass.constructor.apply ( this, arguments );
  21. }



  22. Y.UploaderHTML5 = Y.extend( UploaderHTML5, Y.Widget, {

  23.     /**
  24.     * Stored reference to the instance of the file input field used to
  25.     * initiate the file selection dialog.
  26.     *
  27.     * @property _fileInputField
  28.     * @type {Node}
  29.     * @protected
  30.     */
  31.     _fileInputField: null,

  32.     /**
  33.     * Stored reference to the click event binding of the `Select Files`
  34.     * button.
  35.     *
  36.     * @property _buttonBinding
  37.     * @type {EventHandle}
  38.     * @protected
  39.     */
  40.     _buttonBinding: null,

  41.     /**
  42.     * Stored reference to the instance of Uploader.Queue used to manage
  43.     * the upload process. This is a read-only property that only exists
  44.     * during an active upload process. Only one queue can be active at
  45.     * a time; if an upload start is attempted while a queue is active,
  46.     * it will be ignored.
  47.     *
  48.     * @property queue
  49.     * @type {Y.Uploader.Queue}
  50.     */
  51.     queue: null,

  52.     // Y.UploaderHTML5 prototype

  53.     /**
  54.     * Construction logic executed during UploaderHTML5 instantiation.
  55.     *
  56.     * @method initializer
  57.     * @protected
  58.     */
  59.     initializer : function () {

  60.         this._fileInputField = null;
  61.         this.queue = null;
  62.         this._buttonBinding = null;
  63.         this._fileList = [];

  64.         // Publish available events

  65.         /**
  66.         * Signals that files have been selected.
  67.         *
  68.         * @event fileselect
  69.         * @param event {Event} The event object for the `fileselect` with the
  70.         *                      following payload:
  71.         *  <dl>
  72.         *      <dt>fileList</dt>
  73.         *          <dd>An `Array` of files selected by the user, encapsulated
  74.         *              in Y.FileHTML5 objects.</dd>
  75.         *  </dl>
  76.         */
  77.         this.publish("fileselect");

  78.         /**
  79.         * Signals that an upload of multiple files has been started.
  80.         *
  81.         * @event uploadstart
  82.         * @param event {Event} The event object for the `uploadstart`.
  83.         */
  84.         this.publish("uploadstart");

  85.         /**
  86.         * Signals that an upload of a specific file has started.
  87.         *
  88.         * @event fileuploadstart
  89.         * @param event {Event} The event object for the `fileuploadstart` with the
  90.         *                      following payload:
  91.         *  <dl>
  92.         *      <dt>file</dt>
  93.         *          <dd>A reference to the Y.File that dispatched the event.</dd>
  94.         *      <dt>originEvent</dt>
  95.         *          <dd>The original event dispatched by Y.File.</dd>
  96.         *  </dl>
  97.         */
  98.         this.publish("fileuploadstart");

  99.         /**
  100.         * Reports on upload progress of a specific file.
  101.         *
  102.         * @event uploadprogress
  103.         * @param event {Event} The event object for the `uploadprogress` with the
  104.         *                      following payload:
  105.         *  <dl>
  106.         *      <dt>file</dt>
  107.         *          <dd>The pointer to the instance of `Y.File` that dispatched the event.</dd>
  108.         *      <dt>bytesLoaded</dt>
  109.         *          <dd>The number of bytes of the file that has been uploaded</dd>
  110.         *      <dt>bytesTotal</dt>
  111.         *          <dd>The total number of bytes in the file</dd>
  112.         *      <dt>percentLoaded</dt>
  113.         *          <dd>The fraction of the file that has been uploaded, out of 100</dd>
  114.         *      <dt>originEvent</dt>
  115.         *          <dd>The original event dispatched by the HTML5 uploader</dd>
  116.         *  </dl>
  117.         */
  118.         this.publish("uploadprogress");

  119.         /**
  120.         * Reports on the total upload progress of the file list.
  121.         *
  122.         * @event totaluploadprogress
  123.         * @param event {Event} The event object for the `totaluploadprogress` with the
  124.         *                      following payload:
  125.         *  <dl>
  126.         *      <dt>bytesLoaded</dt>
  127.         *          <dd>The number of bytes of the file list that has been uploaded</dd>
  128.         *      <dt>bytesTotal</dt>
  129.         *          <dd>The total number of bytes in the file list</dd>
  130.         *      <dt>percentLoaded</dt>
  131.         *          <dd>The fraction of the file list that has been uploaded, out of 100</dd>
  132.         *  </dl>
  133.         */
  134.         this.publish("totaluploadprogress");

  135.         /**
  136.         * Signals that a single file upload has been completed.
  137.         *
  138.         * @event uploadcomplete
  139.         * @param event {Event} The event object for the `uploadcomplete` with the
  140.         *                      following payload:
  141.         *  <dl>
  142.         *      <dt>file</dt>
  143.         *          <dd>The pointer to the instance of `Y.File` whose upload has been completed.</dd>
  144.         *      <dt>originEvent</dt>
  145.         *          <dd>The original event fired by the SWF Uploader</dd>
  146.         *      <dt>data</dt>
  147.         *          <dd>Data returned by the server.</dd>
  148.         *  </dl>
  149.         */
  150.         this.publish("uploadcomplete");

  151.         /**
  152.         * Signals that the upload process of the entire file list has been completed.
  153.         *
  154.         * @event alluploadscomplete
  155.         * @param event {Event} The event object for the `alluploadscomplete`.
  156.         */
  157.         this.publish("alluploadscomplete");

  158.         /**
  159.         * Signals that a error has occurred in a specific file's upload process.
  160.         *
  161.         * @event uploaderror
  162.         * @param event {Event} The event object for the `uploaderror` with the
  163.         *                      following payload:
  164.         *  <dl>
  165.         *      <dt>originEvent</dt>
  166.         *          <dd>The original error event fired by the HTML5 Uploader. </dd>
  167.         *      <dt>file</dt>
  168.         *          <dd>The pointer at the instance of Y.File that returned the error.</dd>
  169.         *      <dt>status</dt>
  170.         *          <dd>The status reported by the XMLHttpRequest object.</dd>
  171.         *      <dt>statusText</dt>
  172.         *          <dd>The statusText reported by the XMLHttpRequest object.</dd>
  173.         *  </dl>
  174.         */
  175.         this.publish("uploaderror");

  176.         /**
  177.         * Signals that a dragged object has entered into the uploader's associated drag-and-drop area.
  178.         *
  179.         * @event dragenter
  180.         * @param event {Event} The event object for the `dragenter`.
  181.         */
  182.         this.publish("dragenter");

  183.         /**
  184.         * Signals that an object has been dragged over the uploader's associated drag-and-drop area.
  185.         *
  186.         * @event dragover
  187.         * @param event {Event} The event object for the `dragover`.
  188.         */
  189.         this.publish("dragover");

  190.         /**
  191.         * Signals that an object has been dragged off of the uploader's associated drag-and-drop area.
  192.         *
  193.         * @event dragleave
  194.         * @param event {Event} The event object for the `dragleave`.
  195.         */
  196.         this.publish("dragleave");

  197.         /**
  198.         * Signals that an object has been dropped over the uploader's associated drag-and-drop area.
  199.         *
  200.         * @event drop
  201.         * @param event {Event} The event object for the `drop`.
  202.         */
  203.         this.publish("drop");

  204.     },

  205.     /**
  206.     * Create the DOM structure for the UploaderHTML5.
  207.     * UploaderHTML5's DOM structure consists of a "Select Files" button that can
  208.     * be replaced by the developer's widget of choice; and a hidden file input field
  209.     * that is used to instantiate the File Select dialog.
  210.     *
  211.     * @method renderUI
  212.     * @protected
  213.     */
  214.     renderUI : function () {
  215.         var contentBox = this.get('contentBox'),
  216.             selButton = this.get("selectFilesButton");

  217.         selButton.setStyles({width:"100%", height:"100%"});
  218.         contentBox.append(selButton);
  219.         this._fileInputField = Y.Node.create(UploaderHTML5.HTML5FILEFIELD_TEMPLATE);
  220.         contentBox.append(this._fileInputField);
  221.     },

  222.     /**
  223.     * Binds to the UploaderHTML5 UI and subscribes to the necessary events.
  224.     *
  225.     * @method bindUI
  226.     * @protected
  227.     */
  228.     bindUI : function () {

  229.         this._bindSelectButton();
  230.         this._setMultipleFiles();
  231.         this._setFileFilters();
  232.         this._bindDropArea();
  233.         this._triggerEnabled();

  234.         this.after("multipleFilesChange", this._setMultipleFiles, this);
  235.         this.after("fileFiltersChange", this._setFileFilters, this);
  236.         this.after("enabledChange", this._triggerEnabled, this);
  237.         this.after("selectFilesButtonChange", this._bindSelectButton, this);
  238.         this.after("dragAndDropAreaChange", this._bindDropArea, this);
  239.         this.after("tabIndexChange", function () {
  240.             this.get("selectFilesButton").set("tabIndex", this.get("tabIndex"));
  241.         }, this);
  242.         this._fileInputField.on("change", this._updateFileList, this);

  243.         this.get("selectFilesButton").set("tabIndex", this.get("tabIndex"));
  244.     },


  245.     /**
  246.     * Recreates the file field to null out the previous list of files and
  247.     * thus allow for an identical file list selection.
  248.     *
  249.     * @method _rebindFileField
  250.     * @protected
  251.     */
  252.     _rebindFileField : function () {
  253.         this._fileInputField.remove(true);
  254.         this._fileInputField = Y.Node.create(UploaderHTML5.HTML5FILEFIELD_TEMPLATE);
  255.         this.get("contentBox").append(this._fileInputField);
  256.         this._fileInputField.on("change", this._updateFileList, this);
  257.         this._setMultipleFiles();
  258.         this._setFileFilters();
  259.     },


  260.     /**
  261.     * Binds the specified drop area's drag and drop events to the
  262.     * uploader's custom handler.
  263.     *
  264.     * @method _bindDropArea
  265.     * @protected
  266.     */
  267.     _bindDropArea : function (event) {
  268.         var ev = event || {prevVal: null},
  269.             ddArea = this.get("dragAndDropArea");

  270.         if (ev.prevVal !== null) {
  271.             ev.prevVal.detach('drop', this._ddEventHandler);
  272.             ev.prevVal.detach('dragenter', this._ddEventHandler);
  273.             ev.prevVal.detach('dragover', this._ddEventHandler);
  274.             ev.prevVal.detach('dragleave', this._ddEventHandler);
  275.         }

  276.         if (ddArea !== null) {
  277.             ddArea.on('drop', this._ddEventHandler, this);
  278.             ddArea.on('dragenter', this._ddEventHandler, this);
  279.             ddArea.on('dragover', this._ddEventHandler, this);
  280.             ddArea.on('dragleave', this._ddEventHandler, this);
  281.         }
  282.     },

  283.     /**
  284.     * Binds the instantiation of the file select dialog to the current file select
  285.     * control.
  286.     *
  287.     * @method _bindSelectButton
  288.     * @protected
  289.     */
  290.     _bindSelectButton : function () {
  291.        this._buttonBinding = this.get("selectFilesButton").on("click", this.openFileSelectDialog, this);
  292.     },

  293.     /**
  294.     * Handles the drag and drop events from the uploader's specified drop
  295.     * area.
  296.     *
  297.     * @method _ddEventHandler
  298.     * @protected
  299.     */
  300.     _ddEventHandler : function (event) {


  301.         event.stopPropagation();
  302.         event.preventDefault();

  303.         if (Y.Array.indexOf(event._event.dataTransfer.types, 'Files') > -1) {
  304.             switch (event.type) {
  305.                 case "dragenter":
  306.                     this.fire("dragenter");
  307.                     break;
  308.                 case "dragover":
  309.                     this.fire("dragover");
  310.                     break;
  311.                 case "dragleave":
  312.                     this.fire("dragleave");
  313.                     break;
  314.                 case "drop":

  315.                     var newfiles = event._event.dataTransfer.files,
  316.                         parsedFiles = [],
  317.                         filterFunc = this.get("fileFilterFunction"),
  318.                         oldfiles;

  319.                     if (filterFunc) {
  320.                         Y.each(newfiles, function (value) {
  321.                             var newfile = new Y.FileHTML5(value);
  322.                             if (filterFunc(newfile)) {
  323.                                 parsedFiles.push(newfile);
  324.                             }
  325.                         });
  326.                     }
  327.                     else {
  328.                         Y.each(newfiles, function (value) {
  329.                             parsedFiles.push(new Y.FileHTML5(value));
  330.                         });
  331.                     }

  332.                     if (parsedFiles.length > 0) {
  333.                         oldfiles = this.get("fileList");
  334.                         this.set("fileList",
  335.                         this.get("appendNewFiles") ? oldfiles.concat(parsedFiles) : parsedFiles);
  336.                         this.fire("fileselect", {fileList: parsedFiles});
  337.                     }

  338.                     this.fire("drop");
  339.                     break;
  340.             }
  341.         }
  342.     },

  343.     /**
  344.     * Adds or removes a specified state CSS class to the underlying uploader button.
  345.     *
  346.     * @method _setButtonClass
  347.     * @protected
  348.     * @param state {String} The name of the state enumerated in `buttonClassNames` attribute
  349.     * from which to derive the needed class name.
  350.     * @param add {Boolean} A Boolean indicating whether to add or remove the class.
  351.     */
  352.     _setButtonClass : function (state, add) {
  353.         if (add) {
  354.             this.get("selectFilesButton").addClass(this.get("buttonClassNames")[state]);
  355.         }
  356.         else {
  357.             this.get("selectFilesButton").removeClass(this.get("buttonClassNames")[state]);
  358.         }
  359.     },

  360.     /**
  361.     * Syncs the state of the `multipleFiles` attribute between this class
  362.     * and the file input field.
  363.     *
  364.     * @method _setMultipleFiles
  365.     * @protected
  366.     */
  367.     _setMultipleFiles : function () {
  368.         if (this.get("multipleFiles") === true) {
  369.             this._fileInputField.set("multiple", "multiple");
  370.         }
  371.         else {
  372.             this._fileInputField.set("multiple", "");
  373.         }
  374.     },

  375.     /**
  376.     * Syncs the state of the `fileFilters` attribute between this class
  377.     * and the file input field.
  378.     *
  379.     * @method _setFileFilters
  380.     * @protected
  381.     */
  382.     _setFileFilters : function () {
  383.         if (this.get("fileFilters").length > 0) {
  384.             this._fileInputField.set("accept", this.get("fileFilters").join(","));
  385.         }
  386.         else {
  387.             this._fileInputField.set("accept", "");
  388.         }
  389.     },


  390.     /**
  391.     * Syncs the state of the `enabled` attribute between this class
  392.     * and the underlying button.
  393.     *
  394.     * @method _triggerEnabled
  395.     * @private
  396.     */
  397.     _triggerEnabled : function () {
  398.         if (this.get("enabled") && this._buttonBinding === null) {
  399.             this._bindSelectButton();
  400.             this._setButtonClass("disabled", false);
  401.             this.get("selectFilesButton").setAttribute("aria-disabled", "false");
  402.         }
  403.         else if (!this.get("enabled") && this._buttonBinding) {
  404.             this._buttonBinding.detach();
  405.             this._buttonBinding = null;
  406.             this._setButtonClass("disabled", true);
  407.             this.get("selectFilesButton").setAttribute("aria-disabled", "true");
  408.         }
  409.     },

  410.     /**
  411.     * Getter for the `fileList` attribute
  412.     *
  413.     * @method _getFileList
  414.     * @private
  415.     */
  416.     _getFileList : function () {
  417.         return this._fileList.concat();
  418.     },

  419.     /**
  420.     * Setter for the `fileList` attribute
  421.     *
  422.     * @method _setFileList
  423.     * @private
  424.     */
  425.     _setFileList : function (val) {
  426.         this._fileList = val.concat();
  427.         return this._fileList.concat();
  428.     },

  429.     /**
  430.     * Adjusts the content of the `fileList` based on the results of file selection
  431.     * and the `appendNewFiles` attribute. If the `appendNewFiles` attribute is true,
  432.     * then selected files are appended to the existing list; otherwise, the list is
  433.     * cleared and populated with the newly selected files.
  434.     *
  435.     * @method _updateFileList
  436.     * @param ev {Event} The file selection event received from the uploader.
  437.     * @protected
  438.     */
  439.     _updateFileList : function (ev) {
  440.         var newfiles = ev.target.getDOMNode().files,
  441.             parsedFiles = [],
  442.             filterFunc = this.get("fileFilterFunction"),
  443.             oldfiles;

  444.         if (filterFunc) {
  445.             Y.each(newfiles, function (value) {
  446.                 var newfile = new Y.FileHTML5(value);
  447.                 if (filterFunc(newfile)) {
  448.                     parsedFiles.push(newfile);
  449.                 }
  450.             });
  451.         }
  452.         else {
  453.             Y.each(newfiles, function (value) {
  454.                 parsedFiles.push(new Y.FileHTML5(value));
  455.             });
  456.         }

  457.         if (parsedFiles.length > 0) {
  458.             oldfiles = this.get("fileList");

  459.             this.set("fileList",
  460.                     this.get("appendNewFiles") ? oldfiles.concat(parsedFiles) : parsedFiles );

  461.             this.fire("fileselect", {fileList: parsedFiles});
  462.         }

  463.         this._rebindFileField();
  464.     },


  465.     /**
  466.     * Handles and retransmits events fired by `Y.File` and `Y.Uploader.Queue`.
  467.     *
  468.     * @method _uploadEventHandler
  469.     * @param event The event dispatched during the upload process.
  470.     * @protected
  471.     */
  472.     _uploadEventHandler : function (event) {

  473.         switch (event.type) {
  474.             case "file:uploadstart":
  475.                 this.fire("fileuploadstart", event);
  476.                 break;
  477.             case "file:uploadprogress":
  478.                 this.fire("uploadprogress", event);
  479.                 break;
  480.             case "uploaderqueue:totaluploadprogress":
  481.                 this.fire("totaluploadprogress", event);
  482.                 break;
  483.             case "file:uploadcomplete":
  484.                 this.fire("uploadcomplete", event);
  485.                 break;
  486.             case "uploaderqueue:alluploadscomplete":
  487.                 this.queue = null;
  488.                 this.fire("alluploadscomplete", event);
  489.                 break;
  490.             case "file:uploaderror": // overflow intentional
  491.             case "uploaderqueue:uploaderror":
  492.                 this.fire("uploaderror", event);
  493.                 break;
  494.             case "file:uploadcancel": // overflow intentional
  495.             case "uploaderqueue:uploadcancel":
  496.                 this.fire("uploadcancel", event);
  497.                 break;
  498.         }

  499.     },

  500.     /**
  501.     * Opens the File Selection dialog by simulating a click on the file input field.
  502.     *
  503.     * @method openFileSelectDialog
  504.     */
  505.     openFileSelectDialog : function () {
  506.         var fileDomNode = this._fileInputField.getDOMNode();
  507.         if (fileDomNode.click) {
  508.             fileDomNode.click();
  509.         }
  510.     },

  511.     /**
  512.     * Starts the upload of a specific file.
  513.     *
  514.     * @method upload
  515.     * @param file {Y.File} Reference to the instance of the file to be uploaded.
  516.     * @param url {String} The URL to upload the file to.
  517.     * @param postVars {Object} (optional) A set of key-value pairs to send as variables along with the file upload HTTP request.
  518.     *                          If not specified, the values from the attribute `postVarsPerFile` are used instead.
  519.     */
  520.     upload : function (file, url, postvars) {

  521.         var uploadURL = url || this.get("uploadURL"),
  522.             postVars = postvars || this.get("postVarsPerFile"),
  523.             fileId = file.get("id");

  524.         postVars = postVars.hasOwnProperty(fileId) ? postVars[fileId] : postVars;

  525.         if (file instanceof Y.FileHTML5) {

  526.             file.on("uploadstart", this._uploadEventHandler, this);
  527.             file.on("uploadprogress", this._uploadEventHandler, this);
  528.             file.on("uploadcomplete", this._uploadEventHandler, this);
  529.             file.on("uploaderror", this._uploadEventHandler, this);
  530.             file.on("uploadcancel", this._uploadEventHandler, this);

  531.             file.startUpload(uploadURL, postVars, this.get("fileFieldName"));
  532.         }
  533.     },

  534.    /**
  535.     * Starts the upload of all files on the file list, using an automated queue.
  536.     *
  537.     * @method uploadAll
  538.     * @param url {String} The URL to upload the files to.
  539.     * @param [postVars] {Object} A set of key-value pairs to send as variables along with the file upload HTTP request.
  540.     *                          If not specified, the values from the attribute `postVarsPerFile` are used instead.
  541.     */
  542.     uploadAll : function (url, postvars) {
  543.         this.uploadThese(this.get("fileList"), url, postvars);
  544.     },

  545.     /**
  546.     * Starts the upload of the files specified in the first argument, using an automated queue.
  547.     *
  548.     * @method uploadThese
  549.     * @param files {Array} The list of files to upload.
  550.     * @param url {String} The URL to upload the files to.
  551.     * @param [postVars] {Object} A set of key-value pairs to send as variables along with the file upload HTTP request.
  552.     *                          If not specified, the values from the attribute `postVarsPerFile` are used instead.
  553.     */
  554.     uploadThese : function (files, url, postvars) {
  555.         if (!this.queue) {
  556.             var uploadURL = url || this.get("uploadURL"),
  557.                 postVars = postvars || this.get("postVarsPerFile");

  558.             this.queue = new UploaderQueue({
  559.                 simUploads: this.get("simLimit"),
  560.                 errorAction: this.get("errorAction"),
  561.                 fileFieldName: this.get("fileFieldName"),
  562.                 fileList: files,
  563.                 uploadURL: uploadURL,
  564.                 perFileParameters: postVars,
  565.                 retryCount: this.get("retryCount"),
  566.                 uploadHeaders: this.get("uploadHeaders"),
  567.                 withCredentials: this.get("withCredentials")
  568.             });

  569.             this.queue.on("uploadstart", this._uploadEventHandler, this);
  570.             this.queue.on("uploadprogress", this._uploadEventHandler, this);
  571.             this.queue.on("totaluploadprogress", this._uploadEventHandler, this);
  572.             this.queue.on("uploadcomplete", this._uploadEventHandler, this);
  573.             this.queue.on("alluploadscomplete", this._uploadEventHandler, this);
  574.             this.queue.on("uploadcancel", this._uploadEventHandler, this);
  575.             this.queue.on("uploaderror", this._uploadEventHandler, this);
  576.             this.queue.startUpload();

  577.             this.fire("uploadstart");
  578.        }
  579.        else if (this.queue._currentState === UploaderQueue.UPLOADING) {
  580.             this.queue.set("perFileParameters", this.get("postVarsPerFile"));
  581.             Y.each(files, function (file) {
  582.                 this.queue.addToQueueBottom(file);
  583.             }, this);
  584.        }
  585.     }
  586. }, {

  587.     /**
  588.     * The template for the hidden file input field container. The file input field will only
  589.     * accept clicks if its visibility is set to hidden (and will not if it's `display` value
  590.     * is set to `none`)
  591.     *
  592.     * @property HTML5FILEFIELD_TEMPLATE
  593.     * @type {String}
  594.     * @static
  595.     */
  596.     HTML5FILEFIELD_TEMPLATE: "<input type='file' style='visibility:hidden; width:0px; height: 0px;'>",

  597.     /**
  598.     * The template for the "Select Files" button.
  599.     *
  600.     * @property SELECT_FILES_BUTTON
  601.     * @type {HTML}
  602.     * @static
  603.     * @default '<button type="button" class="yui3-button" role="button" aria-label="{selectButtonLabel}"
  604.     *           tabindex="{tabIndex}">{selectButtonLabel}</button>'
  605.     */
  606.     SELECT_FILES_BUTTON: '<button type="button" class="yui3-button" role="button" aria-label="{selectButtonLabel}" ' +
  607.                          'tabindex="{tabIndex}">{selectButtonLabel}</button>',

  608.     /**
  609.     * The static property reflecting the type of uploader that `Y.Uploader`
  610.     * aliases. The UploaderHTML5 value is `"html5"`.
  611.     *
  612.     * @property TYPE
  613.     * @type {String}
  614.     * @static
  615.     */
  616.     TYPE: "html5",

  617.     /**
  618.     * The identity of the widget.
  619.     *
  620.     * @property NAME
  621.     * @type String
  622.     * @default 'uploader'
  623.     * @readOnly
  624.     * @protected
  625.     * @static
  626.     */
  627.     NAME: "uploader",

  628.     /**
  629.     * Static property used to define the default attribute configuration of
  630.     * the Widget.
  631.     *
  632.     * @property ATTRS
  633.     * @type {Object}
  634.     * @protected
  635.     * @static
  636.     */
  637.     ATTRS: {

  638.         /**
  639.         * A Boolean indicating whether newly selected files should be appended
  640.         * to the existing file list, or whether they should replace it.
  641.         *
  642.         * @attribute appendNewFiles
  643.         * @type {Boolean}
  644.         * @default true
  645.         */
  646.         appendNewFiles : {
  647.             value: true
  648.         },

  649.         /**
  650.         * The names of CSS classes that correspond to different button states
  651.         * of the "Select Files" control. These classes are assigned to the
  652.         * "Select Files" control based on the configuration of the uploader.
  653.         * Currently, the only class name used is that corresponding to the
  654.         * `disabled` state of the uploader. Other button states should be managed
  655.         * directly via CSS selectors.
  656.         * <ul>
  657.         *   <li> <strong>`disabled`</strong>: the class corresponding to the disabled state
  658.         *      of the "Select Files" button.</li>
  659.         * </ul>
  660.         * @attribute buttonClassNames
  661.         * @type {Object}
  662.         * @default {
  663.         *            disabled: "yui3-button-disabled"
  664.         *          }
  665.         */
  666.         buttonClassNames: {
  667.             value: {
  668.                 "hover": "yui3-button-hover",
  669.                 "active": "yui3-button-active",
  670.                 "disabled": "yui3-button-disabled",
  671.                 "focus": "yui3-button-selected"
  672.             }
  673.         },

  674.         /**
  675.         * The node that serves as the drop target for files.
  676.         *
  677.         * @attribute dragAndDropArea
  678.         * @type {Node}
  679.         * @default null
  680.         */
  681.         dragAndDropArea: {
  682.             value: null,
  683.             setter: function (val) {
  684.                 return Y.one(val);
  685.             }
  686.         },

  687.         /**
  688.         * A Boolean indicating whether the uploader is enabled or disabled for user input.
  689.         *
  690.         * @attribute enabled
  691.         * @type {Boolean}
  692.         * @default true
  693.         */
  694.         enabled : {
  695.             value: true
  696.         },

  697.         /**
  698.         * The action  performed when an upload error occurs for a specific file being uploaded.
  699.         * The possible values are:
  700.         * <ul>
  701.         *   <li> <strong>`UploaderQueue.CONTINUE`</strong>: the error is ignored and the upload process is continued.</li>
  702.         *   <li> <strong>`UploaderQueue.STOP`</strong>: the upload process is stopped as soon as any other parallel file
  703.         *     uploads are finished.</li>
  704.         *   <li> <strong>`UploaderQueue.RESTART_ASAP`</strong>: the file is added back to the front of the queue.</li>
  705.         *   <li> <strong>`UploaderQueue.RESTART_AFTER`</strong>: the file is added to the back of the queue.</li>
  706.         * </ul>
  707.         * @attribute errorAction
  708.         * @type {String}
  709.         * @default UploaderQueue.CONTINUE
  710.         */
  711.         errorAction: {
  712.             value: "continue",
  713.             validator: function (val) {
  714.                 return (
  715.                     val === UploaderQueue.CONTINUE ||
  716.                     val === UploaderQueue.STOP ||
  717.                     val === UploaderQueue.RESTART_ASAP ||
  718.                     val === UploaderQueue.RESTART_AFTER
  719.                 );
  720.             }
  721.         },

  722.         /**
  723.         * An array indicating what fileFilters should be applied to the file
  724.         * selection dialog. Each element in the array should be a string
  725.         * indicating the Media (MIME) type for the files that should be supported
  726.         * for selection. The Media type strings should be properly formatted
  727.         * or this parameter will be ignored. Examples of valid strings include:
  728.         * "audio/*", "video/*", "application/pdf", etc. More information
  729.         * on valid Media type strings is available here:
  730.         * http://www.iana.org/assignments/media-types/index.html
  731.         * @attribute fileFilters
  732.         * @type {Array}
  733.         * @default []
  734.         */
  735.         fileFilters: {
  736.             value: []
  737.         },

  738.         /**
  739.         * A filtering function that is applied to every file selected by the user.
  740.         * The function receives the `Y.File` object and must return a Boolean value.
  741.         * If a `false` value is returned, the file in question is not added to the
  742.         * list of files to be uploaded.
  743.         * Use this function to put limits on file sizes or check the file names for
  744.         * correct extension, but make sure that a server-side check is also performed,
  745.         * since any client-side restrictions are only advisory and can be circumvented.
  746.         *
  747.         * @attribute fileFilterFunction
  748.         * @type {Function}
  749.         * @default null
  750.         */
  751.         fileFilterFunction: {
  752.             value: null
  753.         },

  754.         /**
  755.         * A String specifying what should be the POST field name for the file
  756.         * content in the upload request.
  757.         *
  758.         * @attribute fileFieldName
  759.         * @type {String}
  760.         * @default Filedata
  761.         */
  762.         fileFieldName: {
  763.             value: "Filedata"
  764.         },

  765.         /**
  766.         * The array of files to be uploaded. All elements in the array
  767.         * must be instances of `Y.File` and be instantiated with an instance
  768.         * of native JavaScript File() class.
  769.         *
  770.         * @attribute fileList
  771.         * @type {Array}
  772.         * @default []
  773.         */
  774.         fileList: {
  775.             value: [],
  776.             getter: "_getFileList",
  777.             setter: "_setFileList"
  778.         },

  779.         /**
  780.         * A Boolean indicating whether multiple file selection is enabled.
  781.         *
  782.         * @attribute multipleFiles
  783.         * @type {Boolean}
  784.         * @default false
  785.         */
  786.         multipleFiles: {
  787.             value: false
  788.         },

  789.         /**
  790.         * An object, keyed by `fileId`, containing sets of key-value pairs
  791.         * that should be passed as POST variables along with each corresponding
  792.         * file. This attribute is only used if no POST variables are specifed
  793.         * in the upload method call.
  794.         *
  795.         * @attribute postVarsPerFile
  796.         * @type {Object}
  797.         * @default {}
  798.         */
  799.         postVarsPerFile: {
  800.             value: {}
  801.         },

  802.         /**
  803.         * The label for the "Select Files" widget. This is the value that replaces the
  804.         * `{selectButtonLabel}` token in the `SELECT_FILES_BUTTON` template.
  805.         *
  806.         * @attribute selectButtonLabel
  807.         * @type {String}
  808.         * @default "Select Files"
  809.         */
  810.         selectButtonLabel: {
  811.             value: "Select Files"
  812.         },

  813.         /**
  814.         * The widget that serves as the "Select Files control for the file uploader
  815.         *
  816.         *
  817.         * @attribute selectFilesButton
  818.         * @type {Node | Widget}
  819.         * @default A standard HTML button with YUI CSS Button skin.
  820.         */
  821.         selectFilesButton : {
  822.             valueFn: function () {
  823.                 return Y.Node.create(substitute(Y.UploaderHTML5.SELECT_FILES_BUTTON, {
  824.                     selectButtonLabel: this.get("selectButtonLabel"),
  825.                     tabIndex: this.get("tabIndex")
  826.                 }));
  827.             }
  828.         },

  829.         /**
  830.         * The number of files that can be uploaded
  831.         * simultaneously if the automatic queue management
  832.         * is used. This value can be in the range between 2
  833.         * and 5.
  834.         *
  835.         * @attribute simLimit
  836.         * @type {Number}
  837.         * @default 2
  838.         */
  839.         simLimit: {
  840.             value: 2,
  841.             validator: function (val) {
  842.                 return (val >= 1 && val <= 5);
  843.             }
  844.         },

  845.         /**
  846.         * The URL to which file upload requested are POSTed. Only used if a different url is not passed to the upload method call.
  847.         *
  848.         * @attribute uploadURL
  849.         * @type {String}
  850.         * @default ""
  851.         */
  852.         uploadURL: {
  853.             value: ""
  854.         },

  855.         /**
  856.         * Additional HTTP headers that should be included
  857.         * in the upload request.
  858.         *
  859.         *
  860.         * @attribute uploadHeaders
  861.         * @type {Object}
  862.         * @default {}
  863.         */
  864.         uploadHeaders: {
  865.             value: {}
  866.         },

  867.         /**
  868.         * A Boolean that specifies whether the file should be
  869.         * uploaded with the appropriate user credentials for the
  870.         * domain.
  871.         *
  872.         * @attribute withCredentials
  873.         * @type {Boolean}
  874.         * @default true
  875.         */
  876.         withCredentials: {
  877.             value: true
  878.         },

  879.         /**
  880.         * The number of times to try re-uploading a file that failed to upload before
  881.         * cancelling its upload.
  882.         *
  883.         * @attribute retryCount
  884.         * @type {Number}
  885.         * @default 3
  886.         */
  887.         retryCount: {
  888.             value: 3
  889.         }
  890.     }
  891. });

  892. Y.UploaderHTML5.Queue = UploaderQueue;


  893.