2 * jQuery File Upload User Interface Plugin 5.0.13
3 * https://github.com/blueimp/jQuery-File-Upload
5 * Copyright 2010, Sebastian Tschan
8 * Licensed under the MIT license:
9 * http://creativecommons.org/licenses/MIT/
12 /*jslint nomen: true, unparam: true, regexp: true */
13 /*global window, document, URL, webkitURL, FileReader, jQuery */
18 // The UI version extends the basic fileupload widget and adds
19 // a complete user interface based on the given upload/download
21 $.widget('blueimpUI.fileupload', $.blueimp.fileupload, {
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:
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:
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:
49 }).data('data', data);
50 if ((that.options.autoUpload || data.autoUpload) &&
52 data.jqXHR = data.submit();
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)) {
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(
74 // Callback for successful uploads:
75 done: function (e, data) {
76 var that = $(this).data('fileupload');
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')
86 // Fix for IE7 and lower:
92 that._renderDownload(data.result)
93 .css('display', 'none')
94 .appendTo($(this).find('.files'))
96 // Fix for IE7 and lower:
101 // Callback for failed (abort or error) uploads:
102 fail: function (e, data) {
103 var that = $(this).data('fileupload');
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
111 that._renderDownload([file])
112 .css('display', 'none')
114 .fadeIn(function () {
115 // Fix for IE7 and lower:
119 data.context.remove();
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:
130 }).data('data', data);
133 // Callback for upload progress events:
134 progress: function (e, data) {
136 data.context.find('.ui-progressbar').progressbar(
138 parseInt(data.loaded / data.total * 100, 10)
142 // Callback for global upload progress events:
143 progressall: function (e, data) {
144 $(this).find('.fileupload-progressbar').progressbar(
146 parseInt(data.loaded / data.total * 100, 10)
149 // Callback for uploads start, equivalent to the global ajaxStart event:
151 $(this).find('.fileupload-progressbar')
152 .progressbar('value', 0).fadeIn();
154 // Callback for uploads stop, equivalent to the global ajaxStop event:
156 $(this).find('.fileupload-progressbar').fadeOut();
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;
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;
176 // Link handler, that allows to download files
177 // by drag & drop of the links to the desktop:
178 _enableDragToDesktop: function () {
180 url = link.prop('href'),
181 name = decodeURIComponent(url.split('/').pop())
183 type = 'application/octet-stream';
184 link.bind('dragstart', function (e) {
186 e.originalEvent.dataTransfer.setData(
188 [type, name, url].join(':')
194 _hasError: function (file) {
201 _validate: function (files) {
204 $.each(files, function (index, file) {
205 file.error = that._hasError(file);
211 _uploadTemplateHelper: function (file) {
215 _renderUploadTemplate: function (files) {
218 this.options.uploadTemplate,
219 $.map(files, function (file) {
220 return that._uploadTemplateHelper(file);
225 _renderUpload: function (files) {
227 options = this.options,
228 tmpl = this._renderUploadTemplate(files);
229 if (!(tmpl instanceof $)) {
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()
237 tmpl.find('.start button').slice(
238 this.options.autoUpload ? 0 : 1
239 ).remove().end().first()
242 icons: {primary: 'ui-icon-circle-arrow-e'}
244 tmpl.find('.cancel button').slice(1).remove().end().first()
247 icons: {primary: 'ui-icon-cancel'}
252 _downloadTemplateHelper: function (file) {
256 _renderDownloadTemplate: function (files) {
259 this.options.downloadTemplate,
260 $.map(files, function (file) {
261 return that._downloadTemplateHelper(file);
266 _renderDownload: function (files) {
267 var tmpl = this._renderDownloadTemplate(files);
268 if (!(tmpl instanceof $)) {
271 tmpl.css('display', 'none');
272 tmpl.find('a').each(this._enableDragToDesktop);
276 _startHandler: function (e) {
278 var tmpl = $(this).closest('.template-upload'),
279 data = tmpl.data('data');
280 if (data && data.submit && !data.jqXHR) {
281 data.jqXHR = data.submit();
286 _cancelHandler: function (e) {
288 var tmpl = $(this).closest('.template-upload'),
289 data = tmpl.data('data') || {};
291 data.errorThrown = 'abort';
292 e.data.fileupload._trigger('fail', e, data);
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')
304 'click.' + this.options.namespace,
308 filesList.find('.cancel button')
310 'click.' + this.options.namespace,
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);
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
334 if (this.options.downloadTemplate instanceof $ &&
335 !this.options.downloadTemplate.length) {
336 this.options.downloadTemplate = $(
337 this.options.downloadTemplate.selector
342 _create: function () {
343 $.blueimp.fileupload.prototype._create.call(this);
344 this._initTemplates();
347 enable: function () {
348 $.blueimp.fileupload.prototype.enable.call(this);
351 disable: function () {
352 $.blueimp.fileupload.prototype.disable.call(this);