diff -r 322d0feea350 -r 89ef5ed3c48b src/cm/media/js/lib/yui/yui_3.10.3/build/uploader-queue/uploader-queue.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/cm/media/js/lib/yui/yui_3.10.3/build/uploader-queue/uploader-queue.js Tue Jul 16 14:29:46 2013 +0200 @@ -0,0 +1,663 @@ +/* +YUI 3.10.3 (build 2fb5187) +Copyright 2013 Yahoo! Inc. All rights reserved. +Licensed under the BSD License. +http://yuilibrary.com/license/ +*/ + +YUI.add('uploader-queue', function (Y, NAME) { + +/** +* The class manages a queue of files that should be uploaded to the server. +* It initializes the required number of uploads, tracks them as they progress, +* and automatically advances to the next upload when a preceding one has completed. +* @module uploader-queue +*/ + + + +/** +* This class manages a queue of files to be uploaded to the server. +* @class Uploader.Queue +* @extends Base +* @constructor +*/ +var UploaderQueue = function() { + this.queuedFiles = []; + this.uploadRetries = {}; + this.numberOfUploads = 0; + this.currentUploadedByteValues = {}; + this.currentFiles = {}; + this.totalBytesUploaded = 0; + this.totalBytes = 0; + + UploaderQueue.superclass.constructor.apply(this, arguments); +}; + + +Y.extend(UploaderQueue, Y.Base, { + + /** + * Stored value of the current queue state + * @property _currentState + * @type {String} + * @protected + * @default UploaderQueue.STOPPED + */ + _currentState: UploaderQueue.STOPPED, + + /** + * Construction logic executed during UploaderQueue instantiation. + * + * @method initializer + * @protected + */ + initializer : function () {}, + + /** + * Handles and retransmits upload start event. + * + * @method _uploadStartHandler + * @param event The event dispatched during the upload process. + * @private + */ + _uploadStartHandler : function (event) { + var updatedEvent = event; + updatedEvent.file = event.target; + updatedEvent.originEvent = event; + + this.fire("uploadstart", updatedEvent); + }, + + /** + * Handles and retransmits upload error event. + * + * @method _uploadErrorHandler + * @param event The event dispatched during the upload process. + * @private + */ + _uploadErrorHandler : function (event) { + var errorAction = this.get("errorAction"), + updatedEvent = event, + fileid, + retries; + + updatedEvent.file = event.target; + updatedEvent.originEvent = event; + + this.numberOfUploads-=1; + delete this.currentFiles[event.target.get("id")]; + this._detachFileEvents(event.target); + + event.target.cancelUpload(); + + if (errorAction === UploaderQueue.STOP) { + this.pauseUpload(); + } + + else if (errorAction === UploaderQueue.RESTART_ASAP) { + fileid = event.target.get("id"); + retries = this.uploadRetries[fileid] || 0; + + if (retries < this.get("retryCount")) { + this.uploadRetries[fileid] = retries + 1; + this.addToQueueTop(event.target); + } + this._startNextFile(); + } + else if (errorAction === UploaderQueue.RESTART_AFTER) { + fileid = event.target.get("id"); + retries = this.uploadRetries[fileid] || 0; + + if (retries < this.get("retryCount")) { + this.uploadRetries[fileid] = retries + 1; + this.addToQueueBottom(event.target); + } + this._startNextFile(); + } + + this.fire("uploaderror", updatedEvent); + }, + + /** + * Launches the upload of the next file in the queue. + * + * @method _startNextFile + * @private + */ + _startNextFile : function () { + if (this.queuedFiles.length > 0) { + var currentFile = this.queuedFiles.shift(), + fileId = currentFile.get("id"), + parameters = this.get("perFileParameters"), + fileParameters = parameters.hasOwnProperty(fileId) ? parameters[fileId] : parameters; + + this.currentUploadedByteValues[fileId] = 0; + + currentFile.on("uploadstart", this._uploadStartHandler, this); + currentFile.on("uploadprogress", this._uploadProgressHandler, this); + currentFile.on("uploadcomplete", this._uploadCompleteHandler, this); + currentFile.on("uploaderror", this._uploadErrorHandler, this); + currentFile.on("uploadcancel", this._uploadCancelHandler, this); + + currentFile.set("xhrHeaders", this.get("uploadHeaders")); + currentFile.set("xhrWithCredentials", this.get("withCredentials")); + + currentFile.startUpload(this.get("uploadURL"), fileParameters, this.get("fileFieldName")); + + this._registerUpload(currentFile); + } + }, + + /** + * Register a new upload process. + * + * @method _registerUpload + * @private + */ + _registerUpload : function (file) { + this.numberOfUploads += 1; + this.currentFiles[file.get("id")] = file; + }, + + /** + * Unregisters a new upload process. + * + * @method _unregisterUpload + * @private + */ + _unregisterUpload : function (file) { + if (this.numberOfUploads > 0) { + this.numberOfUploads -= 1; + } + + delete this.currentFiles[file.get("id")]; + delete this.uploadRetries[file.get("id")]; + + this._detachFileEvents(file); + }, + + _detachFileEvents : function (file) { + file.detach("uploadstart", this._uploadStartHandler); + file.detach("uploadprogress", this._uploadProgressHandler); + file.detach("uploadcomplete", this._uploadCompleteHandler); + file.detach("uploaderror", this._uploadErrorHandler); + file.detach("uploadcancel", this._uploadCancelHandler); + }, + + /** + * Handles and retransmits upload complete event. + * + * @method _uploadCompleteHandler + * @param event The event dispatched during the upload process. + * @private + */ + _uploadCompleteHandler : function (event) { + + this._unregisterUpload(event.target); + + this.totalBytesUploaded += event.target.get("size"); + delete this.currentUploadedByteValues[event.target.get("id")]; + + + if (this.queuedFiles.length > 0 && this._currentState === UploaderQueue.UPLOADING) { + this._startNextFile(); + } + + var updatedEvent = event, + uploadedTotal = this.totalBytesUploaded, + percentLoaded = Math.min(100, Math.round(10000*uploadedTotal/this.totalBytes) / 100); + + updatedEvent.file = event.target; + updatedEvent.originEvent = event; + + Y.each(this.currentUploadedByteValues, function (value) { + uploadedTotal += value; + }); + + this.fire("totaluploadprogress", { + bytesLoaded: uploadedTotal, + bytesTotal: this.totalBytes, + percentLoaded: percentLoaded + }); + + this.fire("uploadcomplete", updatedEvent); + + if (this.queuedFiles.length === 0 && this.numberOfUploads <= 0) { + this.fire("alluploadscomplete"); + this._currentState = UploaderQueue.STOPPED; + } + }, + + /** + * Handles and retransmits upload cancel event. + * + * @method _uploadCancelHandler + * @param event The event dispatched during the upload process. + * @private + */ + _uploadCancelHandler : function (event) { + + var updatedEvent = event; + updatedEvent.originEvent = event; + updatedEvent.file = event.target; + + this.fire("uploadcacel", updatedEvent); + }, + + + + /** + * Handles and retransmits upload progress event. + * + * @method _uploadProgressHandler + * @param event The event dispatched during the upload process. + * @private + */ + _uploadProgressHandler : function (event) { + + this.currentUploadedByteValues[event.target.get("id")] = event.bytesLoaded; + + var updatedEvent = event, + uploadedTotal = this.totalBytesUploaded, + percentLoaded = Math.min(100, Math.round(10000*uploadedTotal/this.totalBytes) / 100); + + updatedEvent.originEvent = event; + updatedEvent.file = event.target; + + this.fire("uploadprogress", updatedEvent); + + Y.each(this.currentUploadedByteValues, function (value) { + uploadedTotal += value; + }); + + this.fire("totaluploadprogress", { + bytesLoaded: uploadedTotal, + bytesTotal: this.totalBytes, + percentLoaded: percentLoaded + }); + }, + + /** + * Starts uploading the queued up file list. + * + * @method startUpload + */ + startUpload: function() { + this.queuedFiles = this.get("fileList").slice(0); + this.numberOfUploads = 0; + this.currentUploadedByteValues = {}; + this.currentFiles = {}; + this.totalBytesUploaded = 0; + + this._currentState = UploaderQueue.UPLOADING; + + while (this.numberOfUploads < this.get("simUploads") && this.queuedFiles.length > 0) { + this._startNextFile(); + } + }, + + /** + * Pauses the upload process. The ongoing file uploads + * will complete after this method is called, but no + * new ones will be launched. + * + * @method pauseUpload + */ + pauseUpload: function () { + this._currentState = UploaderQueue.STOPPED; + }, + + /** + * Restarts a paused upload process. + * + * @method restartUpload + */ + restartUpload: function () { + this._currentState = UploaderQueue.UPLOADING; + while (this.numberOfUploads < this.get("simUploads")) { + this._startNextFile(); + } + }, + + /** + * If a particular file is stuck in an ongoing upload without + * any progress events, this method allows to force its reupload + * by cancelling its upload and immediately relaunching it. + * + * @method forceReupload + * @param file {Y.File} The file to force reupload on. + */ + forceReupload : function (file) { + var id = file.get("id"); + if (this.currentFiles.hasOwnProperty(id)) { + file.cancelUpload(); + this._unregisterUpload(file); + this.addToQueueTop(file); + this._startNextFile(); + } + }, + + /** + * Add a new file to the top of the queue (the upload will be + * launched as soon as the current number of uploading files + * drops below the maximum permissible value). + * + * @method addToQueueTop + * @param file {Y.File} The file to add to the top of the queue. + */ + addToQueueTop: function (file) { + this.queuedFiles.unshift(file); + }, + + /** + * Add a new file to the bottom of the queue (the upload will be + * launched after all the other queued files are uploaded.) + * + * @method addToQueueBottom + * @param file {Y.File} The file to add to the bottom of the queue. + */ + addToQueueBottom: function (file) { + this.queuedFiles.push(file); + }, + + /** + * Cancels a specific file's upload. If no argument is passed, + * all ongoing uploads are cancelled and the upload process is + * stopped. + * + * @method cancelUpload + * @param file {Y.File} An optional parameter - the file whose upload + * should be cancelled. + */ + cancelUpload: function (file) { + var id, + i, + fid; + + if (file) { + id = file.get("id"); + + if (this.currentFiles[id]) { + this.currentFiles[id].cancelUpload(); + this._unregisterUpload(this.currentFiles[id]); + if (this._currentState === UploaderQueue.UPLOADING) { + this._startNextFile(); + } + } + else { + for (i = 0, len = this.queuedFiles.length; i < len; i++) { + if (this.queuedFiles[i].get("id") === id) { + this.queuedFiles.splice(i, 1); + break; + } + } + } + } + else { + for (fid in this.currentFiles) { + this.currentFiles[fid].cancelUpload(); + this._unregisterUpload(this.currentFiles[fid]); + } + + this.currentUploadedByteValues = {}; + this.currentFiles = {}; + this.totalBytesUploaded = 0; + this.fire("alluploadscancelled"); + this._currentState = UploaderQueue.STOPPED; + } + } +}, { + /** + * Static constant for the value of the `errorAction` attribute: + * prescribes the queue to continue uploading files in case of + * an error. + * @property CONTINUE + * @readOnly + * @type {String} + * @static + */ + CONTINUE: "continue", + + /** + * Static constant for the value of the `errorAction` attribute: + * prescribes the queue to stop uploading files in case of + * an error. + * @property STOP + * @readOnly + * @type {String} + * @static + */ + STOP: "stop", + + /** + * Static constant for the value of the `errorAction` attribute: + * prescribes the queue to restart a file upload immediately in case of + * an error. + * @property RESTART_ASAP + * @readOnly + * @type {String} + * @static + */ + RESTART_ASAP: "restartasap", + + /** + * Static constant for the value of the `errorAction` attribute: + * prescribes the queue to restart an errored out file upload after + * other files have finished uploading. + * @property RESTART_AFTER + * @readOnly + * @type {String} + * @static + */ + RESTART_AFTER: "restartafter", + + /** + * Static constant for the value of the `_currentState` property: + * implies that the queue is currently not uploading files. + * @property STOPPED + * @readOnly + * @type {String} + * @static + */ + STOPPED: "stopped", + + /** + * Static constant for the value of the `_currentState` property: + * implies that the queue is currently uploading files. + * @property UPLOADING + * @readOnly + * @type {String} + * @static + */ + UPLOADING: "uploading", + + /** + * The identity of the class. + * + * @property NAME + * @type String + * @default 'uploaderqueue' + * @readOnly + * @protected + * @static + */ + NAME: 'uploaderqueue', + + /** + * Static property used to define the default attribute configuration of + * the class. + * + * @property ATTRS + * @type {Object} + * @protected + * @static + */ + ATTRS: { + + /** + * Maximum number of simultaneous uploads; must be in the + * range between 1 and 5. The value of `2` is default. It + * is recommended that this value does not exceed 3. + * @attribute simUploads + * @type Number + * @default 2 + */ + simUploads: { + value: 2, + validator: function (val) { + return (val >= 1 && val <= 5); + } + }, + + /** + * The action to take in case of error. The valid values for this attribute are: + * `Y.Uploader.Queue.CONTINUE` (the upload process should continue on other files, + * ignoring the error), `Y.Uploader.Queue.STOP` (the upload process + * should stop completely), `Y.Uploader.Queue.RESTART_ASAP` (the upload + * should restart immediately on the errored out file and continue as planned), or + * Y.Uploader.Queue.RESTART_AFTER (the upload of the errored out file should restart + * after all other files have uploaded) + * @attribute errorAction + * @type String + * @default Y.Uploader.Queue.CONTINUE + */ + errorAction: { + value: "continue", + validator: function (val) { + return ( + val === UploaderQueue.CONTINUE || + val === UploaderQueue.STOP || + val === UploaderQueue.RESTART_ASAP || + val === UploaderQueue.RESTART_AFTER + ); + } + }, + + /** + * The total number of bytes that has been uploaded. + * @attribute bytesUploaded + * @type Number + */ + bytesUploaded: { + readOnly: true, + value: 0 + }, + + /** + * The total number of bytes in the queue. + * @attribute bytesTotal + * @type Number + */ + bytesTotal: { + readOnly: true, + value: 0 + }, + + /** + * The queue file list. This file list should only be modified + * before the upload has been started; modifying it after starting + * the upload has no effect, and `addToQueueTop` or `addToQueueBottom` methods + * should be used instead. + * @attribute fileList + * @type Array + */ + fileList: { + value: [], + lazyAdd: false, + setter: function (val) { + var newValue = val; + Y.Array.each(newValue, function (value) { + this.totalBytes += value.get("size"); + }, this); + + return val; + } + }, + + /** + * A String specifying what should be the POST field name for the file + * content in the upload request. + * + * @attribute fileFieldName + * @type {String} + * @default Filedata + */ + fileFieldName: { + value: "Filedata" + }, + + /** + * The URL to POST the file upload requests to. + * + * @attribute uploadURL + * @type {String} + * @default "" + */ + uploadURL: { + value: "" + }, + + /** + * Additional HTTP headers that should be included + * in the upload request. Due to Flash Player security + * restrictions, this attribute is only honored in the + * HTML5 Uploader. + * + * @attribute uploadHeaders + * @type {Object} + * @default {} + */ + uploadHeaders: { + value: {} + }, + + /** + * A Boolean that specifies whether the file should be + * uploaded with the appropriate user credentials for the + * domain. Due to Flash Player security restrictions, this + * attribute is only honored in the HTML5 Uploader. + * + * @attribute withCredentials + * @type {Boolean} + * @default true + */ + withCredentials: { + value: true + }, + + + /** + * An object, keyed by `fileId`, containing sets of key-value pairs + * that should be passed as POST variables along with each corresponding + * file. + * + * @attribute perFileParameters + * @type {Object} + * @default {} + */ + perFileParameters: { + value: {} + }, + + /** + * The number of times to try re-uploading a file that failed to upload before + * cancelling its upload. + * + * @attribute retryCount + * @type {Number} + * @default 3 + */ + retryCount: { + value: 3 + } + + } +}); + + +Y.namespace('Uploader'); +Y.Uploader.Queue = UploaderQueue; + + +}, '3.10.3', {"requires": ["base"]});