Merge branch 'MDL-32509' of git://github.com/danpoltawski/moodle
[moodle.git] / lib / yui / 3.5.0 / build / uploader-flash / uploader-flash-debug.js
blob7915bb04b8de72f9b9f70827d215dd059bed47dc
1 /*
2 YUI 3.5.0 (build 5089)
3 Copyright 2012 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
6 */
7 YUI.add('uploader-flash', function(Y) {
10     /**
11      * This module provides a UI for file selection and multiple file upload capability using
12      * Flash as a transport engine.
13      * The supported features include: automatic upload queue management, upload progress
14      * tracking, file filtering, server response retrieval and error reporting.
15      *
16      * @module uploader-flash
17      */     
19 // Shorthands for external modules
20 var  substitute            = Y.substitute,
21      UploaderQueue         = Y.Uploader.Queue,
22      getCN                 = Y.ClassNameManager.getClassName,
23      UPLOADER              = 'uploader',
24      SELECT_FILES          = getCN(UPLOADER, 'selectfiles-button');
27     /**
28      * This module provides a UI for file selection and multiple file upload capability
29      * using Flash as a transport engine.
30      * @class UploaderFlash
31      * @extends Widget
32      * @constructor
33      * @param {Object} config Configuration object.
34      */
36 function UploaderFlash(config) {
37   UploaderFlash.superclass.constructor.apply ( this, arguments );
42 Y.UploaderFlash = Y.extend(UploaderFlash, Y.Widget, {
44   /**
45    * Stored value of the current button state (based on 
46    * mouse events dispatched by the Flash player)
47    * @property _buttonState
48    * @type {String}
49    * @protected
50    */
51   _buttonState: "up",
53   /**
54    * Stored value of the current button focus state (based 
55    * on keyboard and mouse events).
56    * @property _buttonFocus
57    * @type {Boolean}
58    * @protected
59    */
60   _buttonFocus: false,
62   /**
63    * Stored value of the unique id for the container that holds the 
64    * Flash uploader.
65    *
66    * @property _swfContainerId
67    * @type {String}
68    * @protected
69    */
70   _swfContainerId: null,
72   /**
73    * Stored reference to the instance of SWF used to host the
74    * Flash uploader.
75    *
76    * @property _swfReference
77    * @type {SWF}
78    * @protected
79    */
80   _swfReference: null,
82   /**
83    * Stored reference to the instance of Uploader.Queue used to manage
84    * the upload process. This is a read-only property that only exists
85    * during an active upload process. Only one queue can be active at
86    * a time; if an upload start is attempted while a queue is active,
87    * it will be ignored.
88    *
89    * @property queue
90    * @type {Y.Uploader.Queue}
91    */
92    queue: null,
94   /**
95    * Stored event bindings for keyboard navigation to and from the uploader.
96    *
97    * @property _tabElementBindings
98    * @type {Object}
99    * @protected
100    */
101   _tabElementBindings: null,
105  * Construction logic executed during UploaderFlash instantiation.
107  * @method initializer
108  * @protected
109  */
110   initializer : function () {
112     // Assign protected variable values
113     this._swfContainerId = Y.guid("uploader");
114     this._swfReference = null;
115     this.queue = null;
116     this._buttonState = "up";
117     this._buttonFocus = null;
118     this._tabElementBindings = null;
120     // Publish available events
122    /**
123     * Signals that files have been selected. 
124     *
125     * @event fileselect
126     * @param event {Event} The event object for the `fileselect` with the
127     *                      following payload:
128     *  <dl>
129     *      <dt>fileList</dt>
130     *          <dd>An `Array` of files selected by the user, encapsulated
131     *              in Y.FileFlash objects.</dd>
132     *  </dl>
133     */
134     this.publish("fileselect");
136    /**
137     * Signals that an upload of multiple files has been started. 
138     *
139     * @event uploadstart
140     * @param event {Event} The event object for the `uploadstart`.
141     */
142     this.publish("uploadstart");
144    /**
145     * Signals that an upload of a specific file has started. 
146     *
147     * @event fileuploadstart
148     * @param event {Event} The event object for the `fileuploadstart` with the
149     *                      following payload:
150     *  <dl>
151     *      <dt>file</dt>
152     *          <dd>A reference to the Y.File that dispatched the event.</dd>
153     *      <dt>originEvent</dt>
154     *          <dd>The original event dispatched by Y.File.</dd>
155     *  </dl>
156     */
157     this.publish("fileuploadstart");
159    /**
160     * Reports on upload progress of a specific file. 
161     *
162     * @event uploadprogress
163     * @param event {Event} The event object for the `uploadprogress` with the
164     *                      following payload:
165     *  <dl>
166     *      <dt>bytesLoaded</dt>
167     *          <dd>The number of bytes of the file that has been uploaded</dd>
168     *      <dt>bytesTotal</dt>
169     *          <dd>The total number of bytes in the file</dd>
170     *      <dt>percentLoaded</dt>
171     *          <dd>The fraction of the file that has been uploaded, out of 100</dd>
172     *      <dt>originEvent</dt>
173     *          <dd>The original event dispatched by the SWF uploader</dd>
174     *  </dl>
175     */
176     this.publish("uploadprogress");
178    /**
179     * Reports on the total upload progress of the file list. 
180     *
181     * @event totaluploadprogress
182     * @param event {Event} The event object for the `totaluploadprogress` with the
183     *                      following payload:
184     *  <dl>
185     *      <dt>bytesLoaded</dt>
186     *          <dd>The number of bytes of the file list that has been uploaded</dd>
187     *      <dt>bytesTotal</dt>
188     *          <dd>The total number of bytes in the file list</dd>
189     *      <dt>percentLoaded</dt>
190     *          <dd>The fraction of the file list that has been uploaded, out of 100</dd>
191     *  </dl>
192     */
193     this.publish("totaluploadprogress");
195    /**
196     * Signals that a single file upload has been completed. 
197     *
198     * @event uploadcomplete
199     * @param event {Event} The event object for the `uploadcomplete` with the
200     *                      following payload:
201     *  <dl>
202     *      <dt>file</dt>
203     *          <dd>The pointer to the instance of `Y.File` whose upload has been completed.</dd>
204     *      <dt>originEvent</dt>
205     *          <dd>The original event fired by the SWF Uploader</dd>
206     *      <dt>data</dt>
207     *          <dd>Data returned by the server.</dd>
208     *  </dl>
209     */
210     this.publish("uploadcomplete");
212    /**
213     * Signals that the upload process of the entire file list has been completed. 
214     *
215     * @event alluploadscomplete
216     * @param event {Event} The event object for the `alluploadscomplete`.
217     */
218     this.publish("alluploadscomplete");
220    /**
221     * Signals that a error has occurred in a specific file's upload process. 
222     *
223     * @event uploaderror
224     * @param event {Event} The event object for the `uploaderror` with the
225     *                      following payload:
226     *  <dl>
227     *      <dt>originEvent</dt>
228     *          <dd>The original error event fired by the SWF Uploader. </dd>
229     *      <dt>file</dt>
230     *          <dd>The pointer at the instance of Y.FileFlash that returned the error.</dd>
231     *      <dt>source</dt>
232     *          <dd>The source of the upload error, either "io" or "http"</dd>       
233     *      <dt>message</dt>
234     *          <dd>The message that accompanied the error. Corresponds to the text of
235     *              the error in cases where source is "io", and to the HTTP status for
236                    cases where source is "http".</dd>     
237     *  </dl>
238     */
239     this.publish("uploaderror");
241    /**
242     * Signals that a mouse has begun hovering over the `Select Files` button. 
243     *
244     * @event mouseenter
245     * @param event {Event} The event object for the `mouseenter` event.
246     */
247     this.publish("mouseenter");
249    /**
250     * Signals that a mouse has stopped hovering over the `Select Files` button. 
251     *
252     * @event mouseleave
253     * @param event {Event} The event object for the `mouseleave` event.
254     */
255     this.publish("mouseleave");
257    /**
258     * Signals that a mouse button has been pressed over the `Select Files` button. 
259     *
260     * @event mousedown
261     * @param event {Event} The event object for the `mousedown` event.
262     */
263     this.publish("mousedown");
265    /**
266     * Signals that a mouse button has been released over the `Select Files` button. 
267     *
268     * @event mouseup
269     * @param event {Event} The event object for the `mouseup` event.
270     */
271     this.publish("mouseup");
273    /**
274     * Signals that a mouse has been clicked over the `Select Files` button. 
275     *
276     * @event click
277     * @param event {Event} The event object for the `click` event.
278     */
279     this.publish("click");
280   },
282   /**
283    * Creates the DOM structure for the UploaderFlash.
284    * UploaderFlash's DOM structure consists of two layers: the base "Select Files"
285    * button that can be replaced by the developer's widget of choice; and a transparent
286    * Flash overlay positoned above the button that captures all input events.
287    * The `position` style attribute of the `boundingBox` of the `Uploader` widget
288    * is forced to be `relative`, in order to accommodate the Flash player overlay
289    * (which is `position`ed `absolute`ly).
290    *
291    * @method renderUI
292    * @protected
293    */
294   renderUI : function () {
295      var boundingBox = this.get("boundingBox"),
296          contentBox = this.get('contentBox'),
297          selFilesButton = this.get("selectFilesButton");
299      boundingBox.setStyle("position", "relative");
300      selFilesButton.setStyles({width: "100%", height: "100%"});
301      contentBox.append(selFilesButton);
302      contentBox.append(Y.Node.create(substitute(UploaderFlash.FLASH_CONTAINER, 
303                                               {swfContainerId: this._swfContainerId})));
304      var flashContainer = Y.one("#" + this._swfContainerId);
305      var params = {version: "10.0.45",
306                      fixedAttributes: {wmode: "transparent", 
307                                        allowScriptAccess:"always", 
308                                        allowNetworking:"all", 
309                                        scale: "noscale"
310                                       }
311                     };
312      this._swfReference = new Y.SWF(flashContainer, this.get("swfURL"), params);
313   },
315   /**
316    * Binds handlers to the UploaderFlash UI events and propagates attribute
317    * values to the Flash player.
318    * The propagation of initial values is set to occur once the Flash player 
319    * instance is ready (as indicated by the `swfReady` event.)
320    *
321    * @method bindUI
322    * @protected
323    */
324   bindUI : function () {
326     this._swfReference.on("swfReady", function () {
327       this._setMultipleFiles();
328       this._setFileFilters();
329       this._triggerEnabled();
330       this.after("multipleFilesChange", this._setMultipleFiles, this);
331       this.after("fileFiltersChange", this._setFileFilters, this);
332       this.after("enabledChange", this._triggerEnabled, this);
333     }, this);
334         
335     this._swfReference.on("fileselect", this._updateFileList, this);
337         this.after("tabElementsChange", this._attachTabElements);
338         this._attachTabElements();
340         // this._swfReference.on("trace", function (ev) {console.log(ev.message);});
342         this._swfReference.on("mouseenter", function () {
343             this.fire("mouseenter");
344             this._setButtonClass("hover", true);
345             if (this._buttonState == "down") {
346                 this._setButtonClass("active", true);
347             }
348         }, this);
349         this._swfReference.on("mouseleave", function () {
350             this.fire("mouseleave");
351             this._setButtonClass("hover", false);
352             this._setButtonClass("active", false);
353             
354         }, this);
355         this._swfReference.on("mousedown", function () {
356             this.fire("mousedown");
357             this._buttonState = "down";
358             this._setButtonClass("active", true);
359         }, this);
360         this._swfReference.on("mouseup", function () {
361             this.fire("mouseup");
362             this._buttonState = "up";
363             this._setButtonClass("active", false);
364         }, this);
365         this._swfReference.on("click", function () {
366             this.fire("click");
367             this._buttonFocus = true;
368             this._setButtonClass("focus", true);
369             Y.one("body").focus();
370             this._swfReference._swf.focus();
371         }, this);
372   },
374   /**
375    * Attaches keyboard bindings to enabling tabbing to and from the instance of the Flash
376    * player in the Uploader widget. If the previous and next elements are specified, the
377    * keyboard bindings enable the user to tab from the `tabElements["from"]` node to the 
378    * Flash-powered "Select Files" button, and to the `tabElements["to"]` node. 
379    *
380    * @method _attachTabElements
381    * @protected
382    * @param ev {Event} Optional event payload if called as a `tabElementsChange` handler.
383    */
384   _attachTabElements : function (ev) {
385       if (this.get("tabElements") !== null && this.get("tabElements").from !== null && this.get("tabElements").to !== null) {
387         if (this._tabElementBindings !== null) {
388           this._tabElementBindings.from.detach();
389           this._tabElementBindings.to.detach();
390           this._tabElementBindings.tabback.detach();
391           this._tabElementBindings.tabforward.detach();
392           this._tabElementBindings.focus.detach();
393           this._tabElementBindings.blur.detach();
394         }
395         else {
396           this._tabElementBindings = {};
397         }
399           var fromElement = Y.one(this.get("tabElements").from);
400           var toElement = Y.one(this.get("tabElements").to);
403           this._tabElementBindings.from = fromElement.on("keydown", function (ev) { 
404                                                     if (ev.keyCode == 9 && !ev.shiftKey) {
405                                                         ev.preventDefault();
406                                                         this._swfReference._swf.setAttribute("tabindex", 0); 
407                                                         this._swfReference._swf.setAttribute("role", "button");
408                                                         this._swfReference._swf.setAttribute("aria-label", this.get("selectButtonLabel"));
409                                                         this._swfReference._swf.focus();
410                                                     }
411                                                   }, this);
412           this._tabElementBindings.to = toElement.on("keydown", function (ev) { 
413                                                     if (ev.keyCode == 9 && ev.shiftKey) {
414                                                         ev.preventDefault();
415                                                         this._swfReference._swf.setAttribute("tabindex", 0); 
416                                                         this._swfReference._swf.setAttribute("role", "button");
417                                                         this._swfReference._swf.setAttribute("aria-label", this.get("selectButtonLabel"));
418                                                         this._swfReference._swf.focus();
419                                                     }
420                                                   }, this);
421           this._tabElementBindings.tabback = this._swfReference.on("tabback", function (ev) {this._swfReference._swf.blur(); setTimeout(function () {fromElement.focus();}, 30);}, this);
422           this._tabElementBindings.tabforward = this._swfReference.on("tabforward", function (ev) {this._swfReference._swf.blur(); setTimeout(function () {toElement.focus();}, 30);}, this);
424           this._tabElementBindings.focus = this._swfReference._swf.on("focus", function (ev) {this._buttonFocus = true; this._setButtonClass("focus", true);}, this);
425           this._tabElementBindings.blur = this._swfReference._swf.on("blur", function (ev) {this._buttonFocus = false; this._setButtonClass("focus", false);}, this);
426       }
427       else if (this._tabElementBindings !== null) {
428           this._tabElementBindings.from.detach();
429           this._tabElementBindings.to.detach();
430           this._tabElementBindings.tabback.detach();
431           this._tabElementBindings.tabforward.detach();
432           this._tabElementBindings.focus.detach();
433           this._tabElementBindings.blur.detach();
434       }
435   },
438   /**
439    * Adds or removes a specified state CSS class to the underlying uploader button. 
440    *
441    * @method _setButtonClass
442    * @protected
443    * @param state {String} The name of the state enumerated in `buttonClassNames` attribute
444    * from which to derive the needed class name.
445    * @param add {Boolean} A Boolean indicating whether to add or remove the class.
446    */
447   _setButtonClass : function (state, add) {
448       if (add) {
449           this.get("selectFilesButton").addClass(this.get("buttonClassNames")[state]);
450       }
451       else {
452           this.get("selectFilesButton").removeClass(this.get("buttonClassNames")[state]);
453       }
454   },
457   /**
458    * Syncs the state of the `fileFilters` attribute between the instance of UploaderFlash
459    * and the Flash player.
460    * 
461    * @method _setFileFilters
462    * @private
463    */
464   _setFileFilters : function () {
465           if (this._swfReference && this.get("fileFilters") !== null) {
466             this._swfReference.callSWF("setFileFilters", [this.get("fileFilters")]);
467           } 
469   },
473   /**
474    * Syncs the state of the `multipleFiles` attribute between this class
475    * and the Flash uploader.
476    * 
477    * @method _setMultipleFiles
478    * @private
479    */
480   _setMultipleFiles : function () {
481         if (this._swfReference) {
482       this._swfReference.callSWF("setAllowMultipleFiles", [this.get("multipleFiles")]);
483     }
484   },
486   /**
487    * Syncs the state of the `enabled` attribute between this class
488    * and the Flash uploader.
489    * 
490    * @method _triggerEnabled
491    * @private
492    */
493   _triggerEnabled : function () {
494       if (this.get("enabled")) {
495         this._swfReference.callSWF("enable");
496         this._swfReference._swf.setAttribute("aria-disabled", "false");
497         this._setButtonClass("disabled", false);
498       }
499       else {
500         this._swfReference.callSWF("disable");
501         this._swfReference._swf.setAttribute("aria-disabled", "true");
502         this._setButtonClass("disabled", true);
503       }
504   },
506   /**
507    * Adjusts the content of the `fileList` based on the results of file selection
508    * and the `appendNewFiles` attribute. If the `appendNewFiles` attribute is true,
509    * then selected files are appended to the existing list; otherwise, the list is
510    * cleared and populated with the newly selected files.
511    * 
512    * @method _updateFileList
513    * @param ev {Event} The file selection event received from the uploader.
514    * @private
515    */
516   _updateFileList : function (ev) {
517      
518      Y.one("body").focus();
519      this._swfReference._swf.focus();
522      var newfiles = ev.fileList,
523          fileConfObjects = [],
524          parsedFiles = [],
525          swfRef = this._swfReference;
527      Y.each(newfiles, function (value) {
528        var newFileConf = {};
529        newFileConf.id = value.fileId;
530        newFileConf.name = value.fileReference.name;
531        newFileConf.size = value.fileReference.size;
532        newFileConf.type = value.fileReference.type;
533        newFileConf.dateCreated = value.fileReference.creationDate;
534        newFileConf.dateModified = value.fileReference.modificationDate;
535        newFileConf.uploader = swfRef;
537        fileConfObjects.push(newFileConf);
538      });
540      Y.each(fileConfObjects, function (value) {
541        parsedFiles.push(new Y.FileFlash(value));
542      });
544      this.fire("fileselect", {fileList: parsedFiles});
546      var oldfiles = this.get("fileList");
548    this.set("fileList", 
549              this.get("appendNewFiles") ? oldfiles.concat(parsedFiles) : parsedFiles );
551   },
555   /**
556    * Handles and retransmits events fired by `Y.FileFlash` and `Y.Uploader.Queue`.
557    * 
558    * @method _uploadEventHandler
559    * @param event The event dispatched during the upload process.
560    * @private
561    */
562   _uploadEventHandler : function (event) {
563   
564     switch (event.type) {
565                 case "file:uploadstart":
566                    this.fire("fileuploadstart", event);
567                 break;
568                 case "file:uploadprogress":
569                    this.fire("uploadprogress", event);
570                 break;
571                 case "uploaderqueue:totaluploadprogress":
572                    this.fire("totaluploadprogress", event);
573                 break;
574                 case "file:uploadcomplete":
575                    this.fire("uploadcomplete", event);
576                 break;
577                 case "uploaderqueue:alluploadscomplete":
578                    this.queue = null;
579                    this.fire("alluploadscomplete", event);
580                 break;
581                 case "uploaderqueue:uploaderror":
582                    this.fire("uploaderror", event);
583     }   
585   },
589   /**
590    * Starts the upload of a specific file.
591    *
592    * @method upload
593    * @param file {Y.FileFlash} Reference to the instance of the file to be uploaded.
594    * @param url {String} The URL to upload the file to.
595    * @param postVars {Object} (optional) A set of key-value pairs to send as variables along with the file upload HTTP request.
596    *                          If not specified, the values from the attribute `postVarsPerFile` are used instead. 
597    */
599   upload : function (file, url, postvars) {
600         
601         var uploadURL = url || this.get("uploadURL"),
602             postVars = postvars || this.get("postVarsPerFile"),
603             fileId = file.get("id");
605             postVars = postVars.hasOwnProperty(fileId) ? postVars[fileId] : postVars;
607         if (file instanceof Y.FileFlash) {
608            
609             file.on("uploadstart", this._uploadStartHandler, this);
610             file.on("uploadprogress", this._uploadProgressHandler, this);
611             file.on("uploadcomplete", this._uploadCompleteHandler, this);
612             file.on("uploaderror", this._uploadErrorHandler, this);
614             file.startUpload(uploadURL, postVars, this.get("fileFieldName"));
615         }
616   },
618   /**
619    * Starts the upload of all files on the file list, using an automated queue.
620    *
621    * @method uploadAll
622    * @param url {String} The URL to upload the files to.
623    * @param postVars {Object} (optional) A set of key-value pairs to send as variables along with the file upload HTTP request.
624    *                          If not specified, the values from the attribute `postVarsPerFile` are used instead. 
625    */
626   uploadAll : function (url, postvars) {
627         this.uploadThese(this.get("fileList"), url, postvars);
628   },
630   /**
631    * Starts the upload of the files specified in the first argument, using an automated queue.
632    *
633    * @method uploadThese
634    * @param files {Array} The list of files to upload.
635    * @param url {String} The URL to upload the files to.
636    * @param postVars {Object} (optional) A set of key-value pairs to send as variables along with the file upload HTTP request.
637    *                          If not specified, the values from the attribute `postVarsPerFile` are used instead. 
638    */
639   uploadThese : function (files, url, postvars) {
640     if (!this.queue) {
641         var uploadURL = url || this.get("uploadURL"),
642             postVars = postvars || this.get("postVarsPerFile");
644            this.queue = new UploaderQueue({simUploads: this.get("simLimit"), 
645                                                 errorAction: this.get("errorAction"),
646                                                 fileFieldName: this.get("fileFieldName"),
647                                                 fileList: files,
648                                                 uploadURL: uploadURL,
649                                                 perFileParameters: postVars
650                                                });
651            this.queue.on("uploadstart", this._uploadEventHandler, this);
652            this.queue.on("uploadprogress", this._uploadEventHandler, this);
653            this.queue.on("totaluploadprogress", this._uploadEventHandler, this);
654            this.queue.on("uploadcomplete", this._uploadEventHandler, this);
655            this.queue.on("alluploadscomplete", this._uploadEventHandler, this);
656            this.queue.on("alluploadscancelled", function (ev) {this.queue = null;}, this);
657            this.queue.on("uploaderror", this._uploadEventHandler, this);
658            this.queue.startUpload();  
659            
660            this.fire("uploadstart"); 
661     }
662   }
666   /**
667    * The template for the Flash player container. Since the Flash player container needs
668    * to completely overlay the &lquot;Select Files&rqot; control, it's positioned absolutely,
669    * with width and height set to 100% of the parent.
670    *
671    * @property FLASH_CONTAINER
672    * @type {String}
673    * @static
674    * @default "<div id='{swfContainerId}' style='position:absolute; top:0px; left: 0px; margin: 0; padding: 0; border: 0; width:100%; height:100%'></div>"
675    */
676   FLASH_CONTAINER: "<div id='{swfContainerId}' style='position:absolute; top:0px; left: 0px; margin: 0; padding: 0; border: 0; width:100%; height:100%'></div>",
678   /**
679    * The template for the "Select Files" button.
680    *
681    * @property SELECT_FILES_BUTTON
682    * @type {String}
683    * @static
684    * @default "<button type='button' class='yui3-button' tabindex='-1'>{selectButtonLabel}</button>"
685    */
686   SELECT_FILES_BUTTON: "<button type='button' class='yui3-button' tabindex='-1'>{selectButtonLabel}</button>",
688    /**
689    * The static property reflecting the type of uploader that `Y.Uploader`
690    * aliases. The UploaderFlash value is `"flash"`.
691    * 
692    * @property TYPE
693    * @type {String}
694    * @static
695    */
696   TYPE: "flash",
698   /**
699    * The identity of the widget.
700    *
701    * @property NAME
702    * @type String
703    * @default 'uploader'
704    * @readOnly
705    * @protected
706    * @static
707    */
708   NAME: "uploader",
710   /**
711    * Static property used to define the default attribute configuration of
712    * the Widget.
713    *
714    * @property ATTRS
715    * @type {Object}
716    * @protected
717    * @static
718    */
719   ATTRS: {
721         /**
722          * A Boolean indicating whether newly selected files should be appended 
723          * to the existing file list, or whether they should replace it.
724          *
725          * @attribute appendNewFiles
726          * @type {Boolean}
727          * @default true
728          */
729          appendNewFiles : {
730             value: true
731          },
733         /**
734          * The names of CSS classes that correspond to different button states
735          * of the "Select Files" control. These classes are assigned to the 
736          * "Select Files" control based on the mouse states reported by the
737          * Flash player. The keys for the class names are:
738          * <ul>
739          *   <li> <strong>`hover`</strong>: the class corresponding to mouse hovering over
740          *      the "Select Files" button.</li>
741          *   <li> <strong>`active`</strong>: the class corresponding to mouse down state of
742          *      the "Select Files" button.</li>
743          *   <li> <strong>`disabled`</strong>: the class corresponding to the disabled state
744          *      of the "Select Files" button.</li>
745          *   <li> <strong>`focus`</strong>: the class corresponding to the focused state of
746          *      the "Select Files" button.</li>
747          * </ul>
748          * @attribute buttonClassNames
749          * @type {Object}
750          * @default { hover: "yui3-button-hover",
751          *            active: "yui3-button-active",
752          *            disabled: "yui3-button-disabled",
753          *            focus: "yui3-button-selected"
754          *          }
755          */
756         buttonClassNames: {
757             value: {
758                 "hover": "yui3-button-hover",
759                 "active": "yui3-button-active",
760                 "disabled": "yui3-button-disabled",
761                 "focus": "yui3-button-selected"
762             }
763         },
765         /**
766          * A Boolean indicating whether the uploader is enabled or disabled for user input.
767          *
768          * @attribute enabled
769          * @type {Boolean}
770          * @default true
771          */
772         enabled : {
773             value: true
774         },
776         /**
777          * The action  performed when an upload error occurs for a specific file being uploaded.
778          * The possible values are: 
779          * <ul>
780          *   <li> <strong>`UploaderQueue.CONTINUE`</strong>: the error is ignored and the upload process is continued.</li>
781          *   <li> <strong>`UploaderQueue.STOP`</strong>: the upload process is stopped as soon as any other parallel file
782          *     uploads are finished.</li>
783          *   <li> <strong>`UploaderQueue.RESTART_ASAP`</strong>: the file is added back to the front of the queue.</li>
784          *   <li> <strong>`UploaderQueue.RESTART_AFTER`</strong>: the file is added to the back of the queue.</li>
785          * </ul>
786          * @attribute errorAction
787          * @type {String}
788          * @default UploaderQueue.CONTINUE
789          */
790         errorAction: {
791             value: "continue",
792             validator: function (val, name) {
793                  return (val === UploaderQueue.CONTINUE || val === UploaderQueue.STOP || val === UploaderQueue.RESTART_ASAP || val === UploaderQueue.RESTART_AFTER);           
794              }
795         },
797         /**
798          * An array indicating what fileFilters should be applied to the file
799          * selection dialog. Each element in the array should be an object with
800          * the following key-value pairs:
801          * {
802          *   description : String           
803              extensions: String of the form &lquot;*.ext1;*.ext2;*.ext3;...&rquot;
804          * }
805          * @attribute fileFilters
806          * @type {Array}
807          * @default null
808          */
809         fileFilters: {
810           value: null
811         },
812          
813         /**
814          * A String specifying what should be the POST field name for the file
815          * content in the upload request.
816          *
817          * @attribute fileFieldName
818          * @type {String}
819          * @default Filedata
820          */
821         fileFieldName: {
822           value: "Filedata"
823         },
825         /**
826          * The array of files to be uploaded. All elements in the array
827        * must be instances of `Y.FileFlash` and be instantiated with a `fileId`
828        * retrieved from an instance of the uploader.
829          *
830          * @attribute fileList
831          * @type {Array}
832          * @default []
833          */
834         fileList: {
835           value: []
836         },
838         /**
839          * A Boolean indicating whether multiple file selection is enabled.
840          *
841          * @attribute multipleFiles
842          * @type {Boolean}
843          * @default false
844          */
845         multipleFiles: {
846           value: false
847         },
849         /**
850          * An object, keyed by `fileId`, containing sets of key-value pairs
851          * that should be passed as POST variables along with each corresponding
852          * file. This attribute is only used if no POST variables are specifed
853          * in the upload method call.
854          *
855          * @attribute postVarsPerFile
856          * @type {Object}
857          * @default {}
858          */
859         postVarsPerFile: {
860           value: {}
861         },
863         /**
864          * The label for the "Select Files" widget. This is the value that replaces the
865          * `{selectButtonLabel}` token in the `SELECT_FILES_BUTTON` template.
866          * 
867          * @attribute selectButtonLabel
868          * @type {String}
869          * @default "Select Files"
870          */
871         selectButtonLabel: {
872             value: "Select Files"
873         },
875         /**
876          * The widget that serves as the "Select Files" control for the file uploader
877          * 
878          *
879          * @attribute selectFilesButton
880          * @type {Node | Widget}
881          * @default A standard HTML button with YUI CSS Button skin.
882          */
883         selectFilesButton : {
884            valueFn: function () {
885                      return Y.Node.create(substitute(Y.UploaderFlash.SELECT_FILES_BUTTON, {selectButtonLabel: this.get("selectButtonLabel")}));
886                  }
887          },
888      
889         /**
890          * The number of files that can be uploaded
891          * simultaneously if the automatic queue management
892          * is used. This value can be in the range between 2
893          * and 5.
894          *
895          * @attribute simLimit
896          * @type {Number}
897          * @default 2
898          */
899         simLimit: {
900                 value: 2,
901                 validator: function (val, name) {
902                     return (val >= 2 && val <= 5);
903                 }
904             },
906         /**
907          * The URL to the SWF file of the flash uploader. A copy local to
908          * the server that hosts the page on which the uploader appears is
909          * recommended.
910          *
911          * @attribute swfURL
912          * @type {String}
913          * @default "CDN Prefix + uploader/assets/flashuploader.swf" with a 
914          * random GET parameter for IE (to prevent buggy behavior when the SWF 
915          * is cached).
916          */
917         swfURL: {
918           valueFn: function () {
919             var prefix = Y.Env.cdn + "uploader/assets/flashuploader.swf";
921             if (Y.UA.ie > 0) {
922               return (prefix + "?t=" + Y.guid("uploader"));
923             }
924             return prefix;
925           }
926         },
928         /**
929          * The id's or `Node` references of the DOM elements that precede
930          * and follow the `Select Files` button in the tab order. Specifying
931          * these allows keyboard navigation to and from the Flash player
932          * layer of the uploader.
933          * The two keys corresponding to the DOM elements are:
934            <ul>
935          *   <li> `from`: the id or the `Node` reference corresponding to the
936          *     DOM element that precedes the `Select Files` button in the tab order.</li>
937          *   <li> `to`: the id or the `Node` reference corresponding to the
938          *     DOM element that follows the `Select Files` button in the tab order.</li>
939          * </ul>
940          * @attribute tabElements
941          * @type {Object}
942          * @default null
943          */
944         tabElements: {
945             value: null
946         },
948         /**
949          * The URL to which file upload requested are POSTed. Only used if a different url is not passed to the upload method call.
950          *
951          * @attribute uploadURL
952          * @type {String}
953          * @default ""
954          */
955         uploadURL: {
956           value: ""
957         }
958   }
961 Y.UploaderFlash.Queue = UploaderQueue;
966 }, '3.5.0' ,{requires:['swf', 'widget', 'substitute', 'base', 'cssbutton', 'node', 'event-custom', 'file-flash', 'uploader-queue']});