src/cm/media/js/lib/yui/yui_3.10.3/build/uploader-queue/uploader-queue.js
changeset 525 89ef5ed3c48b
equal deleted inserted replaced
524:322d0feea350 525:89ef5ed3c48b
       
     1 /*
       
     2 YUI 3.10.3 (build 2fb5187)
       
     3 Copyright 2013 Yahoo! Inc. All rights reserved.
       
     4 Licensed under the BSD License.
       
     5 http://yuilibrary.com/license/
       
     6 */
       
     7 
       
     8 YUI.add('uploader-queue', function (Y, NAME) {
       
     9 
       
    10 /**
       
    11 * The class manages a queue of files that should be uploaded to the server.
       
    12 * It initializes the required number of uploads, tracks them as they progress,
       
    13 * and automatically advances to the next upload when a preceding one has completed.
       
    14 * @module uploader-queue
       
    15 */
       
    16 
       
    17 
       
    18 
       
    19 /**
       
    20 * This class manages a queue of files to be uploaded to the server.
       
    21 * @class Uploader.Queue
       
    22 * @extends Base
       
    23 * @constructor
       
    24 */
       
    25 var UploaderQueue = function() {
       
    26     this.queuedFiles = [];
       
    27     this.uploadRetries = {};
       
    28     this.numberOfUploads = 0;
       
    29     this.currentUploadedByteValues = {};
       
    30     this.currentFiles = {};
       
    31     this.totalBytesUploaded = 0;
       
    32     this.totalBytes = 0;
       
    33 
       
    34     UploaderQueue.superclass.constructor.apply(this, arguments);
       
    35 };
       
    36 
       
    37 
       
    38 Y.extend(UploaderQueue, Y.Base, {
       
    39 
       
    40     /**
       
    41     * Stored value of the current queue state
       
    42     * @property _currentState
       
    43     * @type {String}
       
    44     * @protected
       
    45     * @default UploaderQueue.STOPPED
       
    46     */
       
    47     _currentState: UploaderQueue.STOPPED,
       
    48 
       
    49     /**
       
    50     * Construction logic executed during UploaderQueue instantiation.
       
    51     *
       
    52     * @method initializer
       
    53     * @protected
       
    54     */
       
    55     initializer : function () {},
       
    56 
       
    57     /**
       
    58     * Handles and retransmits upload start event.
       
    59     *
       
    60     * @method _uploadStartHandler
       
    61     * @param event The event dispatched during the upload process.
       
    62     * @private
       
    63     */
       
    64     _uploadStartHandler : function (event) {
       
    65         var updatedEvent = event;
       
    66         updatedEvent.file = event.target;
       
    67         updatedEvent.originEvent = event;
       
    68 
       
    69         this.fire("uploadstart", updatedEvent);
       
    70     },
       
    71 
       
    72     /**
       
    73     * Handles and retransmits upload error event.
       
    74     *
       
    75     * @method _uploadErrorHandler
       
    76     * @param event The event dispatched during the upload process.
       
    77     * @private
       
    78     */
       
    79     _uploadErrorHandler : function (event) {
       
    80         var errorAction = this.get("errorAction"),
       
    81             updatedEvent = event,
       
    82             fileid,
       
    83             retries;
       
    84 
       
    85         updatedEvent.file = event.target;
       
    86         updatedEvent.originEvent = event;
       
    87 
       
    88         this.numberOfUploads-=1;
       
    89         delete this.currentFiles[event.target.get("id")];
       
    90         this._detachFileEvents(event.target);
       
    91 
       
    92         event.target.cancelUpload();
       
    93 
       
    94         if (errorAction === UploaderQueue.STOP) {
       
    95             this.pauseUpload();
       
    96         }
       
    97 
       
    98         else if (errorAction === UploaderQueue.RESTART_ASAP) {
       
    99             fileid = event.target.get("id");
       
   100             retries = this.uploadRetries[fileid] || 0;
       
   101 
       
   102             if (retries < this.get("retryCount")) {
       
   103                 this.uploadRetries[fileid] = retries + 1;
       
   104                 this.addToQueueTop(event.target);
       
   105             }
       
   106             this._startNextFile();
       
   107         }
       
   108         else if (errorAction === UploaderQueue.RESTART_AFTER) {
       
   109             fileid = event.target.get("id");
       
   110             retries = this.uploadRetries[fileid] || 0;
       
   111 
       
   112             if (retries < this.get("retryCount")) {
       
   113                 this.uploadRetries[fileid] = retries + 1;
       
   114                 this.addToQueueBottom(event.target);
       
   115             }
       
   116             this._startNextFile();
       
   117         }
       
   118 
       
   119         this.fire("uploaderror", updatedEvent);
       
   120     },
       
   121 
       
   122     /**
       
   123     * Launches the upload of the next file in the queue.
       
   124     *
       
   125     * @method _startNextFile
       
   126     * @private
       
   127     */
       
   128     _startNextFile : function () {
       
   129         if (this.queuedFiles.length > 0) {
       
   130             var currentFile = this.queuedFiles.shift(),
       
   131                 fileId = currentFile.get("id"),
       
   132                 parameters = this.get("perFileParameters"),
       
   133                 fileParameters = parameters.hasOwnProperty(fileId) ? parameters[fileId] : parameters;
       
   134 
       
   135             this.currentUploadedByteValues[fileId] = 0;
       
   136 
       
   137             currentFile.on("uploadstart", this._uploadStartHandler, this);
       
   138             currentFile.on("uploadprogress", this._uploadProgressHandler, this);
       
   139             currentFile.on("uploadcomplete", this._uploadCompleteHandler, this);
       
   140             currentFile.on("uploaderror", this._uploadErrorHandler, this);
       
   141             currentFile.on("uploadcancel", this._uploadCancelHandler, this);
       
   142 
       
   143             currentFile.set("xhrHeaders", this.get("uploadHeaders"));
       
   144             currentFile.set("xhrWithCredentials", this.get("withCredentials"));
       
   145 
       
   146             currentFile.startUpload(this.get("uploadURL"), fileParameters, this.get("fileFieldName"));
       
   147 
       
   148             this._registerUpload(currentFile);
       
   149         }
       
   150     },
       
   151 
       
   152     /**
       
   153     * Register a new upload process.
       
   154     *
       
   155     * @method _registerUpload
       
   156     * @private
       
   157     */
       
   158     _registerUpload : function (file) {
       
   159         this.numberOfUploads += 1;
       
   160         this.currentFiles[file.get("id")] = file;
       
   161     },
       
   162 
       
   163     /**
       
   164     * Unregisters a new upload process.
       
   165     *
       
   166     * @method _unregisterUpload
       
   167     * @private
       
   168     */
       
   169     _unregisterUpload : function (file) {
       
   170         if (this.numberOfUploads > 0) {
       
   171             this.numberOfUploads -= 1;
       
   172         }
       
   173 
       
   174         delete this.currentFiles[file.get("id")];
       
   175         delete this.uploadRetries[file.get("id")];
       
   176 
       
   177         this._detachFileEvents(file);
       
   178     },
       
   179 
       
   180     _detachFileEvents : function (file) {
       
   181         file.detach("uploadstart", this._uploadStartHandler);
       
   182         file.detach("uploadprogress", this._uploadProgressHandler);
       
   183         file.detach("uploadcomplete", this._uploadCompleteHandler);
       
   184         file.detach("uploaderror", this._uploadErrorHandler);
       
   185         file.detach("uploadcancel", this._uploadCancelHandler);
       
   186     },
       
   187 
       
   188     /**
       
   189     * Handles and retransmits upload complete event.
       
   190     *
       
   191     * @method _uploadCompleteHandler
       
   192     * @param event The event dispatched during the upload process.
       
   193     * @private
       
   194     */
       
   195     _uploadCompleteHandler : function (event) {
       
   196 
       
   197         this._unregisterUpload(event.target);
       
   198 
       
   199         this.totalBytesUploaded += event.target.get("size");
       
   200         delete this.currentUploadedByteValues[event.target.get("id")];
       
   201 
       
   202 
       
   203         if (this.queuedFiles.length > 0 && this._currentState === UploaderQueue.UPLOADING) {
       
   204             this._startNextFile();
       
   205         }
       
   206 
       
   207         var updatedEvent = event,
       
   208             uploadedTotal = this.totalBytesUploaded,
       
   209             percentLoaded = Math.min(100, Math.round(10000*uploadedTotal/this.totalBytes) / 100);
       
   210 
       
   211         updatedEvent.file = event.target;
       
   212         updatedEvent.originEvent = event;
       
   213 
       
   214         Y.each(this.currentUploadedByteValues, function (value) {
       
   215             uploadedTotal += value;
       
   216         });
       
   217 
       
   218         this.fire("totaluploadprogress", {
       
   219             bytesLoaded: uploadedTotal,
       
   220             bytesTotal: this.totalBytes,
       
   221             percentLoaded: percentLoaded
       
   222         });
       
   223 
       
   224         this.fire("uploadcomplete", updatedEvent);
       
   225 
       
   226         if (this.queuedFiles.length === 0 && this.numberOfUploads <= 0) {
       
   227             this.fire("alluploadscomplete");
       
   228             this._currentState = UploaderQueue.STOPPED;
       
   229         }
       
   230     },
       
   231 
       
   232     /**
       
   233     * Handles and retransmits upload cancel event.
       
   234     *
       
   235     * @method _uploadCancelHandler
       
   236     * @param event The event dispatched during the upload process.
       
   237     * @private
       
   238     */
       
   239     _uploadCancelHandler : function (event) {
       
   240 
       
   241         var updatedEvent = event;
       
   242         updatedEvent.originEvent = event;
       
   243         updatedEvent.file = event.target;
       
   244 
       
   245         this.fire("uploadcacel", updatedEvent);
       
   246     },
       
   247 
       
   248 
       
   249 
       
   250     /**
       
   251     * Handles and retransmits upload progress event.
       
   252     *
       
   253     * @method _uploadProgressHandler
       
   254     * @param event The event dispatched during the upload process.
       
   255     * @private
       
   256     */
       
   257     _uploadProgressHandler : function (event) {
       
   258 
       
   259         this.currentUploadedByteValues[event.target.get("id")] = event.bytesLoaded;
       
   260 
       
   261         var updatedEvent = event,
       
   262             uploadedTotal = this.totalBytesUploaded,
       
   263             percentLoaded = Math.min(100, Math.round(10000*uploadedTotal/this.totalBytes) / 100);
       
   264 
       
   265         updatedEvent.originEvent = event;
       
   266         updatedEvent.file = event.target;
       
   267 
       
   268         this.fire("uploadprogress", updatedEvent);
       
   269 
       
   270         Y.each(this.currentUploadedByteValues, function (value) {
       
   271             uploadedTotal += value;
       
   272         });
       
   273 
       
   274         this.fire("totaluploadprogress", {
       
   275             bytesLoaded: uploadedTotal,
       
   276             bytesTotal: this.totalBytes,
       
   277             percentLoaded: percentLoaded
       
   278         });
       
   279     },
       
   280 
       
   281     /**
       
   282     * Starts uploading the queued up file list.
       
   283     *
       
   284     * @method startUpload
       
   285     */
       
   286     startUpload: function() {
       
   287         this.queuedFiles = this.get("fileList").slice(0);
       
   288         this.numberOfUploads = 0;
       
   289         this.currentUploadedByteValues = {};
       
   290         this.currentFiles = {};
       
   291         this.totalBytesUploaded = 0;
       
   292 
       
   293         this._currentState = UploaderQueue.UPLOADING;
       
   294 
       
   295         while (this.numberOfUploads < this.get("simUploads") && this.queuedFiles.length > 0) {
       
   296             this._startNextFile();
       
   297         }
       
   298     },
       
   299 
       
   300     /**
       
   301     * Pauses the upload process. The ongoing file uploads
       
   302     * will complete after this method is called, but no
       
   303     * new ones will be launched.
       
   304     *
       
   305     * @method pauseUpload
       
   306     */
       
   307     pauseUpload: function () {
       
   308         this._currentState = UploaderQueue.STOPPED;
       
   309     },
       
   310 
       
   311     /**
       
   312     * Restarts a paused upload process.
       
   313     *
       
   314     * @method restartUpload
       
   315     */
       
   316     restartUpload: function () {
       
   317         this._currentState = UploaderQueue.UPLOADING;
       
   318         while (this.numberOfUploads < this.get("simUploads")) {
       
   319              this._startNextFile();
       
   320         }
       
   321     },
       
   322 
       
   323     /**
       
   324     * If a particular file is stuck in an ongoing upload without
       
   325     * any progress events, this method allows to force its reupload
       
   326     * by cancelling its upload and immediately relaunching it.
       
   327     *
       
   328     * @method forceReupload
       
   329     * @param file {Y.File} The file to force reupload on.
       
   330     */
       
   331     forceReupload : function (file) {
       
   332         var id = file.get("id");
       
   333         if (this.currentFiles.hasOwnProperty(id)) {
       
   334             file.cancelUpload();
       
   335             this._unregisterUpload(file);
       
   336             this.addToQueueTop(file);
       
   337             this._startNextFile();
       
   338         }
       
   339     },
       
   340 
       
   341     /**
       
   342     * Add a new file to the top of the queue (the upload will be
       
   343     * launched as soon as the current number of uploading files
       
   344     * drops below the maximum permissible value).
       
   345     *
       
   346     * @method addToQueueTop
       
   347     * @param file {Y.File} The file to add to the top of the queue.
       
   348     */
       
   349     addToQueueTop: function (file) {
       
   350             this.queuedFiles.unshift(file);
       
   351     },
       
   352 
       
   353     /**
       
   354     * Add a new file to the bottom of the queue (the upload will be
       
   355     * launched after all the other queued files are uploaded.)
       
   356     *
       
   357     * @method addToQueueBottom
       
   358     * @param file {Y.File} The file to add to the bottom of the queue.
       
   359     */
       
   360     addToQueueBottom: function (file) {
       
   361             this.queuedFiles.push(file);
       
   362     },
       
   363 
       
   364     /**
       
   365     * Cancels a specific file's upload. If no argument is passed,
       
   366     * all ongoing uploads are cancelled and the upload process is
       
   367     * stopped.
       
   368     *
       
   369     * @method cancelUpload
       
   370     * @param file {Y.File} An optional parameter - the file whose upload
       
   371     * should be cancelled.
       
   372     */
       
   373     cancelUpload: function (file) {
       
   374         var id,
       
   375             i,
       
   376             fid;
       
   377 
       
   378         if (file) {
       
   379             id = file.get("id");
       
   380 
       
   381             if (this.currentFiles[id]) {
       
   382                 this.currentFiles[id].cancelUpload();
       
   383                 this._unregisterUpload(this.currentFiles[id]);
       
   384                 if (this._currentState === UploaderQueue.UPLOADING) {
       
   385                     this._startNextFile();
       
   386                 }
       
   387             }
       
   388             else {
       
   389                 for (i = 0, len = this.queuedFiles.length; i < len; i++) {
       
   390                     if (this.queuedFiles[i].get("id") === id) {
       
   391                         this.queuedFiles.splice(i, 1);
       
   392                         break;
       
   393                     }
       
   394                 }
       
   395             }
       
   396         }
       
   397         else {
       
   398             for (fid in this.currentFiles) {
       
   399                 this.currentFiles[fid].cancelUpload();
       
   400                 this._unregisterUpload(this.currentFiles[fid]);
       
   401             }
       
   402 
       
   403             this.currentUploadedByteValues = {};
       
   404             this.currentFiles = {};
       
   405             this.totalBytesUploaded = 0;
       
   406             this.fire("alluploadscancelled");
       
   407             this._currentState = UploaderQueue.STOPPED;
       
   408         }
       
   409     }
       
   410 }, {
       
   411     /**
       
   412     * Static constant for the value of the `errorAction` attribute:
       
   413     * prescribes the queue to continue uploading files in case of
       
   414     * an error.
       
   415     * @property CONTINUE
       
   416     * @readOnly
       
   417     * @type {String}
       
   418     * @static
       
   419     */
       
   420     CONTINUE: "continue",
       
   421 
       
   422     /**
       
   423     * Static constant for the value of the `errorAction` attribute:
       
   424     * prescribes the queue to stop uploading files in case of
       
   425     * an error.
       
   426     * @property STOP
       
   427     * @readOnly
       
   428     * @type {String}
       
   429     * @static
       
   430     */
       
   431     STOP: "stop",
       
   432 
       
   433     /**
       
   434     * Static constant for the value of the `errorAction` attribute:
       
   435     * prescribes the queue to restart a file upload immediately in case of
       
   436     * an error.
       
   437     * @property RESTART_ASAP
       
   438     * @readOnly
       
   439     * @type {String}
       
   440     * @static
       
   441     */
       
   442     RESTART_ASAP: "restartasap",
       
   443 
       
   444     /**
       
   445     * Static constant for the value of the `errorAction` attribute:
       
   446     * prescribes the queue to restart an errored out file upload after
       
   447     * other files have finished uploading.
       
   448     * @property RESTART_AFTER
       
   449     * @readOnly
       
   450     * @type {String}
       
   451     * @static
       
   452     */
       
   453     RESTART_AFTER: "restartafter",
       
   454 
       
   455     /**
       
   456     * Static constant for the value of the `_currentState` property:
       
   457     * implies that the queue is currently not uploading files.
       
   458     * @property STOPPED
       
   459     * @readOnly
       
   460     * @type {String}
       
   461     * @static
       
   462     */
       
   463     STOPPED: "stopped",
       
   464 
       
   465     /**
       
   466     * Static constant for the value of the `_currentState` property:
       
   467     * implies that the queue is currently uploading files.
       
   468     * @property UPLOADING
       
   469     * @readOnly
       
   470     * @type {String}
       
   471     * @static
       
   472     */
       
   473     UPLOADING: "uploading",
       
   474 
       
   475     /**
       
   476     * The identity of the class.
       
   477     *
       
   478     * @property NAME
       
   479     * @type String
       
   480     * @default 'uploaderqueue'
       
   481     * @readOnly
       
   482     * @protected
       
   483     * @static
       
   484     */
       
   485     NAME: 'uploaderqueue',
       
   486 
       
   487     /**
       
   488     * Static property used to define the default attribute configuration of
       
   489     * the class.
       
   490     *
       
   491     * @property ATTRS
       
   492     * @type {Object}
       
   493     * @protected
       
   494     * @static
       
   495     */
       
   496     ATTRS: {
       
   497 
       
   498         /**
       
   499         * Maximum number of simultaneous uploads; must be in the
       
   500         * range between 1 and 5. The value of `2` is default. It
       
   501         * is recommended that this value does not exceed 3.
       
   502         * @attribute simUploads
       
   503         * @type Number
       
   504         * @default 2
       
   505         */
       
   506          simUploads: {
       
   507                  value: 2,
       
   508                  validator: function (val) {
       
   509                          return (val >= 1 && val <= 5);
       
   510                  }
       
   511          },
       
   512 
       
   513         /**
       
   514         * The action to take in case of error. The valid values for this attribute are:
       
   515         * `Y.Uploader.Queue.CONTINUE` (the upload process should continue on other files,
       
   516         * ignoring the error), `Y.Uploader.Queue.STOP` (the upload process
       
   517         * should stop completely), `Y.Uploader.Queue.RESTART_ASAP` (the upload
       
   518         * should restart immediately on the errored out file and continue as planned), or
       
   519         * Y.Uploader.Queue.RESTART_AFTER (the upload of the errored out file should restart
       
   520         * after all other files have uploaded)
       
   521         * @attribute errorAction
       
   522         * @type String
       
   523         * @default Y.Uploader.Queue.CONTINUE
       
   524         */
       
   525         errorAction: {
       
   526             value: "continue",
       
   527                 validator: function (val) {
       
   528                 return (
       
   529                     val === UploaderQueue.CONTINUE ||
       
   530                     val === UploaderQueue.STOP ||
       
   531                     val === UploaderQueue.RESTART_ASAP ||
       
   532                     val === UploaderQueue.RESTART_AFTER
       
   533                 );
       
   534             }
       
   535         },
       
   536 
       
   537         /**
       
   538         * The total number of bytes that has been uploaded.
       
   539         * @attribute bytesUploaded
       
   540         * @type Number
       
   541         */
       
   542         bytesUploaded: {
       
   543             readOnly: true,
       
   544             value: 0
       
   545         },
       
   546 
       
   547         /**
       
   548         * The total number of bytes in the queue.
       
   549         * @attribute bytesTotal
       
   550         * @type Number
       
   551         */
       
   552         bytesTotal: {
       
   553             readOnly: true,
       
   554             value: 0
       
   555         },
       
   556 
       
   557         /**
       
   558         * The queue file list. This file list should only be modified
       
   559         * before the upload has been started; modifying it after starting
       
   560         * the upload has no effect, and `addToQueueTop` or `addToQueueBottom` methods
       
   561         * should be used instead.
       
   562         * @attribute fileList
       
   563         * @type Array
       
   564         */
       
   565         fileList: {
       
   566             value: [],
       
   567             lazyAdd: false,
       
   568             setter: function (val) {
       
   569                 var newValue = val;
       
   570                 Y.Array.each(newValue, function (value) {
       
   571                     this.totalBytes += value.get("size");
       
   572                 }, this);
       
   573 
       
   574                 return val;
       
   575             }
       
   576         },
       
   577 
       
   578         /**
       
   579         * A String specifying what should be the POST field name for the file
       
   580         * content in the upload request.
       
   581         *
       
   582         * @attribute fileFieldName
       
   583         * @type {String}
       
   584         * @default Filedata
       
   585         */
       
   586         fileFieldName: {
       
   587             value: "Filedata"
       
   588         },
       
   589 
       
   590         /**
       
   591         * The URL to POST the file upload requests to.
       
   592         *
       
   593         * @attribute uploadURL
       
   594         * @type {String}
       
   595         * @default ""
       
   596         */
       
   597         uploadURL: {
       
   598             value: ""
       
   599         },
       
   600 
       
   601         /**
       
   602         * Additional HTTP headers that should be included
       
   603         * in the upload request. Due to Flash Player security
       
   604         * restrictions, this attribute is only honored in the
       
   605         * HTML5 Uploader.
       
   606         *
       
   607         * @attribute uploadHeaders
       
   608         * @type {Object}
       
   609         * @default {}
       
   610         */
       
   611         uploadHeaders: {
       
   612             value: {}
       
   613         },
       
   614 
       
   615         /**
       
   616         * A Boolean that specifies whether the file should be
       
   617         * uploaded with the appropriate user credentials for the
       
   618         * domain. Due to Flash Player security restrictions, this
       
   619         * attribute is only honored in the HTML5 Uploader.
       
   620         *
       
   621         * @attribute withCredentials
       
   622         * @type {Boolean}
       
   623         * @default true
       
   624         */
       
   625         withCredentials: {
       
   626             value: true
       
   627         },
       
   628 
       
   629 
       
   630         /**
       
   631         * An object, keyed by `fileId`, containing sets of key-value pairs
       
   632         * that should be passed as POST variables along with each corresponding
       
   633         * file.
       
   634         *
       
   635         * @attribute perFileParameters
       
   636         * @type {Object}
       
   637         * @default {}
       
   638         */
       
   639         perFileParameters: {
       
   640             value: {}
       
   641         },
       
   642 
       
   643         /**
       
   644         * The number of times to try re-uploading a file that failed to upload before
       
   645         * cancelling its upload.
       
   646         *
       
   647         * @attribute retryCount
       
   648         * @type {Number}
       
   649         * @default 3
       
   650         */
       
   651         retryCount: {
       
   652             value: 3
       
   653         }
       
   654 
       
   655     }
       
   656 });
       
   657 
       
   658 
       
   659 Y.namespace('Uploader');
       
   660 Y.Uploader.Queue = UploaderQueue;
       
   661 
       
   662 
       
   663 }, '3.10.3', {"requires": ["base"]});