~ubuntu-branches/ubuntu/utopic/moodle/utopic

« back to all changes in this revision

Viewing changes to lib/yuilib/3.13.0/uploader-queue/uploader-queue-debug.js

  • Committer: Package Import Robot
  • Author(s): Thijs Kinkhorst
  • Date: 2014-05-12 16:10:38 UTC
  • mfrom: (36.1.3 sid)
  • Revision ID: package-import@ubuntu.com-20140512161038-puyqf65k4e0s8ytz
Tags: 2.6.3-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
*/
 
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("uploadcancel", 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.13.0', {"requires": ["base"]});