NOBUG: Fixed file access permissions
[moodle.git] / lib / yuilib / 3.13.0 / uploader-flash / uploader-flash.js
blobd23a5471c07b49710be2670de9b385398db0ff92
1 /*
2 YUI 3.13.0 (build 508226d)
3 Copyright 2013 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
6 */
8 YUI.add('uploader-flash', function (Y, NAME) {
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.
16 * @module uploader-flash
17 * @deprecated
20 // Shorthands for external modules
21 var substitute            = Y.Lang.sub,
22     UploaderQueue         = Y.Uploader.Queue;
25 /**
26  * Embed a Flash applications in a standard manner and communicate with it
27  * via External Interface.
28  * @module swf
29  */
31     var Event = Y.Event,
32         SWFDetect = Y.SWFDetect,
33         Lang = Y.Lang,
34         uA = Y.UA,
35         Node = Y.Node,
36         Escape = Y.Escape,
38         // private
39         FLASH_CID = "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000",
40         FLASH_TYPE = "application/x-shockwave-flash",
41         FLASH_VER = "10.0.22",
42         EXPRESS_INSTALL_URL = "http://fpdownload.macromedia.com/pub/flashplayer/update/current/swf/autoUpdater.swf?" + Math.random(),
43         EVENT_HANDLER = "SWF.eventHandler",
44         possibleAttributes = {align:"", allowFullScreen:"", allowNetworking:"", allowScriptAccess:"", base:"", bgcolor:"", loop:"", menu:"", name:"", play: "", quality:"", salign:"", scale:"", tabindex:"", wmode:""};
46         /**
47          * The SWF utility is a tool for embedding Flash applications in HTML pages.
48          * @module swf
49          * @title SWF Utility
50          * @requires event-custom, node, swfdetect
51          */
53         /**
54          * Creates the SWF instance and keeps the configuration data
55          *
56          * @class SWF
57          * @uses Y.Event.Target
58          * @constructor
59          * @param {String|HTMLElement} id The id of the element, or the element itself that the SWF will be inserted into.
60          *        The width and height of the SWF will be set to the width and height of this container element.
61          * @param {String} swfURL The URL of the SWF to be embedded into the page.
62          * @param {Object} p_oAttributes (optional) Configuration parameters for the Flash application and values for Flashvars
63          *        to be passed to the SWF. The p_oAttributes object allows the following additional properties:
64          *        <dl>
65          *          <dt>version : String</dt>
66          *          <dd>The minimum version of Flash required on the user's machine.</dd>
67          *          <dt>fixedAttributes : Object</dt>
68          *          <dd>An object literal containing one or more of the following String keys and their values: <code>align,
69          *              allowFullScreen, allowNetworking, allowScriptAccess, base, bgcolor, menu, name, quality, salign, scale,
70          *              tabindex, wmode.</code> event from the thumb</dd>
71          *        </dl>
72          */
74 function SWF (p_oElement /*:String*/, swfURL /*:String*/, p_oAttributes /*:Object*/ ) {
76     this._id = Y.guid("yuiswf");
79     var _id = this._id;
80     var oElement = Node.one(p_oElement);
82     var p_oAttributes = p_oAttributes || {};
84     var flashVersion = p_oAttributes.version || FLASH_VER;
86     var flashVersionSplit = (flashVersion + '').split(".");
87     var isFlashVersionRight = SWFDetect.isFlashVersionAtLeast(parseInt(flashVersionSplit[0], 10), parseInt(flashVersionSplit[1], 10), parseInt(flashVersionSplit[2], 10));
88     var canExpressInstall = (SWFDetect.isFlashVersionAtLeast(8,0,0));
89     var shouldExpressInstall = canExpressInstall && !isFlashVersionRight && p_oAttributes.useExpressInstall;
90     var flashURL = (shouldExpressInstall)?EXPRESS_INSTALL_URL:swfURL;
91     var objstring = '<object ';
92     var w, h;
93     var flashvarstring = "yId=" + Y.id + "&YUISwfId=" + _id + "&YUIBridgeCallback=" + EVENT_HANDLER + "&allowedDomain=" + document.location.hostname;
95     Y.SWF._instances[_id] = this;
96     if (oElement && (isFlashVersionRight || shouldExpressInstall) && flashURL) {
97         objstring += 'id="' + _id + '" ';
98         if (uA.ie) {
99             objstring += 'classid="' + FLASH_CID + '" ';
100         } else {
101             objstring += 'type="' + FLASH_TYPE + '" data="' + Escape.html(flashURL) + '" ';
102         }
104         w = "100%";
105         h = "100%";
107         objstring += 'width="' + w + '" height="' + h + '">';
109         if (uA.ie) {
110             objstring += '<param name="movie" value="' + Escape.html(flashURL) + '"/>';
111         }
113         for (var attribute in p_oAttributes.fixedAttributes) {
114             if (possibleAttributes.hasOwnProperty(attribute)) {
115                 objstring += '<param name="' + Escape.html(attribute) + '" value="' + Escape.html(p_oAttributes.fixedAttributes[attribute]) + '"/>';
116             }
117         }
119         for (var flashvar in p_oAttributes.flashVars) {
120             var fvar = p_oAttributes.flashVars[flashvar];
121             if (Lang.isString(fvar)) {
122                 flashvarstring += "&" + Escape.html(flashvar) + "=" + Escape.html(encodeURIComponent(fvar));
123             }
124         }
126         if (flashvarstring) {
127             objstring += '<param name="flashVars" value="' + flashvarstring + '"/>';
128         }
130         objstring += "</object>";
131         //using innerHTML as setHTML/setContent causes some issues with ExternalInterface for IE versions of the player
132         oElement.set("innerHTML", objstring);
134         this._swf = Node.one("#" + _id);
135     } else {
136         /**
137          * Fired when the Flash player version on the user's machine is
138          * below the required value.
139          *
140          * @event wrongflashversion
141          */
142         var event = {};
143         event.type = "wrongflashversion";
144         this.publish("wrongflashversion", {fireOnce:true});
145         this.fire("wrongflashversion", event);
146     }
150  * @private
151  * The static collection of all instances of the SWFs on the page.
152  * @property _instances
153  * @type Object
154  */
156 SWF._instances = SWF._instances || {};
159  * @private
160  * Handles an event coming from within the SWF and delegate it
161  * to a specific instance of SWF.
162  * @method eventHandler
163  * @param swfid {String} the id of the SWF dispatching the event
164  * @param event {Object} the event being transmitted.
165  */
166 SWF.eventHandler = function (swfid, event) {
167     SWF._instances[swfid]._eventHandler(event);
170 SWF.prototype = {
171     /**
172      * @private
173      * Propagates a specific event from Flash to JS.
174      * @method _eventHandler
175      * @param event {Object} The event to be propagated from Flash.
176      */
177     _eventHandler: function(event) {
178         if (event.type === "swfReady") {
179             this.publish("swfReady", {fireOnce:true});
180             this.fire("swfReady", event);
181         } else if(event.type === "log") {
182         } else {
183             this.fire(event.type, event);
184         }
185     },
187         /**
188      * Calls a specific function exposed by the SWF's
189      * ExternalInterface.
190      * @method callSWF
191      * @param func {String} the name of the function to call
192      * @param args {Array} the set of arguments to pass to the function.
193      */
195     callSWF: function (func, args)
196     {
197     if (!args) {
198           args= [];
199     }
200         if (this._swf._node[func]) {
201         return(this._swf._node[func].apply(this._swf._node, args));
202         } else {
203         return null;
204         }
205     },
207     /**
208      * Public accessor to the unique name of the SWF instance.
209      *
210      * @method toString
211      * @return {String} Unique name of the SWF instance.
212      */
213     toString: function()
214     {
215         return "SWF " + this._id;
216     }
219 Y.augment(SWF, Y.EventTarget);
221 Y.SWF = SWF;
222     /**
223      * The FileFlash class provides a wrapper for a file pointer stored in Flash. The File wrapper
224      * also implements the mechanics for uploading a file and tracking its progress.
225      * @module file-flash
226      */
227     /**
228      * The class provides a wrapper for a file pointer in Flash.
229      * @class FileFlash
230      * @extends Base
231      * @constructor
232      * @param {Object} config Configuration object.
233      */
235     var FileFlash = function(o) {
236         FileFlash.superclass.constructor.apply(this, arguments);
237     };
239     Y.extend(FileFlash, Y.Base, {
241        /**
242         * Construction logic executed during FileFlash instantiation.
243         *
244         * @method initializer
245         * @protected
246         */
247         initializer : function (cfg) {
248             if (!this.get("id")) {
249                 this._set("id", Y.guid("file"));
250             }
251         },
253        /**
254         * Handler of events dispatched by the Flash player.
255         *
256         * @method _swfEventHandler
257         * @param {Event} event The event object received from the Flash player.
258         * @protected
259         */
260         _swfEventHandler: function (event) {
261           if (event.id === this.get("id")) {
262           switch (event.type) {
263             /**
264              * Signals that this file's upload has started.
265              *
266              * @event uploadstart
267              * @param event {Event} The event object for the `uploadstart` with the
268              *                      following payload:
269              *  <dl>
270              *      <dt>uploader</dt>
271              *          <dd>The Y.SWF instance of Flash uploader that's handling the upload.</dd>
272              *  </dl>
273              */
274             case "uploadstart":
275                  this.fire("uploadstart", {uploader: this.get("uploader")});
276                  break;
277             case "uploadprogress":
279                   /**
280                    * Signals that progress has been made on the upload of this file.
281                    *
282                    * @event uploadprogress
283                    * @param event {Event} The event object for the `uploadprogress` with the
284                    *                      following payload:
285                    *  <dl>
286                    *      <dt>originEvent</dt>
287                    *          <dd>The original event fired by the Flash uploader instance.</dd>
288                    *      <dt>bytesLoaded</dt>
289                    *          <dd>The number of bytes of the file that has been uploaded.</dd>
290                    *      <dt>bytesTotal</dt>
291                    *          <dd>The total number of bytes in the file (the file size)</dd>
292                    *      <dt>percentLoaded</dt>
293                    *          <dd>The fraction of the file that has been uploaded, out of 100.</dd>
294                    *  </dl>
295                    */
296                  this.fire("uploadprogress", {originEvent: event,
297                                               bytesLoaded: event.bytesLoaded,
298                                               bytesTotal: event.bytesTotal,
299                                               percentLoaded: Math.min(100, Math.round(10000*event.bytesLoaded/event.bytesTotal)/100)
300                                              });
301                  this._set("bytesUploaded", event.bytesLoaded);
302                  break;
303             case "uploadcomplete":
305                   /**
306                    * Signals that this file's upload has completed, but data has not yet been received from the server.
307                    *
308                    * @event uploadfinished
309                    * @param event {Event} The event object for the `uploadfinished` with the
310                    *                      following payload:
311                    *  <dl>
312                    *      <dt>originEvent</dt>
313                    *          <dd>The original event fired by the Flash player instance.</dd>
314                    *  </dl>
315                    */
316                  this.fire("uploadfinished", {originEvent: event});
317                  break;
318             case "uploadcompletedata":
319                 /**
320                  * Signals that this file's upload has completed and data has been received from the server.
321                  *
322                  * @event uploadcomplete
323                  * @param event {Event} The event object for the `uploadcomplete` with the
324                  *                      following payload:
325                  *  <dl>
326                  *      <dt>originEvent</dt>
327                  *          <dd>The original event fired by the Flash player instance.</dd>
328                  *      <dt>data</dt>
329                  *          <dd>The data returned by the server.</dd>
330                  *  </dl>
331                  */
332                  this.fire("uploadcomplete", {originEvent: event,
333                                               data: event.data});
334                  break;
335             case "uploadcancel":
337                 /**
338                  * Signals that this file's upload has been cancelled.
339                  *
340                  * @event uploadcancel
341                  * @param event {Event} The event object for the `uploadcancel` with the
342                  *                      following payload:
343                  *  <dl>
344                  *      <dt>originEvent</dt>
345                  *          <dd>The original event fired by the Flash player instance.</dd>
346                  *  </dl>
347                  */
348                  this.fire("uploadcancel", {originEvent: event});
349                  break;
350             case "uploaderror":
352                 /**
353                  * Signals that this file's upload has encountered an error.
354                  *
355                  * @event uploaderror
356                  * @param event {Event} The event object for the `uploaderror` with the
357                  *                      following payload:
358                  *  <dl>
359                  *      <dt>originEvent</dt>
360                  *          <dd>The original event fired by the Flash player instance.</dd>
361                  *      <dt>status</dt>
362                  *          <dd>The status code reported by the Flash Player. If it's an HTTP error,
363                  *                then this corresponds to the HTTP status code received by the uploader.</dd>
364                  *      <dt>statusText</dt>
365                  *          <dd>The text of the error event reported by the Flash Player.</dd>
366                  *      <dt>source</dt>
367                  *          <dd>Either "http" (if it's an HTTP error), or "io" (if it's a network transmission
368                  *              error.)</dd>
369                  *  </dl>
370                  */
371                  this.fire("uploaderror", {originEvent: event, status: event.status, statusText: event.message, source: event.source});
373           }
374         }
375         },
377        /**
378         * Starts the upload of a specific file.
379         *
380         * @method startUpload
381         * @param url {String} The URL to upload the file to.
382         * @param parameters {Object} (optional) A set of key-value pairs to send as variables along with the file upload HTTP request.
383         * @param fileFieldName {String} (optional) The name of the POST variable that should contain the uploaded file ('Filedata' by default)
384         */
385         startUpload: function(url, parameters, fileFieldName) {
387         if (this.get("uploader")) {
389             var myUploader = this.get("uploader"),
390                 fileField = fileFieldName || "Filedata",
391                 id = this.get("id"),
392                 params = parameters || null;
394             this._set("bytesUploaded", 0);
396             myUploader.on("uploadstart", this._swfEventHandler, this);
397             myUploader.on("uploadprogress", this._swfEventHandler, this);
398             myUploader.on("uploadcomplete", this._swfEventHandler, this);
399             myUploader.on("uploadcompletedata", this._swfEventHandler, this);
400             myUploader.on("uploaderror", this._swfEventHandler, this);
402             myUploader.callSWF("upload", [id, url, params, fileField]);
403          }
405         },
407        /**
408         * Cancels the upload of a specific file, if currently in progress.
409         *
410         * @method cancelUpload
411         */
412         cancelUpload: function () {
413          if (this.get("uploader")) {
414            this.get("uploader").callSWF("cancel", [this.get("id")]);
415            this.fire("uploadcancel");
416          }
417         }
419     }, {
421        /**
422         * The identity of the class.
423         *
424         * @property NAME
425         * @type String
426         * @default 'file'
427         * @readOnly
428         * @protected
429         * @static
430         */
431         NAME: 'file',
433        /**
434         * The type of transport.
435         *
436         * @property TYPE
437         * @type String
438         * @default 'flash'
439         * @readOnly
440         * @protected
441         * @static
442         */
443         TYPE: "flash",
445        /**
446         * Static property used to define the default attribute configuration of
447         * the File.
448         *
449         * @property ATTRS
450         * @type {Object}
451         * @protected
452         * @static
453         */
454         ATTRS: {
456        /**
457         * A String containing the unique id of the file wrapped by the FileFlash instance.
458         * The id is supplied by the Flash player uploader.
459         *
460         * @attribute id
461         * @type {String}
462         * @initOnly
463         */
464         id: {
465             writeOnce: "initOnly",
466             value: null
467         },
469        /**
470         * The size of the file wrapped by FileFlash. This value is supplied by the Flash player uploader.
471         *
472         * @attribute size
473         * @type {Number}
474         * @initOnly
475         */
476         size: {
477             writeOnce: "initOnly",
478             value: 0
479         },
481        /**
482         * The name of the file wrapped by FileFlash. This value is supplied by the Flash player uploader.
483         *
484         * @attribute name
485         * @type {String}
486         * @initOnly
487         */
488         name: {
489             writeOnce: "initOnly",
490             value: null
491         },
493        /**
494         * The date that the file wrapped by FileFlash was created on. This value is supplied by the Flash player uploader.
495         *
496         * @attribute dateCreated
497         * @type {Date}
498         * @initOnly
499         */
500         dateCreated: {
501             writeOnce: "initOnly",
502             value: null
503         },
505        /**
506         * The date that the file wrapped by FileFlash was last modified on. This value is supplied by the Flash player uploader.
507         *
508         * @attribute dateModified
509         * @type {Date}
510         * @initOnly
511         */
512         dateModified: {
513             writeOnce: "initOnly",
514             value: null
515         },
517        /**
518         * The number of bytes of the file that has been uploaded to the server. This value is
519         * non-zero only while a file is being uploaded.
520         *
521         * @attribute bytesUploaded
522         * @type {Date}
523         * @readOnly
524         */
525         bytesUploaded: {
526             readOnly: true,
527             value: 0
528         },
530        /**
531         * The type of the file wrapped by FileFlash. This value is provided by the Flash player
532         * uploader.
533         *
534         * @attribute type
535         * @type {String}
536         * @initOnly
537         */
538         type: {
539             writeOnce: "initOnly",
540             value: null
541         },
543        /**
544         * The instance of Y.SWF wrapping the Flash player uploader associated with this file.
545         *
546         * @attribute uploder
547         * @type {SWF}
548         * @initOnly
549         */
550         uploader: {
551             writeOnce: "initOnly",
552             value: null
553         }
554         }
555     });
557     Y.FileFlash = FileFlash;
559 * This module provides a UI for file selection and multiple file upload capability
560 * using Flash as a transport engine.
561 * @class UploaderFlash
562 * @extends Widget
563 * @param {Object} config Configuration object.
564 * @constructor
565 * @deprecated
568 function UploaderFlash() {
569     UploaderFlash.superclass.constructor.apply ( this, arguments );
574 Y.UploaderFlash = Y.extend(UploaderFlash, Y.Widget, {
576     /**
577     * Stored value of the current button state (based on
578     * mouse events dispatched by the Flash player)
579     * @property _buttonState
580     * @type {String}
581     * @protected
582     */
583     _buttonState: "up",
585     /**
586     * Stored value of the current button focus state (based
587     * on keyboard and mouse events).
588     * @property _buttonFocus
589     * @type {Boolean}
590     * @protected
591     */
592     _buttonFocus: false,
594     /**
595     * Stored value of the unique id for the container that holds the
596     * Flash uploader.
597     *
598     * @property _swfContainerId
599     * @type {String}
600     * @protected
601     */
602     _swfContainerId: null,
604     /**
605     * Stored reference to the instance of SWF used to host the
606     * Flash uploader.
607     *
608     * @property _swfReference
609     * @type {SWF}
610     * @protected
611     */
612     _swfReference: null,
614     /**
615     * Stored reference to the instance of Uploader.Queue used to manage
616     * the upload process. This is a read-only property that only exists
617     * during an active upload process. Only one queue can be active at
618     * a time; if an upload start is attempted while a queue is active,
619     * it will be ignored.
620     *
621     * @property queue
622     * @type {Y.Uploader.Queue}
623     */
624     queue: null,
626     /**
627     * Stored event bindings for keyboard navigation to and from the uploader.
628     *
629     * @property _tabElementBindings
630     * @type {Object}
631     * @protected
632     */
633     _tabElementBindings: null,
636     /**
637     * Construction logic executed during UploaderFlash instantiation.
638     *
639     * @method initializer
640     * @protected
641     */
642     initializer : function () {
644         // Assign protected variable values
645         this._swfContainerId = Y.guid("uploader");
646         this._swfReference = null;
647         this.queue = null;
648         this._buttonState = "up";
649         this._buttonFocus = null;
650         this._tabElementBindings = null;
651         this._fileList = [];
653         // Publish available events
655         /**
656         * Signals that files have been selected.
657         *
658         * @event fileselect
659         * @param event {Event} The event object for the `fileselect` with the
660         *                      following payload:
661         *  <dl>
662         *      <dt>fileList</dt>
663         *          <dd>An `Array` of files selected by the user, encapsulated
664         *              in Y.FileFlash objects.</dd>
665         *  </dl>
666         */
667         this.publish("fileselect");
669         /**
670         * Signals that an upload of multiple files has been started.
671         *
672         * @event uploadstart
673         * @param event {Event} The event object for the `uploadstart`.
674         */
675         this.publish("uploadstart");
677         /**
678         * Signals that an upload of a specific file has started.
679         *
680         * @event fileuploadstart
681         * @param event {Event} The event object for the `fileuploadstart` with the
682         *                      following payload:
683         *  <dl>
684         *      <dt>file</dt>
685         *          <dd>A reference to the Y.File that dispatched the event.</dd>
686         *      <dt>originEvent</dt>
687         *          <dd>The original event dispatched by Y.File.</dd>
688         *  </dl>
689         */
690         this.publish("fileuploadstart");
692         /**
693         * Reports on upload progress of a specific file.
694         *
695         * @event uploadprogress
696         * @param event {Event} The event object for the `uploadprogress` with the
697         *                      following payload:
698         *  <dl>
699         *      <dt>bytesLoaded</dt>
700         *          <dd>The number of bytes of the file that has been uploaded</dd>
701         *      <dt>bytesTotal</dt>
702         *          <dd>The total number of bytes in the file</dd>
703         *      <dt>percentLoaded</dt>
704         *          <dd>The fraction of the file that has been uploaded, out of 100</dd>
705         *      <dt>originEvent</dt>
706         *          <dd>The original event dispatched by the SWF uploader</dd>
707         *  </dl>
708         */
709         this.publish("uploadprogress");
711         /**
712         * Reports on the total upload progress of the file list.
713         *
714         * @event totaluploadprogress
715         * @param event {Event} The event object for the `totaluploadprogress` with the
716         *                      following payload:
717         *  <dl>
718         *      <dt>bytesLoaded</dt>
719         *          <dd>The number of bytes of the file list that has been uploaded</dd>
720         *      <dt>bytesTotal</dt>
721         *          <dd>The total number of bytes in the file list</dd>
722         *      <dt>percentLoaded</dt>
723         *          <dd>The fraction of the file list that has been uploaded, out of 100</dd>
724         *  </dl>
725         */
726         this.publish("totaluploadprogress");
728         /**
729         * Signals that a single file upload has been completed.
730         *
731         * @event uploadcomplete
732         * @param event {Event} The event object for the `uploadcomplete` with the
733         *                      following payload:
734         *  <dl>
735         *      <dt>file</dt>
736         *          <dd>The pointer to the instance of `Y.File` whose upload has been completed.</dd>
737         *      <dt>originEvent</dt>
738         *          <dd>The original event fired by the SWF Uploader</dd>
739         *      <dt>data</dt>
740         *          <dd>Data returned by the server.</dd>
741         *  </dl>
742         */
743         this.publish("uploadcomplete");
745         /**
746         * Signals that the upload process of the entire file list has been completed.
747         *
748         * @event alluploadscomplete
749         * @param event {Event} The event object for the `alluploadscomplete`.
750         */
751         this.publish("alluploadscomplete");
753         /**
754         * Signals that a error has occurred in a specific file's upload process.
755         *
756         * @event uploaderror
757         * @param event {Event} The event object for the `uploaderror` with the
758         *                      following payload:
759         *  <dl>
760         *      <dt>originEvent</dt>
761         *          <dd>The original error event fired by the SWF Uploader. </dd>
762         *      <dt>file</dt>
763         *          <dd>The pointer at the instance of Y.FileFlash that returned the error.</dd>
764         *      <dt>source</dt>
765         *          <dd>The source of the upload error, either "io" or "http"</dd>
766         *      <dt>message</dt>
767         *          <dd>The message that accompanied the error. Corresponds to the text of
768         *              the error in cases where source is "io", and to the HTTP status for
769                                      cases where source is "http".</dd>
770         *  </dl>
771         */
772         this.publish("uploaderror");
774         /**
775         * Signals that a mouse has begun hovering over the `Select Files` button.
776         *
777         * @event mouseenter
778         * @param event {Event} The event object for the `mouseenter` event.
779         */
780         this.publish("mouseenter");
782         /**
783         * Signals that a mouse has stopped hovering over the `Select Files` button.
784         *
785         * @event mouseleave
786         * @param event {Event} The event object for the `mouseleave` event.
787         */
788         this.publish("mouseleave");
790         /**
791         * Signals that a mouse button has been pressed over the `Select Files` button.
792         *
793         * @event mousedown
794         * @param event {Event} The event object for the `mousedown` event.
795         */
796         this.publish("mousedown");
798         /**
799         * Signals that a mouse button has been released over the `Select Files` button.
800         *
801         * @event mouseup
802         * @param event {Event} The event object for the `mouseup` event.
803         */
804         this.publish("mouseup");
806         /**
807         * Signals that a mouse has been clicked over the `Select Files` button.
808         *
809         * @event click
810         * @param event {Event} The event object for the `click` event.
811         */
812         this.publish("click");
813     },
815     /**
816     * Creates the DOM structure for the UploaderFlash.
817     * UploaderFlash's DOM structure consists of two layers: the base "Select Files"
818     * button that can be replaced by the developer's widget of choice; and a transparent
819     * Flash overlay positoned above the button that captures all input events.
820     * The `position` style attribute of the `boundingBox` of the `Uploader` widget
821     * is forced to be `relative`, in order to accommodate the Flash player overlay
822     * (which is `position`ed `absolute`ly).
823     *
824     * @method renderUI
825     * @protected
826     */
827     renderUI : function () {
828         var boundingBox = this.get("boundingBox"),
829             contentBox = this.get('contentBox'),
830             selFilesButton = this.get("selectFilesButton"),
831             flashContainer = Y.Node.create(substitute(UploaderFlash.FLASH_CONTAINER, {
832                 swfContainerId: this._swfContainerId
833             })),
834             params = {
835                 version: "10.0.45",
836                 fixedAttributes: {
837                     wmode: "transparent",
838                     allowScriptAccess:"always",
839                     allowNetworking:"all",
840                     scale: "noscale"
841                 }
842             };
844         boundingBox.setStyle("position", "relative");
845         selFilesButton.setStyles({width: "100%", height: "100%"});
846         contentBox.append(selFilesButton);
847         contentBox.append(flashContainer);
849         this._swfReference = new Y.SWF(flashContainer, this.get("swfURL"), params);
850     },
852     /**
853     * Binds handlers to the UploaderFlash UI events and propagates attribute
854     * values to the Flash player.
855     * The propagation of initial values is set to occur once the Flash player
856     * instance is ready (as indicated by the `swfReady` event.)
857     *
858     * @method bindUI
859     * @protected
860     */
861     bindUI : function () {
863         this._swfReference.on("swfReady", function () {
864             this._setMultipleFiles();
865             this._setFileFilters();
866             this._triggerEnabled();
867             this._attachTabElements();
868             this.after("multipleFilesChange", this._setMultipleFiles, this);
869             this.after("fileFiltersChange", this._setFileFilters, this);
870             this.after("enabledChange", this._triggerEnabled, this);
871             this.after("tabElementsChange", this._attachTabElements);
872         }, this);
874         this._swfReference.on("fileselect", this._updateFileList, this);
878         // this._swfReference.on("trace", function (ev) {console.log(ev.message);});
880         this._swfReference.on("mouseenter", function () {
881             this.fire("mouseenter");
882             this._setButtonClass("hover", true);
883             if (this._buttonState === "down") {
884                 this._setButtonClass("active", true);
885             }
886         }, this);
888         this._swfReference.on("mouseleave", function () {
889             this.fire("mouseleave");
890             this._setButtonClass("hover", false);
891             this._setButtonClass("active", false);
892         }, this);
894         this._swfReference.on("mousedown", function () {
895             this.fire("mousedown");
896             this._buttonState = "down";
897             this._setButtonClass("active", true);
898         }, this);
900         this._swfReference.on("mouseup", function () {
901             this.fire("mouseup");
902             this._buttonState = "up";
903             this._setButtonClass("active", false);
904         }, this);
906         this._swfReference.on("click", function () {
907             this.fire("click");
908             this._buttonFocus = true;
909             this._setButtonClass("focus", true);
910             Y.one("body").focus();
911             this._swfReference._swf.focus();
912         }, this);
913     },
915     /**
916     * Attaches keyboard bindings to enabling tabbing to and from the instance of the Flash
917     * player in the Uploader widget. If the previous and next elements are specified, the
918     * keyboard bindings enable the user to tab from the `tabElements["from"]` node to the
919     * Flash-powered "Select Files" button, and to the `tabElements["to"]` node.
920     *
921     * @method _attachTabElements
922     * @protected
923     * @param ev {Event} Optional event payload if called as a `tabElementsChange` handler.
924     */
925     _attachTabElements : function () {
926         if (this.get("tabElements") !== null && this.get("tabElements").from !== null && this.get("tabElements").to !== null) {
928             if (this._tabElementBindings !== null) {
929                 this._tabElementBindings.from.detach();
930                 this._tabElementBindings.to.detach();
931                 this._tabElementBindings.tabback.detach();
932                 this._tabElementBindings.tabforward.detach();
933                 this._tabElementBindings.focus.detach();
934                 this._tabElementBindings.blur.detach();
935             }
936             else {
937                 this._tabElementBindings = {};
938             }
940             var fromElement = Y.one(this.get("tabElements").from),
941                 toElement = Y.one(this.get("tabElements").to);
944             this._tabElementBindings.from = fromElement.on("keydown", function (ev) {
945                 if (ev.keyCode === 9 && !ev.shiftKey) {
946                     ev.preventDefault();
947                     this._swfReference._swf.setAttribute("tabindex", 0);
948                     this._swfReference._swf.setAttribute("role", "button");
949                     this._swfReference._swf.setAttribute("aria-label", this.get("selectButtonLabel"));
950                     this._swfReference._swf.focus();
951                 }
952             }, this);
954             this._tabElementBindings.to = toElement.on("keydown", function (ev) {
955                 if (ev.keyCode === 9 && ev.shiftKey) {
956                     ev.preventDefault();
957                     this._swfReference._swf.setAttribute("tabindex", 0);
958                     this._swfReference._swf.setAttribute("role", "button");
959                     this._swfReference._swf.setAttribute("aria-label", this.get("selectButtonLabel"));
960                     this._swfReference._swf.focus();
961                 }
962             }, this);
964             this._tabElementBindings.tabback = this._swfReference.on("tabback", function () {
965                 this._swfReference._swf.blur();
966                 setTimeout(function () {
967                     fromElement.focus();
968                 }, 30);
969             }, this);
971             this._tabElementBindings.tabforward = this._swfReference.on("tabforward", function () {
972                 this._swfReference._swf.blur();
973                 setTimeout(function () {
974                     toElement.focus();
975                 }, 30);
976             }, this);
978             this._tabElementBindings.focus = this._swfReference._swf.on("focus", function () {
979                 this._buttonFocus = true;
980                 this._setButtonClass("focus", true);
981             }, this);
983             this._tabElementBindings.blur = this._swfReference._swf.on("blur", function () {
984                 this._buttonFocus = false;
985                 this._setButtonClass("focus", false);
986             }, this);
987         }
988         else if (this._tabElementBindings !== null) {
989             this._tabElementBindings.from.detach();
990             this._tabElementBindings.to.detach();
991             this._tabElementBindings.tabback.detach();
992             this._tabElementBindings.tabforward.detach();
993             this._tabElementBindings.focus.detach();
994             this._tabElementBindings.blur.detach();
995         }
996     },
999     /**
1000     * Adds or removes a specified state CSS class to the underlying uploader button.
1001     *
1002     * @method _setButtonClass
1003     * @protected
1004     * @param state {String} The name of the state enumerated in `buttonClassNames` attribute
1005     * from which to derive the needed class name.
1006     * @param add {Boolean} A Boolean indicating whether to add or remove the class.
1007     */
1008     _setButtonClass : function (state, add) {
1009         if (add) {
1010             this.get("selectFilesButton").addClass(this.get("buttonClassNames")[state]);
1011         }
1012         else {
1013             this.get("selectFilesButton").removeClass(this.get("buttonClassNames")[state]);
1014         }
1015     },
1018     /**
1019     * Syncs the state of the `fileFilters` attribute between the instance of UploaderFlash
1020     * and the Flash player.
1021     *
1022     * @method _setFileFilters
1023     * @private
1024     */
1025     _setFileFilters : function () {
1026         if (this._swfReference && this.get("fileFilters").length > 0) {
1027             this._swfReference.callSWF("setFileFilters", [this.get("fileFilters")]);
1028         }
1029     },
1033     /**
1034     * Syncs the state of the `multipleFiles` attribute between this class
1035     * and the Flash uploader.
1036     *
1037     * @method _setMultipleFiles
1038     * @private
1039     */
1040     _setMultipleFiles : function () {
1041         if (this._swfReference) {
1042             this._swfReference.callSWF("setAllowMultipleFiles", [this.get("multipleFiles")]);
1043         }
1044     },
1046     /**
1047     * Syncs the state of the `enabled` attribute between this class
1048     * and the Flash uploader.
1049     *
1050     * @method _triggerEnabled
1051     * @private
1052     */
1053     _triggerEnabled : function () {
1054         if (this.get("enabled")) {
1055             this._swfReference.callSWF("enable");
1056             this._swfReference._swf.setAttribute("aria-disabled", "false");
1057             this._setButtonClass("disabled", false);
1058         }
1059         else {
1060             this._swfReference.callSWF("disable");
1061             this._swfReference._swf.setAttribute("aria-disabled", "true");
1062             this._setButtonClass("disabled", true);
1063         }
1064     },
1066     /**
1067     * Getter for the `fileList` attribute
1068     *
1069     * @method _getFileList
1070     * @private
1071     */
1072     _getFileList : function () {
1073         return this._fileList.concat();
1074     },
1076     /**
1077     * Setter for the `fileList` attribute
1078     *
1079     * @method _setFileList
1080     * @private
1081     */
1082     _setFileList : function (val) {
1083         this._fileList = val.concat();
1084         return this._fileList.concat();
1085     },
1087     /**
1088     * Adjusts the content of the `fileList` based on the results of file selection
1089     * and the `appendNewFiles` attribute. If the `appendNewFiles` attribute is true,
1090     * then selected files are appended to the existing list; otherwise, the list is
1091     * cleared and populated with the newly selected files.
1092     *
1093     * @method _updateFileList
1094     * @param ev {Event} The file selection event received from the uploader.
1095     * @private
1096     */
1097     _updateFileList : function (ev) {
1099         Y.one("body").focus();
1100         this._swfReference._swf.focus();
1103         var newfiles = ev.fileList,
1104             fileConfObjects = [],
1105             parsedFiles = [],
1106             swfRef = this._swfReference,
1107             filterFunc = this.get("fileFilterFunction"),
1108             oldfiles;
1110         Y.each(newfiles, function (value) {
1111             var newFileConf = {};
1112             newFileConf.id = value.fileId;
1113             newFileConf.name = value.fileReference.name;
1114             newFileConf.size = value.fileReference.size;
1115             newFileConf.type = value.fileReference.type;
1116             newFileConf.dateCreated = value.fileReference.creationDate;
1117             newFileConf.dateModified = value.fileReference.modificationDate;
1118             newFileConf.uploader = swfRef;
1120             fileConfObjects.push(newFileConf);
1121         });
1123          if (filterFunc) {
1124             Y.each(fileConfObjects, function (value) {
1125                 var newfile = new Y.FileFlash(value);
1126                 if (filterFunc(newfile)) {
1127                     parsedFiles.push(newfile);
1128                 }
1129             });
1130          }
1131          else {
1132             Y.each(fileConfObjects, function (value) {
1133                 parsedFiles.push(new Y.FileFlash(value));
1134             });
1135          }
1137         if (parsedFiles.length > 0) {
1138             oldfiles = this.get("fileList");
1140             this.set("fileList",
1141                              this.get("appendNewFiles") ? oldfiles.concat(parsedFiles) : parsedFiles );
1143             this.fire("fileselect", { fileList: parsedFiles });
1144         }
1146     },
1150     /**
1151     * Handles and retransmits events fired by `Y.FileFlash` and `Y.Uploader.Queue`.
1152     *
1153     * @method _uploadEventHandler
1154     * @param event The event dispatched during the upload process.
1155     * @private
1156     */
1157     _uploadEventHandler : function (event) {
1159         switch (event.type) {
1160             case "file:uploadstart":
1161                  this.fire("fileuploadstart", event);
1162                 break;
1163             case "file:uploadprogress":
1164                  this.fire("uploadprogress", event);
1165                 break;
1166             case "uploaderqueue:totaluploadprogress":
1167                  this.fire("totaluploadprogress", event);
1168                 break;
1169             case "file:uploadcomplete":
1170                  this.fire("uploadcomplete", event);
1171                 break;
1172             case "uploaderqueue:alluploadscomplete":
1173                  this.queue = null;
1174                  this.fire("alluploadscomplete", event);
1175                 break;
1176             case "file:uploaderror": //overflow intentional
1177             case "uploaderqueue:uploaderror":
1178                  this.fire("uploaderror", event);
1179                 break;
1180             case "file:uploadcancel": // overflow intentional
1181             case "uploaderqueue:uploadcancel":
1182                  this.fire("uploadcancel", event);
1183             break;
1184         }
1186     },
1190     /**
1191     * Starts the upload of a specific file.
1192     *
1193     * @method upload
1194     * @param file {Y.FileFlash} Reference to the instance of the file to be uploaded.
1195     * @param url {String} The URL to upload the file to.
1196     * @param [postVars] {Object} A set of key-value pairs to send as variables along with the file upload HTTP request.
1197     *                          If not specified, the values from the attribute `postVarsPerFile` are used instead.
1198     */
1199     upload : function (file, url, postvars) {
1201         var uploadURL = url || this.get("uploadURL"),
1202             postVars = postvars || this.get("postVarsPerFile"),
1203             fileId = file.get("id");
1205             postVars = postVars.hasOwnProperty(fileId) ? postVars[fileId] : postVars;
1207         if (file instanceof Y.FileFlash) {
1209             file.on("uploadstart", this._uploadEventHandler, this);
1210             file.on("uploadprogress", this._uploadEventHandler, this);
1211             file.on("uploadcomplete", this._uploadEventHandler, this);
1212             file.on("uploaderror", this._uploadEventHandler, this);
1213             file.on("uploadcancel", this._uploadEventHandler, this);
1215             file.startUpload(uploadURL, postVars, this.get("fileFieldName"));
1216         }
1217     },
1219     /**
1220     * Starts the upload of all files on the file list, using an automated queue.
1221     *
1222     * @method uploadAll
1223     * @param url {String} The URL to upload the files to.
1224     * @param [postVars] {Object} A set of key-value pairs to send as variables along with the file upload HTTP request.
1225     *                          If not specified, the values from the attribute `postVarsPerFile` are used instead.
1226     */
1227     uploadAll : function (url, postvars) {
1228         this.uploadThese(this.get("fileList"), url, postvars);
1229     },
1231     /**
1232     * Starts the upload of the files specified in the first argument, using an automated queue.
1233     *
1234     * @method uploadThese
1235     * @param files {Array} The list of files to upload.
1236     * @param url {String} The URL to upload the files to.
1237     * @param [postVars] {Object} A set of key-value pairs to send as variables along with the file upload HTTP request.
1238     *                          If not specified, the values from the attribute `postVarsPerFile` are used instead.
1239     */
1240     uploadThese : function (files, url, postvars) {
1241         if (!this.queue) {
1242             var uploadURL = url || this.get("uploadURL"),
1243                 postVars = postvars || this.get("postVarsPerFile");
1245             this.queue = new UploaderQueue({
1246                 simUploads: this.get("simLimit"),
1247                 errorAction: this.get("errorAction"),
1248                 fileFieldName: this.get("fileFieldName"),
1249                 fileList: files,
1250                 uploadURL: uploadURL,
1251                 perFileParameters: postVars,
1252                 retryCount: this.get("retryCount")
1253             });
1255             this.queue.on("uploadstart", this._uploadEventHandler, this);
1256             this.queue.on("uploadprogress", this._uploadEventHandler, this);
1257             this.queue.on("totaluploadprogress", this._uploadEventHandler, this);
1258             this.queue.on("uploadcomplete", this._uploadEventHandler, this);
1259             this.queue.on("alluploadscomplete", this._uploadEventHandler, this);
1260             this.queue.on("alluploadscancelled", function () {this.queue = null;}, this);
1261             this.queue.on("uploaderror", this._uploadEventHandler, this);
1262             this.queue.startUpload();
1264             this.fire("uploadstart");
1265         }
1266     }
1270     /**
1271     * The template for the Flash player container. Since the Flash player container needs
1272     * to completely overlay the &lquot;Select Files&rqot; control, it's positioned absolutely,
1273     * with width and height set to 100% of the parent.
1274     *
1275     * @property FLASH_CONTAINER
1276     * @type {HTML}
1277     * @static
1278     * @default '<div id="{swfContainerId}" style="position:absolute; top:0px; left: 0px; margin: 0; padding: 0;
1279     *           border: 0; width:100%; height:100%"></div>'
1280     */
1281     FLASH_CONTAINER: '<div id="{swfContainerId}" style="position:absolute; top:0px; left: 0px; margin: 0; ' +
1282                      'padding: 0; border: 0; width:100%; height:100%"></div>',
1284     /**
1285     * The template for the "Select Files" button.
1286     *
1287     * @property SELECT_FILES_BUTTON
1288     * @type {HTML}
1289     * @static
1290     * @default "<button type='button' class='yui3-button' tabindex='-1'>{selectButtonLabel}</button>"
1291     */
1292     SELECT_FILES_BUTTON: "<button type='button' class='yui3-button' tabindex='-1'>{selectButtonLabel}</button>",
1294     /**
1295     * The static property reflecting the type of uploader that `Y.Uploader`
1296     * aliases. The UploaderFlash value is `"flash"`.
1297     *
1298     * @property TYPE
1299     * @type {String}
1300     * @static
1301     */
1302     TYPE: "flash",
1304     /**
1305     * The identity of the widget.
1306     *
1307     * @property NAME
1308     * @type String
1309     * @default 'uploader'
1310     * @readOnly
1311     * @protected
1312     * @static
1313     */
1314     NAME: "uploader",
1316     /**
1317     * Static property used to define the default attribute configuration of
1318     * the Widget.
1319     *
1320     * @property ATTRS
1321     * @type {Object}
1322     * @protected
1323     * @static
1324     */
1325     ATTRS: {
1327         /**
1328         * A Boolean indicating whether newly selected files should be appended
1329         * to the existing file list, or whether they should replace it.
1330         *
1331         * @attribute appendNewFiles
1332         * @type {Boolean}
1333         * @default true
1334         */
1335         appendNewFiles : {
1336             value: true
1337         },
1339         /**
1340         * The names of CSS classes that correspond to different button states
1341         * of the "Select Files" control. These classes are assigned to the
1342         * "Select Files" control based on the mouse states reported by the
1343         * Flash player. The keys for the class names are:
1344         * <ul>
1345         *   <li> <strong>`hover`</strong>: the class corresponding to mouse hovering over
1346         *      the "Select Files" button.</li>
1347         *   <li> <strong>`active`</strong>: the class corresponding to mouse down state of
1348         *      the "Select Files" button.</li>
1349         *   <li> <strong>`disabled`</strong>: the class corresponding to the disabled state
1350         *      of the "Select Files" button.</li>
1351         *   <li> <strong>`focus`</strong>: the class corresponding to the focused state of
1352         *      the "Select Files" button.</li>
1353         * </ul>
1354         * @attribute buttonClassNames
1355         * @type {Object}
1356         * @default { hover: "yui3-button-hover",
1357         *            active: "yui3-button-active",
1358         *            disabled: "yui3-button-disabled",
1359         *            focus: "yui3-button-selected"
1360         *          }
1361         */
1362         buttonClassNames: {
1363             value: {
1364                 "hover": "yui3-button-hover",
1365                 "active": "yui3-button-active",
1366                 "disabled": "yui3-button-disabled",
1367                 "focus": "yui3-button-selected"
1368             }
1369         },
1371         /**
1372         * A Boolean indicating whether the uploader is enabled or disabled for user input.
1373         *
1374         * @attribute enabled
1375         * @type {Boolean}
1376         * @default true
1377         */
1378         enabled : {
1379             value: true
1380         },
1382         /**
1383         * The action  performed when an upload error occurs for a specific file being uploaded.
1384         * The possible values are:
1385         * <ul>
1386         *   <li> <strong>`UploaderQueue.CONTINUE`</strong>: the error is ignored and the upload process is continued.</li>
1387         *   <li> <strong>`UploaderQueue.STOP`</strong>: the upload process is stopped as soon as any other parallel file
1388         *     uploads are finished.</li>
1389         *   <li> <strong>`UploaderQueue.RESTART_ASAP`</strong>: the file is added back to the front of the queue.</li>
1390         *   <li> <strong>`UploaderQueue.RESTART_AFTER`</strong>: the file is added to the back of the queue.</li>
1391         * </ul>
1392         * @attribute errorAction
1393         * @type {String}
1394         * @default UploaderQueue.CONTINUE
1395         */
1396         errorAction: {
1397             value: "continue",
1398             validator: function (val) {
1399                 return (
1400                     val === UploaderQueue.CONTINUE ||
1401                     val === UploaderQueue.STOP ||
1402                     val === UploaderQueue.RESTART_ASAP ||
1403                     val === UploaderQueue.RESTART_AFTER
1404                 );
1405             }
1406         },
1408         /**
1409         * An array indicating what fileFilters should be applied to the file
1410         * selection dialog. Each element in the array should be an object with
1411         * the following key-value pairs:
1412         * {
1413         *   description : String
1414          extensions: String of the form &lquot;*.ext1;*.ext2;*.ext3;...&rquot;
1415         * }
1416         * @attribute fileFilters
1417         * @type {Array}
1418         * @default []
1419         */
1420         fileFilters: {
1421             value: []
1422         },
1424         /**
1425         * A filtering function that is applied to every file selected by the user.
1426         * The function receives the `Y.File` object and must return a Boolean value.
1427         * If a `false` value is returned, the file in question is not added to the
1428         * list of files to be uploaded.
1429         * Use this function to put limits on file sizes or check the file names for
1430         * correct extension, but make sure that a server-side check is also performed,
1431         * since any client-side restrictions are only advisory and can be circumvented.
1432         *
1433         * @attribute fileFilterFunction
1434         * @type {Function}
1435         * @default null
1436         */
1437         fileFilterFunction: {
1438             value: null
1439         },
1441         /**
1442         * A String specifying what should be the POST field name for the file
1443         * content in the upload request.
1444         *
1445         * @attribute fileFieldName
1446         * @type {String}
1447         * @default Filedata
1448         */
1449         fileFieldName: {
1450             value: "Filedata"
1451         },
1453         /**
1454         * The array of files to be uploaded. All elements in the array
1455         * must be instances of `Y.FileFlash` and be instantiated with a `fileId`
1456         * retrieved from an instance of the uploader.
1457         *
1458         * @attribute fileList
1459         * @type {Array}
1460         * @default []
1461         */
1462         fileList: {
1463             value: [],
1464             getter: "_getFileList",
1465             setter: "_setFileList"
1466         },
1468         /**
1469         * A Boolean indicating whether multiple file selection is enabled.
1470         *
1471         * @attribute multipleFiles
1472         * @type {Boolean}
1473         * @default false
1474         */
1475         multipleFiles: {
1476             value: false
1477         },
1479         /**
1480         * An object, keyed by `fileId`, containing sets of key-value pairs
1481         * that should be passed as POST variables along with each corresponding
1482         * file. This attribute is only used if no POST variables are specifed
1483         * in the upload method call.
1484         *
1485         * @attribute postVarsPerFile
1486         * @type {Object}
1487         * @default {}
1488         */
1489         postVarsPerFile: {
1490             value: {}
1491         },
1493         /**
1494         * The label for the "Select Files" widget. This is the value that replaces the
1495         * `{selectButtonLabel}` token in the `SELECT_FILES_BUTTON` template.
1496         *
1497         * @attribute selectButtonLabel
1498         * @type {String}
1499         * @default "Select Files"
1500         */
1501         selectButtonLabel: {
1502             value: "Select Files"
1503         },
1505         /**
1506         * The widget that serves as the "Select Files" control for the file uploader
1507         *
1508         *
1509         * @attribute selectFilesButton
1510         * @type {Node | Widget}
1511         * @default A standard HTML button with YUI CSS Button skin.
1512         */
1513         selectFilesButton : {
1514             valueFn: function () {
1515                 return Y.Node.create(substitute(Y.UploaderFlash.SELECT_FILES_BUTTON, {selectButtonLabel: this.get("selectButtonLabel")}));
1516              }
1517         },
1519         /**
1520         * The number of files that can be uploaded
1521         * simultaneously if the automatic queue management
1522         * is used. This value can be in the range between 2
1523         * and 5.
1524         *
1525         * @attribute simLimit
1526         * @type {Number}
1527         * @default 2
1528         */
1529         simLimit: {
1530             value: 2,
1531             validator: function (val) {
1532                     return (val >= 2 && val <= 5);
1533             }
1534         },
1536         /**
1537         * The URL to the SWF file of the flash uploader. A copy local to
1538         * the server that hosts the page on which the uploader appears is
1539         * recommended.
1540         *
1541         * @attribute swfURL
1542         * @type {String}
1543         * @default "flashuploader.swf" with a
1544         * random GET parameter for IE (to prevent buggy behavior when the SWF
1545         * is cached).
1546         */
1547         swfURL: {
1548             valueFn: function () {
1549                 var prefix = "flashuploader.swf";
1551                 if (Y.UA.ie > 0) {
1552                     return (prefix + "?t=" + Y.guid("uploader"));
1553                 }
1555                 return prefix;
1556             }
1557         },
1559         /**
1560         * The id's or `Node` references of the DOM elements that precede
1561         * and follow the `Select Files` button in the tab order. Specifying
1562         * these allows keyboard navigation to and from the Flash player
1563         * layer of the uploader.
1564         * The two keys corresponding to the DOM elements are:
1565         <ul>
1566         *   <li> `from`: the id or the `Node` reference corresponding to the
1567         *     DOM element that precedes the `Select Files` button in the tab order.</li>
1568         *   <li> `to`: the id or the `Node` reference corresponding to the
1569         *     DOM element that follows the `Select Files` button in the tab order.</li>
1570         * </ul>
1571         * @attribute tabElements
1572         * @type {Object}
1573         * @default null
1574         */
1575         tabElements: {
1576             value: null
1577         },
1579         /**
1580         * The URL to which file upload requested are POSTed. Only used if a different url is not passed to the upload method call.
1581         *
1582         * @attribute uploadURL
1583         * @type {String}
1584         * @default ""
1585         */
1586         uploadURL: {
1587             value: ""
1588         },
1590         /**
1591         * The number of times to try re-uploading a file that failed to upload before
1592         * cancelling its upload.
1593         *
1594         * @attribute retryCount
1595         * @type {Number}
1596         * @default 3
1597         */
1598         retryCount: {
1599             value: 3
1600         }
1601     }
1604 Y.UploaderFlash.Queue = UploaderQueue;
1607 }, '3.13.0', {
1608     "requires": [
1609         "swfdetect",
1610         "escape",
1611         "widget",
1612         "base",
1613         "cssbutton",
1614         "node",
1615         "event-custom",
1616         "uploader-queue"
1617     ]