Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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