Dotclear

source: admin/js/jsUpload/jquery.fileupload-ui.js @ 1144:4af82896ca3d

Revision 1144:4af82896ca3d, 24.5 KB checked in by Nicolas <nikrou77@…>, 12 years ago (diff)

Remplacement de l'upload utilisant swfupload par le plugin jQuery-File-Upload

Todo:

  • Gestion des suppressions
  • Gestion des annulations
  • Gestion des mises de l'interface sans rechargement de la page
  • Simplification (moins de javascript) ?
Line 
1/*
2 * jQuery File Upload User Interface Plugin 8.2.1
3 * https://github.com/blueimp/jQuery-File-Upload
4 *
5 * Copyright 2010, Sebastian Tschan
6 * https://blueimp.net
7 *
8 * Licensed under the MIT license:
9 * http://www.opensource.org/licenses/MIT
10 */
11
12/*jslint nomen: true, unparam: true, regexp: true */
13/*global define, window, URL, webkitURL, FileReader */
14
15(function (factory) {
16    'use strict';
17    if (typeof define === 'function' && define.amd) {
18        // Register as an anonymous AMD module:
19        define([
20            'jquery',
21            'tmpl',
22            './jquery.fileupload-resize',
23            './jquery.fileupload-validate'
24        ], factory);
25    } else {
26        // Browser globals:
27        factory(
28            window.jQuery,
29            window.tmpl
30        );
31    }
32}(function ($, tmpl, loadImage) {
33    'use strict';
34
35    $.blueimp.fileupload.prototype._specialOptions.push(
36        'filesContainer',
37        'uploadTemplateId',
38        'downloadTemplateId'
39    );
40
41    // The UI version extends the file upload widget
42    // and adds complete user interface interaction:
43    $.widget('blueimp.fileupload', $.blueimp.fileupload, {
44
45        options: {
46            // By default, files added to the widget are uploaded as soon
47            // as the user clicks on the start buttons. To enable automatic
48            // uploads, set the following option to true:
49            autoUpload: false,
50            // The ID of the upload template:
51            uploadTemplateId: 'template-upload',
52            // The ID of the download template:
53            downloadTemplateId: 'template-download',
54            // The container for the list of files. If undefined, it is set to
55            // an element with class "files" inside of the widget element:
56            filesContainer: undefined,
57            // By default, files are appended to the files container.
58            // Set the following option to true, to prepend files instead:
59            prependFiles: false,
60            // The expected data type of the upload response, sets the dataType
61            // option of the $.ajax upload requests:
62            dataType: 'json',
63
64            // Function returning the current number of files,
65            // used by the maxNumberOfFiles validation:
66            getNumberOfFiles: function () {
67                return this.filesContainer.children().length;
68            },
69
70            // Callback to retrieve the list of files from the server response:
71            getFilesFromResponse: function (data) {
72                if (data.result && $.isArray(data.result.files)) {
73                    return data.result.files;
74                }
75                return [];
76            },
77
78            // The add callback is invoked as soon as files are added to the fileupload
79            // widget (via file input selection, drag & drop or add API call).
80            // See the basic file upload widget for more information:
81            add: function (e, data) {
82                var $this = $(this),
83                    that = $this.data('blueimp-fileupload') ||
84                        $this.data('fileupload'),
85                    options = that.options,
86                    files = data.files;
87                data.process(function () {
88                    return $this.fileupload('process', data);
89                }).always(function () {
90                    data.context = that._renderUpload(files).data('data', data);
91                    that._renderPreviews(data);
92                    options.filesContainer[
93                        options.prependFiles ? 'prepend' : 'append'
94                    ](data.context);
95                    that._forceReflow(data.context);
96                    that._transition(data.context).done(
97                        function () {
98                            if ((that._trigger('added', e, data) !== false) &&
99                                    (options.autoUpload || data.autoUpload) &&
100                                    data.autoUpload !== false && !data.files.error) {
101                                data.submit();
102                            }
103                        }
104                    );
105                });
106            },
107            // Callback for the start of each file upload request:
108            send: function (e, data) {
109                var that = $(this).data('blueimp-fileupload') ||
110                        $(this).data('fileupload');
111                if (data.context && data.dataType &&
112                        data.dataType.substr(0, 6) === 'iframe') {
113                    // Iframe Transport does not support progress events.
114                    // In lack of an indeterminate progress bar, we set
115                    // the progress to 100%, showing the full animated bar:
116                    data.context
117                        .find('.progress').addClass(
118                            !$.support.transition && 'progress-animated'
119                        )
120                        .attr('aria-valuenow', 100)
121                        .find('.bar').css(
122                            'width',
123                            '100%'
124                        );
125                }
126                return that._trigger('sent', e, data);
127            },
128            // Callback for successful uploads:
129            done: function (e, data) {
130                var that = $(this).data('blueimp-fileupload') ||
131                        $(this).data('fileupload'),
132                    getFilesFromResponse = data.getFilesFromResponse ||
133                        that.options.getFilesFromResponse,
134                    files = getFilesFromResponse(data),
135                    template,
136                    deferred;
137                if (data.context) {
138                    data.context.each(function (index) {
139                        var file = files[index] ||
140                                {error: 'Empty file upload result'},
141                            deferred = that._addFinishedDeferreds();
142                        that._transition($(this)).done(
143                            function () {
144                                var node = $(this);
145                                template = that._renderDownload([file])
146                                    .replaceAll(node);
147                                that._forceReflow(template);
148                                that._transition(template).done(
149                                    function () {
150                                        data.context = $(this);
151                                        that._trigger('completed', e, data);
152                                        that._trigger('finished', e, data);
153                                        deferred.resolve();
154                                    }
155                                );
156                            }
157                        );
158                    });
159                } else {
160                    template = that._renderDownload(files)
161                        .appendTo(that.options.filesContainer);
162                    that._forceReflow(template);
163                    deferred = that._addFinishedDeferreds();
164                    that._transition(template).done(
165                        function () {
166                            data.context = $(this);
167                            that._trigger('completed', e, data);
168                            that._trigger('finished', e, data);
169                            deferred.resolve();
170                        }
171                    );
172                }
173            },
174            // Callback for failed (abort or error) uploads:
175            fail: function (e, data) {
176                var that = $(this).data('blueimp-fileupload') ||
177                        $(this).data('fileupload'),
178                    template,
179                    deferred;
180                if (data.context) {
181                    data.context.each(function (index) {
182                        if (data.errorThrown !== 'abort') {
183                            var file = data.files[index];
184                            file.error = file.error || data.errorThrown ||
185                                true;
186                            deferred = that._addFinishedDeferreds();
187                            that._transition($(this)).done(
188                                function () {
189                                    var node = $(this);
190                                    template = that._renderDownload([file])
191                                        .replaceAll(node);
192                                    that._forceReflow(template);
193                                    that._transition(template).done(
194                                        function () {
195                                            data.context = $(this);
196                                            that._trigger('failed', e, data);
197                                            that._trigger('finished', e, data);
198                                            deferred.resolve();
199                                        }
200                                    );
201                                }
202                            );
203                        } else {
204                            deferred = that._addFinishedDeferreds();
205                            that._transition($(this)).done(
206                                function () {
207                                    $(this).remove();
208                                    that._trigger('failed', e, data);
209                                    that._trigger('finished', e, data);
210                                    deferred.resolve();
211                                }
212                            );
213                        }
214                    });
215                } else if (data.errorThrown !== 'abort') {
216                    data.context = that._renderUpload(data.files)
217                        .appendTo(that.options.filesContainer)
218                        .data('data', data);
219                    that._forceReflow(data.context);
220                    deferred = that._addFinishedDeferreds();
221                    that._transition(data.context).done(
222                        function () {
223                            data.context = $(this);
224                            that._trigger('failed', e, data);
225                            that._trigger('finished', e, data);
226                            deferred.resolve();
227                        }
228                    );
229                } else {
230                    that._trigger('failed', e, data);
231                    that._trigger('finished', e, data);
232                    that._addFinishedDeferreds().resolve();
233                }
234            },
235            // Callback for upload progress events:
236            progress: function (e, data) {
237                if (data.context) {
238                    var progress = Math.floor(data.loaded / data.total * 100);
239                    data.context.find('.progress')
240                        .attr('aria-valuenow', progress)
241                        .find('.bar').css(
242                            'width',
243                            progress + '%'
244                        );
245                }
246            },
247            // Callback for global upload progress events:
248            progressall: function (e, data) {
249                var $this = $(this),
250                    progress = Math.floor(data.loaded / data.total * 100),
251                    globalProgressNode = $this.find('.fileupload-progress'),
252                    extendedProgressNode = globalProgressNode
253                        .find('.progress-extended');
254                if (extendedProgressNode.length) {
255                    extendedProgressNode.html(
256                        ($this.data('blueimp-fileupload') || $this.data('fileupload'))
257                            ._renderExtendedProgress(data)
258                    );
259                }
260                globalProgressNode
261                    .find('.progress')
262                    .attr('aria-valuenow', progress)
263                    .find('.bar').css(
264                        'width',
265                        progress + '%'
266                    );
267            },
268            // Callback for uploads start, equivalent to the global ajaxStart event:
269            start: function (e) {
270                var that = $(this).data('blueimp-fileupload') ||
271                        $(this).data('fileupload');
272                that._resetFinishedDeferreds();
273                that._transition($(this).find('.fileupload-progress')).done(
274                    function () {
275                        that._trigger('started', e);
276                    }
277                );
278            },
279            // Callback for uploads stop, equivalent to the global ajaxStop event:
280            stop: function (e) {
281                var that = $(this).data('blueimp-fileupload') ||
282                        $(this).data('fileupload'),
283                    deferred = that._addFinishedDeferreds();
284                $.when.apply($, that._getFinishedDeferreds())
285                    .done(function () {
286                        that._trigger('stopped', e);
287                    });
288                that._transition($(this).find('.fileupload-progress')).done(
289                    function () {
290                        $(this).find('.progress')
291                            .attr('aria-valuenow', '0')
292                            .find('.bar').css('width', '0%');
293                        $(this).find('.progress-extended').html('&nbsp;');
294                        deferred.resolve();
295                    }
296                );
297            },
298            processstart: function () {
299                $(this).addClass('fileupload-processing');
300            },
301            processstop: function () {
302                $(this).removeClass('fileupload-processing');
303            },
304            // Callback for file deletion:
305            destroy: function (e, data) {
306                var that = $(this).data('blueimp-fileupload') ||
307                        $(this).data('fileupload');
308                if (data.url) {
309                    $.ajax(data).done(function () {
310                        that._transition(data.context).done(
311                            function () {
312                                $(this).remove();
313                                that._trigger('destroyed', e, data);
314                            }
315                        );
316                    });
317                }
318            }
319        },
320
321        _resetFinishedDeferreds: function () {
322            this._finishedUploads = [];
323        },
324
325        _addFinishedDeferreds: function (deferred) {
326            if (!deferred) {
327                deferred = $.Deferred();
328            }
329            this._finishedUploads.push(deferred);
330            return deferred;
331        },
332
333        _getFinishedDeferreds: function () {
334            return this._finishedUploads;
335        },
336
337        // Link handler, that allows to download files
338        // by drag & drop of the links to the desktop:
339        _enableDragToDesktop: function () {
340            var link = $(this),
341                url = link.prop('href'),
342                name = link.prop('download'),
343                type = 'application/octet-stream';
344            link.bind('dragstart', function (e) {
345                try {
346                    e.originalEvent.dataTransfer.setData(
347                        'DownloadURL',
348                        [type, name, url].join(':')
349                    );
350                } catch (ignore) {}
351            });
352        },
353
354        _formatFileSize: function (bytes) {
355            if (typeof bytes !== 'number') {
356                return '';
357            }
358            if (bytes >= 1000000000) {
359                return (bytes / 1000000000).toFixed(2) + ' GB';
360            }
361            if (bytes >= 1000000) {
362                return (bytes / 1000000).toFixed(2) + ' MB';
363            }
364            return (bytes / 1000).toFixed(2) + ' KB';
365        },
366
367        _formatBitrate: function (bits) {
368            if (typeof bits !== 'number') {
369                return '';
370            }
371            if (bits >= 1000000000) {
372                return (bits / 1000000000).toFixed(2) + ' Gbit/s';
373            }
374            if (bits >= 1000000) {
375                return (bits / 1000000).toFixed(2) + ' Mbit/s';
376            }
377            if (bits >= 1000) {
378                return (bits / 1000).toFixed(2) + ' kbit/s';
379            }
380            return bits.toFixed(2) + ' bit/s';
381        },
382
383        _formatTime: function (seconds) {
384            var date = new Date(seconds * 1000),
385                days = Math.floor(seconds / 86400);
386            days = days ? days + 'd ' : '';
387            return days +
388                ('0' + date.getUTCHours()).slice(-2) + ':' +
389                ('0' + date.getUTCMinutes()).slice(-2) + ':' +
390                ('0' + date.getUTCSeconds()).slice(-2);
391        },
392
393        _formatPercentage: function (floatValue) {
394            return (floatValue * 100).toFixed(2) + ' %';
395        },
396
397        _renderExtendedProgress: function (data) {
398            return this._formatBitrate(data.bitrate) + ' | ' +
399                this._formatTime(
400                    (data.total - data.loaded) * 8 / data.bitrate
401                ) + ' | ' +
402                this._formatPercentage(
403                    data.loaded / data.total
404                ) + ' | ' +
405                this._formatFileSize(data.loaded) + ' / ' +
406                this._formatFileSize(data.total);
407        },
408
409        _renderTemplate: function (func, files) {
410            if (!func) {
411                return $();
412            }
413            var result = func({
414                files: files,
415                formatFileSize: this._formatFileSize,
416                options: this.options
417            });
418            if (result instanceof $) {
419                return result;
420            }
421            return $(this.options.templatesContainer).html(result).children();
422        },
423
424        _renderPreviews: function (data) {
425            data.context.find('.preview').each(function (index, elm) {
426                $(elm).append(data.files[index].preview);
427            });
428        },
429
430        _renderUpload: function (files) {
431            return this._renderTemplate(
432                this.options.uploadTemplate,
433                files
434            );
435        },
436
437        _renderDownload: function (files) {
438            return this._renderTemplate(
439                this.options.downloadTemplate,
440                files
441            ).find('a[download]').each(this._enableDragToDesktop).end();
442        },
443
444        _startHandler: function (e) {
445            e.preventDefault();
446            var button = $(e.currentTarget),
447                template = button.closest('.template-upload'),
448                data = template.data('data');
449            if (data && data.submit && !data.jqXHR && data.submit()) {
450                button.prop('disabled', true);
451            }
452        },
453
454        _cancelHandler: function (e) {
455            e.preventDefault();
456            var template = $(e.currentTarget).closest('.template-upload'),
457                data = template.data('data') || {};
458            if (!data.jqXHR) {
459                data.errorThrown = 'abort';
460                this._trigger('fail', e, data);
461            } else {
462                data.jqXHR.abort();
463            }
464        },
465
466        _deleteHandler: function (e) {
467            e.preventDefault();
468            var button = $(e.currentTarget);
469            this._trigger('destroy', e, $.extend({
470                context: button.closest('.template-download'),
471                type: 'DELETE'
472            }, button.data()));
473        },
474
475        _forceReflow: function (node) {
476            return $.support.transition && node.length &&
477                node[0].offsetWidth;
478        },
479
480        _transition: function (node) {
481            var dfd = $.Deferred();
482            if ($.support.transition && node.hasClass('fade') && node.is(':visible')) {
483                node.bind(
484                    $.support.transition.end,
485                    function (e) {
486                        // Make sure we don't respond to other transitions events
487                        // in the container element, e.g. from button elements:
488                        if (e.target === node[0]) {
489                            node.unbind($.support.transition.end);
490                            dfd.resolveWith(node);
491                        }
492                    }
493                ).toggleClass('in');
494            } else {
495                node.toggleClass('in');
496                dfd.resolveWith(node);
497            }
498            return dfd;
499        },
500
501        _initButtonBarEventHandlers: function () {
502            var fileUploadButtonBar = this.element.find('.fileupload-buttonbar'),
503                filesList = this.options.filesContainer;
504            this._on(fileUploadButtonBar.find('.start'), {
505                click: function (e) {
506                    e.preventDefault();
507                    filesList.find('.start').click();
508                }
509            });
510            this._on(fileUploadButtonBar.find('.cancel'), {
511                click: function (e) {
512                    e.preventDefault();
513                    filesList.find('.cancel').click();
514                }
515            });
516            this._on(fileUploadButtonBar.find('.delete'), {
517                click: function (e) {
518                    e.preventDefault();
519                    filesList.find('.toggle:checked')
520                        .closest('.template-download')
521                        .find('.delete').click();
522                    fileUploadButtonBar.find('.toggle')
523                        .prop('checked', false);
524                }
525            });
526            this._on(fileUploadButtonBar.find('.toggle'), {
527                change: function (e) {
528                    filesList.find('.toggle').prop(
529                        'checked',
530                        $(e.currentTarget).is(':checked')
531                    );
532                }
533            });
534        },
535
536        _destroyButtonBarEventHandlers: function () {
537            this._off(
538                this.element.find('.fileupload-buttonbar')
539                    .find('.start, .cancel, .delete'),
540                'click'
541            );
542            this._off(
543                this.element.find('.fileupload-buttonbar .toggle'),
544                'change.'
545            );
546        },
547
548        _initEventHandlers: function () {
549            this._super();
550            this._on(this.options.filesContainer, {
551                'click .start': this._startHandler,
552                'click .cancel': this._cancelHandler,
553                'click .delete': this._deleteHandler
554            });
555            this._initButtonBarEventHandlers();
556        },
557
558        _destroyEventHandlers: function () {
559            this._destroyButtonBarEventHandlers();
560            this._off(this.options.filesContainer, 'click');
561            this._super();
562        },
563
564        _enableFileInputButton: function () {
565            this.element.find('.fileinput-button input')
566                .prop('disabled', false)
567                .parent().removeClass('disabled');
568        },
569
570        _disableFileInputButton: function () {
571            this.element.find('.fileinput-button input')
572                .prop('disabled', true)
573                .parent().addClass('disabled');
574        },
575
576        _initTemplates: function () {
577            var options = this.options;
578            options.templatesContainer = this.document[0].createElement(
579                options.filesContainer.prop('nodeName')
580            );
581            if (tmpl) {
582                if (options.uploadTemplateId) {
583                    options.uploadTemplate = tmpl(options.uploadTemplateId);
584                }
585                if (options.downloadTemplateId) {
586                    options.downloadTemplate = tmpl(options.downloadTemplateId);
587                }
588            }
589        },
590
591        _initFilesContainer: function () {
592            var options = this.options;
593            if (options.filesContainer === undefined) {
594                options.filesContainer = this.element.find('.files');
595            } else if (!(options.filesContainer instanceof $)) {
596                options.filesContainer = $(options.filesContainer);
597            }
598        },
599
600        _initSpecialOptions: function () {
601            this._super();
602            this._initFilesContainer();
603            this._initTemplates();
604        },
605
606        _create: function () {
607            this._super();
608            this._resetFinishedDeferreds();
609        },
610
611        enable: function () {
612            var wasDisabled = false;
613            if (this.options.disabled) {
614                wasDisabled = true;
615            }
616            this._super();
617            if (wasDisabled) {
618                this.element.find('input, button').prop('disabled', false);
619                this._enableFileInputButton();
620            }
621        },
622
623        disable: function () {
624            if (!this.options.disabled) {
625                this.element.find('input, button').prop('disabled', true);
626                this._disableFileInputButton();
627            }
628            this._super();
629        }
630
631    });
632
633}));
Note: See TracBrowser for help on using the repository browser.

Sites map