]> git.vanrenterghem.biz Git - git.ikiwiki.info.git/blob - underlays/attachment/ikiwiki/jquery.fileupload-ui.js
link to an actual implementation of the "Flip wikilinks" change
[git.ikiwiki.info.git] / underlays / attachment / ikiwiki / jquery.fileupload-ui.js
1 /*
2  * jQuery File Upload User Interface Plugin 5.0.13
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://creativecommons.org/licenses/MIT/
10  */
12 /*jslint nomen: true, unparam: true, regexp: true */
13 /*global window, document, URL, webkitURL, FileReader, jQuery */
15 (function ($) {
16     'use strict';
17     
18     // The UI version extends the basic fileupload widget and adds
19     // a complete user interface based on the given upload/download
20     // templates.
21     $.widget('blueimpUI.fileupload', $.blueimp.fileupload, {
22         
23         options: {
24             // By default, files added to the widget are uploaded as soon
25             // as the user clicks on the start buttons. To enable automatic
26             // uploads, set the following option to true:
27             autoUpload: true,
28             // The file upload template that is given as first argument to the
29             // jQuery.tmpl method to render the file uploads:
30             uploadTemplate: $('#template-upload'),
31             // The file download template, that is given as first argument to the
32             // jQuery.tmpl method to render the file downloads:
33             downloadTemplate: $('#template-download'),
34             // The expected data type of the upload response, sets the dataType
35             // option of the $.ajax upload requests:
36             dataType: 'json',
37             
38             // The add callback is invoked as soon as files are added to the fileupload
39             // widget (via file input selection, drag & drop or add API call).
40             // See the basic file upload widget for more information:
41             add: function (e, data) {
42                 var that = $(this).data('fileupload');
43                 data.isAdjusted = true;
44                 data.isValidated = that._validate(data.files);
45                 data.context = that._renderUpload(data.files)
46                     .appendTo($(this).find('.files')).fadeIn(function () {
47                         // Fix for IE7 and lower:
48                         $(this).show();
49                     }).data('data', data);
50                 if ((that.options.autoUpload || data.autoUpload) &&
51                         data.isValidated) {
52                     data.jqXHR = data.submit();
53                 }
54             },
55             // Callback for the start of each file upload request:
56             send: function (e, data) {
57                 if (!data.isValidated) {
58                     var that = $(this).data('fileupload');
59                     if (!that._validate(data.files)) {
60                         return false;
61                     }
62                 }
63                 if (data.context && data.dataType &&
64                         data.dataType.substr(0, 6) === 'iframe') {
65                     // Iframe Transport does not support progress events.
66                     // In lack of an indeterminate progress bar, we set
67                     // the progress to 100%, showing the full animated bar:
68                     data.context.find('.ui-progressbar').progressbar(
69                         'value',
70                         parseInt(100, 10)
71                     );
72                 }
73             },
74             // Callback for successful uploads:
75             done: function (e, data) {
76                 var that = $(this).data('fileupload');
77                 if (data.context) {
78                     data.context.each(function (index) {
79                         var file = ($.isArray(data.result) &&
80                                 data.result[index]) || {error: 'emptyResult'};
81                         $(this).fadeOut(function () {
82                             that._renderDownload([file])
83                                 .css('display', 'none')
84                                 .replaceAll(this)
85                                 .fadeIn(function () {
86                                     // Fix for IE7 and lower:
87                                     $(this).show();
88                                 });
89                         });
90                     });
91                 } else {
92                     that._renderDownload(data.result)
93                         .css('display', 'none')
94                         .appendTo($(this).find('.files'))
95                         .fadeIn(function () {
96                             // Fix for IE7 and lower:
97                             $(this).show();
98                         });
99                 }
100             },
101             // Callback for failed (abort or error) uploads:
102             fail: function (e, data) {
103                 var that = $(this).data('fileupload');
104                 if (data.context) {
105                     data.context.each(function (index) {
106                         $(this).fadeOut(function () {
107                             if (data.errorThrown !== 'abort') {
108                                 var file = data.files[index];
109                                 file.error = file.error || data.errorThrown
110                                     || true;
111                                 that._renderDownload([file])
112                                     .css('display', 'none')
113                                     .replaceAll(this)
114                                     .fadeIn(function () {
115                                         // Fix for IE7 and lower:
116                                         $(this).show();
117                                     });
118                             } else {
119                                 data.context.remove();
120                             }
121                         });
122                     });
123                 } else if (data.errorThrown !== 'abort') {
124                     data.context = that._renderUpload(data.files)
125                         .css('display', 'none')
126                         .appendTo($(this).find('.files'))
127                         .fadeIn(function () {
128                             // Fix for IE7 and lower:
129                             $(this).show();
130                         }).data('data', data);
131                 }
132             },
133             // Callback for upload progress events:
134             progress: function (e, data) {
135                 if (data.context) {
136                     data.context.find('.ui-progressbar').progressbar(
137                         'value',
138                         parseInt(data.loaded / data.total * 100, 10)
139                     );
140                 }
141             },
142             // Callback for global upload progress events:
143             progressall: function (e, data) {
144                 $(this).find('.fileupload-progressbar').progressbar(
145                     'value',
146                     parseInt(data.loaded / data.total * 100, 10)
147                 );
148             },
149             // Callback for uploads start, equivalent to the global ajaxStart event:
150             start: function () {
151                 $(this).find('.fileupload-progressbar')
152                     .progressbar('value', 0).fadeIn();
153             },
154             // Callback for uploads stop, equivalent to the global ajaxStop event:
155             stop: function () {
156                 $(this).find('.fileupload-progressbar').fadeOut();
157             },
158         },
159         
160         _createObjectURL: function (file) {
161             var undef = 'undefined',
162                 urlAPI = (typeof window.createObjectURL !== undef && window) ||
163                     (typeof URL !== undef && URL) ||
164                     (typeof webkitURL !== undef && webkitURL);
165             return urlAPI ? urlAPI.createObjectURL(file) : false;
166         },
167         
168         _revokeObjectURL: function (url) {
169             var undef = 'undefined',
170                 urlAPI = (typeof window.revokeObjectURL !== undef && window) ||
171                     (typeof URL !== undef && URL) ||
172                     (typeof webkitURL !== undef && webkitURL);
173             return urlAPI ? urlAPI.revokeObjectURL(url) : false;
174         },
176         // Link handler, that allows to download files
177         // by drag & drop of the links to the desktop:
178         _enableDragToDesktop: function () {
179             var link = $(this),
180                 url = link.prop('href'),
181                 name = decodeURIComponent(url.split('/').pop())
182                     .replace(/:/g, '-'),
183                 type = 'application/octet-stream';
184             link.bind('dragstart', function (e) {
185                 try {
186                     e.originalEvent.dataTransfer.setData(
187                         'DownloadURL',
188                         [type, name, url].join(':')
189                     );
190                 } catch (err) {}
191             });
192         },
194         _hasError: function (file) {
195             if (file.error) {
196                 return file.error;
197             }
198             return null;
199         },
201         _validate: function (files) {
202             var that = this,
203                 valid;
204             $.each(files, function (index, file) {
205                 file.error = that._hasError(file);
206                 valid = !file.error;
207             });
208             return valid;
209         },
211         _uploadTemplateHelper: function (file) {
212             return file;
213         },
215         _renderUploadTemplate: function (files) {
216             var that = this;
217             return $.tmpl(
218                 this.options.uploadTemplate,
219                 $.map(files, function (file) {
220                     return that._uploadTemplateHelper(file);
221                 })
222             );
223         },
225         _renderUpload: function (files) {
226             var that = this,
227                 options = this.options,
228                 tmpl = this._renderUploadTemplate(files);
229             if (!(tmpl instanceof $)) {
230                 return $();
231             }
232             tmpl.css('display', 'none');
233             // .slice(1).remove().end().first() removes all but the first
234             // element and selects only the first for the jQuery collection:
235             tmpl.find('.progress div').slice(1).remove().end().first()
236                 .progressbar();
237             tmpl.find('.start button').slice(
238                 this.options.autoUpload ? 0 : 1
239             ).remove().end().first()
240                 .button({
241                     text: false,
242                     icons: {primary: 'ui-icon-circle-arrow-e'}
243                 });
244             tmpl.find('.cancel button').slice(1).remove().end().first()
245                 .button({
246                     text: false,
247                     icons: {primary: 'ui-icon-cancel'}
248                 });
249             return tmpl;
250         },
252         _downloadTemplateHelper: function (file) {
253             return file;
254         },
256         _renderDownloadTemplate: function (files) {
257             var that = this;
258             return $.tmpl(
259                 this.options.downloadTemplate,
260                 $.map(files, function (file) {
261                     return that._downloadTemplateHelper(file);
262                 })
263             );
264         },
265         
266         _renderDownload: function (files) {
267             var tmpl = this._renderDownloadTemplate(files);
268             if (!(tmpl instanceof $)) {
269                 return $();
270             }
271             tmpl.css('display', 'none');
272             tmpl.find('a').each(this._enableDragToDesktop);
273             return tmpl;
274         },
275         
276         _startHandler: function (e) {
277             e.preventDefault();
278             var tmpl = $(this).closest('.template-upload'),
279                 data = tmpl.data('data');
280             if (data && data.submit && !data.jqXHR) {
281                 data.jqXHR = data.submit();
282                 $(this).fadeOut();
283             }
284         },
285         
286         _cancelHandler: function (e) {
287             e.preventDefault();
288             var tmpl = $(this).closest('.template-upload'),
289                 data = tmpl.data('data') || {};
290             if (!data.jqXHR) {
291                 data.errorThrown = 'abort';
292                 e.data.fileupload._trigger('fail', e, data);
293             } else {
294                 data.jqXHR.abort();
295             }
296         },
297         
298         _initEventHandlers: function () {
299             $.blueimp.fileupload.prototype._initEventHandlers.call(this);
300             var filesList = this.element.find('.files'),
301                 eventData = {fileupload: this};
302             filesList.find('.start button')
303                 .live(
304                     'click.' + this.options.namespace,
305                     eventData,
306                     this._startHandler
307                 );
308             filesList.find('.cancel button')
309                 .live(
310                     'click.' + this.options.namespace,
311                     eventData,
312                     this._cancelHandler
313                 );
314         },
315         
316         _destroyEventHandlers: function () {
317             var filesList = this.element.find('.files');
318             filesList.find('.start button')
319                 .die('click.' + this.options.namespace);
320             filesList.find('.cancel button')
321                 .die('click.' + this.options.namespace);
322             $.blueimp.fileupload.prototype._destroyEventHandlers.call(this);
323         },
325         _initTemplates: function () {
326             // Handle cases where the templates are defined
327             // after the widget library has been included:
328             if (this.options.uploadTemplate instanceof $ &&
329                     !this.options.uploadTemplate.length) {
330                 this.options.uploadTemplate = $(
331                     this.options.uploadTemplate.selector
332                 );
333             }
334             if (this.options.downloadTemplate instanceof $ &&
335                     !this.options.downloadTemplate.length) {
336                 this.options.downloadTemplate = $(
337                     this.options.downloadTemplate.selector
338                 );
339             }
340         },
342         _create: function () {
343             $.blueimp.fileupload.prototype._create.call(this);
344             this._initTemplates();
345         },
346         
347         enable: function () {
348             $.blueimp.fileupload.prototype.enable.call(this);
349         },
350         
351         disable: function () {
352             $.blueimp.fileupload.prototype.disable.call(this);
353         }
355     });
357 }(jQuery));