3
Copyright 2012 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
7
YUI.add('uploader-queue', function(Y) {
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
22
currentUploadedByteValues,
28
* This class manages a queue of files to be uploaded to the server.
29
* @class Uploader.Queue
32
* @param {Object} config Configuration object
34
var UploaderQueue = function(o) {
35
this.queuedFiles = [];
36
this.numberOfUploads = 0;
37
this.currentUploadedByteValues = {};
38
this.currentFiles = {};
39
this.totalBytesUploaded = 0;
42
UploaderQueue.superclass.constructor.apply(this, arguments);
46
Y.extend(UploaderQueue, Y.Base, {
49
* Stored value of the current queue state
50
* @property _currentState
53
* @default UploaderQueue.STOPPED
55
_currentState: UploaderQueue.STOPPED,
58
* Construction logic executed during UploaderQueue instantiation.
63
initializer : function (cfg) {
68
* Handles and retransmits upload start event.
70
* @method _uploadStartHandler
71
* @param event The event dispatched during the upload process.
74
_uploadStartHandler : function (event) {
75
var updatedEvent = event;
76
updatedEvent.file = event.target;
77
updatedEvent.originEvent = event;
79
this.fire("uploadstart", updatedEvent);
83
* Handles and retransmits upload error event.
85
* @method _uploadErrorHandler
86
* @param event The event dispatched during the upload process.
89
_uploadErrorHandler : function (event) {
90
var errorAction = this.get("errorAction");
91
var updatedEvent = event;
92
updatedEvent.file = event.target;
93
updatedEvent.originEvent = event;
95
this.numberOfUploads-=1;
96
delete this.currentFiles[event.target.get("id")];
98
event.target.cancelUpload();
100
if (errorAction === UploaderQueue.STOP) {
104
else if (errorAction === UploaderQueue.RESTART_ASAP) {
105
this.queuedFiles.unshift(event.target);
106
this._startNextFile();
108
else if (errorAction === UploaderQueue.RESTART_AFTER) {
109
this.queuedFiles.push(event.target);
110
this._startNextFile();
113
this.fire("uploaderror", updatedEvent);
117
* Launches the upload of the next file in the queue.
119
* @method _startNextFile
122
_startNextFile : function () {
123
if (this.queuedFiles.length > 0) {
124
var currentFile = this.queuedFiles.shift(),
125
fileId = currentFile.get("id"),
126
parameters = this.get("perFileParameters"),
127
fileParameters = parameters.hasOwnProperty(fileId) ? parameters[fileId] : parameters;
129
this.currentUploadedByteValues[fileId] = 0;
131
currentFile.on("uploadstart", this._uploadStartHandler, this);
132
currentFile.on("uploadprogress", this._uploadProgressHandler, this);
133
currentFile.on("uploadcomplete", this._uploadCompleteHandler, this);
134
currentFile.on("uploaderror", this._uploadErrorHandler, this);
136
currentFile.startUpload(this.get("uploadURL"), fileParameters, this.get("fileFieldName"));
138
this._registerUpload(currentFile);
143
* Register a new upload process.
145
* @method _registerUpload
148
_registerUpload : function (file) {
149
this.numberOfUploads += 1;
150
this.currentFiles[file.get("id")] = file;
154
* Unregisters a new upload process.
156
* @method _unregisterUpload
159
_unregisterUpload : function (file) {
160
if (this.numberOfUploads > 0) {
161
this.numberOfUploads -=1;
163
delete this.currentFiles[file.get("id")];
167
* Handles and retransmits upload complete event.
169
* @method _uploadCompleteHandler
170
* @param event The event dispatched during the upload process.
173
_uploadCompleteHandler : function (event) {
175
this._unregisterUpload(event.target);
177
this.totalBytesUploaded += event.target.get("size");
178
delete this.currentUploadedByteValues[event.target.get("id")];
181
if (this.queuedFiles.length > 0 && this._currentState === UploaderQueue.UPLOADING) {
182
this._startNextFile();
185
var updatedEvent = event;
186
updatedEvent.file = event.target;
187
updatedEvent.originEvent = event;
189
var uploadedTotal = this.totalBytesUploaded;
191
Y.each(this.currentUploadedByteValues, function (value) {
192
uploadedTotal += value;
195
var percentLoaded = Math.min(100, Math.round(10000*uploadedTotal/this.totalBytes) / 100);
197
this.fire("totaluploadprogress", {bytesLoaded: uploadedTotal,
198
bytesTotal: this.totalBytes,
199
percentLoaded: percentLoaded});
201
this.fire("uploadcomplete", updatedEvent);
203
if (this.queuedFiles.length === 0 && this.numberOfUploads <= 0) {
204
this.fire("alluploadscomplete");
205
this._currentState = UploaderQueue.STOPPED;
212
* Handles and retransmits upload progress event.
214
* @method _uploadProgressHandler
215
* @param event The event dispatched during the upload process.
218
_uploadProgressHandler : function (event) {
220
this.currentUploadedByteValues[event.target.get("id")] = event.bytesLoaded;
222
var updatedEvent = event;
223
updatedEvent.originEvent = event;
224
updatedEvent.file = event.target;
226
this.fire("uploadprogress", updatedEvent);
228
var uploadedTotal = this.totalBytesUploaded;
230
Y.each(this.currentUploadedByteValues, function (value) {
231
uploadedTotal += value;
234
var percentLoaded = Math.min(100, Math.round(10000*uploadedTotal/this.totalBytes) / 100);
236
this.fire("totaluploadprogress", {bytesLoaded: uploadedTotal,
237
bytesTotal: this.totalBytes,
238
percentLoaded: percentLoaded});
242
* Starts uploading the queued up file list.
244
* @method startUpload
246
startUpload: function() {
248
this.queuedFiles = this.get("fileList").slice(0);
249
this.numberOfUploads = 0;
250
this.currentUploadedByteValues = {};
251
this.currentFiles = {};
252
this.totalBytesUploaded = 0;
254
this._currentState = UploaderQueue.UPLOADING;
256
while (this.numberOfUploads < this.get("simUploads") && this.queuedFiles.length > 0) {
257
this._startNextFile();
262
* Pauses the upload process. The ongoing file uploads
263
* will complete after this method is called, but no
264
* new ones will be launched.
266
* @method pauseUpload
268
pauseUpload: function () {
269
this._currentState = UploaderQueue.STOPPED;
273
* Restarts a paused upload process.
275
* @method restartUpload
277
restartUpload: function () {
278
this._currentState = UploaderQueue.UPLOADING;
279
while (this.numberOfUploads < this.get("simUploads")) {
280
this._startNextFile();
285
* If a particular file is stuck in an ongoing upload without
286
* any progress events, this method allows to force its reupload
287
* by cancelling its upload and immediately relaunching it.
289
* @method forceReupload
290
* @param file {Y.File} The file to force reupload on.
292
forceReupload : function (file) {
293
var id = file.get("id");
294
if (this.currentFiles.hasOwnProperty(id)) {
296
this._unregisterUpload(file);
297
this.queuedFiles.unshift(file);
298
this._startNextFile();
303
* Add a new file to the top of the queue (the upload will be
304
* launched as soon as the current number of uploading files
305
* drops below the maximum permissible value).
307
* @method addToQueueTop
308
* @param file {Y.File} The file to add to the top of the queue.
310
addToQueueTop: function (file) {
311
this.queuedFiles.unshift(file);
315
* Add a new file to the bottom of the queue (the upload will be
316
* launched after all the other queued files are uploaded.)
318
* @method addToQueueBottom
319
* @param file {Y.File} The file to add to the bottom of the queue.
321
addToQueueBottom: function (file) {
322
this.queuedFiles.push(file);
326
* Cancels a specific file's upload. If no argument is passed,
327
* all ongoing uploads are cancelled and the upload process is
330
* @method cancelUpload
331
* @param file {Y.File} An optional parameter - the file whose upload
332
* should be cancelled.
334
cancelUpload: function (file) {
337
var id = file.get("id");
338
if (this.currentFiles[id]) {
339
this.currentFiles[id].cancelUpload();
340
this._unregisterUpload(this.currentFiles[id]);
343
for (var i = 0, len = this.queuedFiles.length; i < len; i++) {
344
if (this.queuedFiles[i].get("id") === id) {
345
this.queuedFiles.splice(i, 1);
352
for (var fid in this.currentFiles) {
353
this.currentFiles[fid].cancelUpload();
354
this._unregisterUpload(this.currentFiles[fid]);
357
this.currentUploadedByteValues = {};
358
this.currentFiles = {};
359
this.totalBytesUploaded = 0;
360
this.fire("alluploadscancelled");
361
this._currentState = UploaderQueue.STOPPED;
368
* Static constant for the value of the `errorAction` attribute:
369
* prescribes the queue to continue uploading files in case of
376
CONTINUE: "continue",
379
* Static constant for the value of the `errorAction` attribute:
380
* prescribes the queue to stop uploading files in case of
390
* Static constant for the value of the `errorAction` attribute:
391
* prescribes the queue to restart a file upload immediately in case of
393
* @property RESTART_ASAP
398
RESTART_ASAP: "restartasap",
401
* Static constant for the value of the `errorAction` attribute:
402
* prescribes the queue to restart an errored out file upload after
403
* other files have finished uploading.
404
* @property RESTART_AFTER
409
RESTART_AFTER: "restartafter",
412
* Static constant for the value of the `_currentState` property:
413
* implies that the queue is currently not uploading files.
422
* Static constant for the value of the `_currentState` property:
423
* implies that the queue is currently uploading files.
424
* @property UPLOADING
429
UPLOADING: "uploading",
432
* The identity of the class.
436
* @default 'uploaderqueue'
441
NAME: 'uploaderqueue',
444
* Static property used to define the default attribute configuration of
455
* Maximum number of simultaneous uploads; must be in the
456
* range between 1 and 5. The value of `2` is default. It
457
* is recommended that this value does not exceed 3.
458
* @property simUploads
464
validator: function (val, name) {
465
return (val >= 1 && val <= 5);
470
* The action to take in case of error. The valid values for this attribute are:
471
* `Y.Uploader.Queue.CONTINUE` (the upload process should continue on other files,
472
* ignoring the error), `Y.Uploader.Queue.STOP` (the upload process
473
* should stop completely), `Y.Uploader.Queue.RESTART_ASAP` (the upload
474
* should restart immediately on the errored out file and continue as planned), or
475
* Y.Uploader.Queue.RESTART_AFTER (the upload of the errored out file should restart
476
* after all other files have uploaded)
477
* @property errorAction
479
* @default Y.Uploader.Queue.CONTINUE
483
validator: function (val, name) {
484
return (val === UploaderQueue.CONTINUE || val === UploaderQueue.STOP || val === UploaderQueue.RESTART_ASAP || val === UploaderQueue.RESTART_AFTER);
489
* The total number of bytes that has been uploaded.
490
* @property bytesUploaded
499
* The total number of bytes in the queue.
500
* @property bytesTotal
509
* The queue file list. This file list should only be modified
510
* before the upload has been started; modifying it after starting
511
* the upload has no effect, and `addToQueueTop` or `addToQueueBottom` methods
512
* should be used instead.
519
setter: function (val) {
521
Y.Array.each(newValue, function (value) {
522
this.totalBytes += value.get("size");
530
* A String specifying what should be the POST field name for the file
531
* content in the upload request.
533
* @attribute fileFieldName
542
* The URL to POST the file upload requests to.
544
* @attribute uploadURL
552
* An object, keyed by `fileId`, containing sets of key-value pairs
553
* that should be passed as POST variables along with each corresponding
556
* @attribute perFileParameters
568
Y.namespace('Uploader');
569
Y.Uploader.Queue = UploaderQueue;
572
}, '3.5.1' ,{requires:['base']});