jquery.fileupload-rails 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Readme.md ADDED
@@ -0,0 +1,14 @@
1
+ # jQuery File Upload for Rails
2
+
3
+ jQuery File Upload is a very well designed cross-browser solution for modern file uploading with pure JavaScript.
4
+ The plugin is developed by Sebastian Tschan (@blueimp) and well maintained.
5
+
6
+ This is a simple gem package for this plugin.
7
+
8
+ [See the original project page](https://github.com/blueimp/jQuery-File-Upload) for reference & documentation.
9
+
10
+ ## Changelog
11
+
12
+ 0.1.0. jquery.fileupload 5.9.0 and jquery.fileupload-ui 6.6.2, added readme.
13
+
14
+ 0.0.1. jquery.fileupload 5.5.2 and jquery.fileupload-ui 5.1.1.
@@ -1,5 +1,5 @@
1
1
  module JqueryFileUpload
2
2
  module Rails
3
- VERSION = "0.0.1"
3
+ VERSION = "0.1.0"
4
4
  end
5
5
  end
@@ -0,0 +1,160 @@
1
+ /*
2
+ * jQuery File Upload Image Processing Plugin 1.0.6
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2012, 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, document */
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
+ 'load-image',
22
+ 'canvas-to-blob',
23
+ './jquery.fileupload'
24
+ ], factory);
25
+ } else {
26
+ // Browser globals:
27
+ factory(
28
+ window.jQuery,
29
+ window.loadImage,
30
+ window.canvasToBlob
31
+ );
32
+ }
33
+ }(function ($, loadImage, canvasToBlob) {
34
+ 'use strict';
35
+
36
+ // The File Upload IP version extends the basic fileupload widget
37
+ // with image processing functionality:
38
+ $.widget('blueimpIP.fileupload', $.blueimp.fileupload, {
39
+
40
+ options: {
41
+ // The regular expression to define which image files are to be
42
+ // resized, given that the browser supports the operation:
43
+ resizeSourceFileTypes: /^image\/(gif|jpeg|png)$/,
44
+ // The maximum file size of images that are to be resized:
45
+ resizeSourceMaxFileSize: 20000000, // 20MB
46
+ // The maximum width of the resized images:
47
+ resizeMaxWidth: undefined,
48
+ // The maximum height of the resized images:
49
+ resizeMaxHeight: undefined,
50
+ // The minimum width of the resized images:
51
+ resizeMinWidth: undefined,
52
+ // The minimum height of the resized images:
53
+ resizeMinHeight: undefined,
54
+
55
+ // The add callback is invoked as soon as files are added to the fileupload
56
+ // widget (via file input selection, drag & drop or add API call).
57
+ // See the basic file upload widget for more information:
58
+ add: function (e, data) {
59
+ $(this).fileupload('resize', data).done(function () {
60
+ data.submit();
61
+ });
62
+ }
63
+ },
64
+
65
+ // Resizes the image file at the given index and stores the created blob
66
+ // at the original position of the files list, returns a Promise object:
67
+ _resizeImage: function (files, index, options) {
68
+ var that = this,
69
+ file = files[index],
70
+ deferred = $.Deferred(),
71
+ canvas,
72
+ blob;
73
+ options = options || this.options;
74
+ loadImage(
75
+ file,
76
+ function (img) {
77
+ var width = img.width,
78
+ height = img.height;
79
+ canvas = loadImage.scale(img, {
80
+ maxWidth: options.resizeMaxWidth,
81
+ maxHeight: options.resizeMaxHeight,
82
+ minWidth: options.resizeMinWidth,
83
+ minHeight: options.resizeMinHeight,
84
+ canvas: true
85
+ });
86
+ if (width !== canvas.width || height !== canvas.height) {
87
+ canvasToBlob(canvas, function (blob) {
88
+ if (!blob.name) {
89
+ if (file.type === blob.type) {
90
+ blob.name = file.name;
91
+ } else if (file.name) {
92
+ blob.name = file.name.replace(
93
+ /\..+$/,
94
+ '.' + blob.type.substr(6)
95
+ );
96
+ }
97
+ }
98
+ files[index] = blob;
99
+ deferred.resolveWith(that);
100
+ }, file);
101
+ } else {
102
+ deferred.resolveWith(that);
103
+ }
104
+ }
105
+ );
106
+ return deferred.promise();
107
+ },
108
+
109
+ // Resizes the images given as files property of the data parameter,
110
+ // returns a Promise object that allows to bind a done handler, which
111
+ // will be invoked after processing all images is done:
112
+ resize: function (data) {
113
+ var that = this,
114
+ options = $.extend({}, this.options, data),
115
+ resizeAll = $.type(options.resizeSourceMaxFileSize) !== 'number',
116
+ isXHRUpload = this._isXHRUpload(options);
117
+ $.each(data.files, function (index, file) {
118
+ if (isXHRUpload && that._resizeSupport &&
119
+ (options.resizeMaxWidth || options.resizeMaxHeight ||
120
+ options.resizeMinWidth || options.resizeMinHeight) &&
121
+ (resizeAll || file.size < options.resizeSourceMaxFileSize) &&
122
+ options.resizeSourceFileTypes.test(file.type)) {
123
+ that._processing += 1;
124
+ if (that._processing === 1) {
125
+ that.element.addClass('fileupload-processing');
126
+ }
127
+ that._processingQueue = that._processingQueue.pipe(function () {
128
+ var deferred = $.Deferred();
129
+ that._resizeImage(
130
+ data.files,
131
+ index,
132
+ options
133
+ ).done(function () {
134
+ that._processing -= 1;
135
+ if (that._processing === 0) {
136
+ that.element
137
+ .removeClass('fileupload-processing');
138
+ }
139
+ deferred.resolveWith(that);
140
+ });
141
+ return deferred.promise();
142
+ });
143
+ }
144
+ });
145
+ return this._processingQueue;
146
+ },
147
+
148
+ _create: function () {
149
+ $.blueimp.fileupload.prototype._create.call(this);
150
+ this._processing = 0;
151
+ this._processingQueue = $.Deferred().resolveWith(this).promise();
152
+ this._resizeSupport = canvasToBlob && canvasToBlob(
153
+ document.createElement('canvas'),
154
+ $.noop
155
+ );
156
+ }
157
+
158
+ });
159
+
160
+ }));
@@ -1,24 +1,42 @@
1
1
  /*
2
- * jQuery File Upload User Interface Plugin 5.1.1
2
+ * jQuery File Upload User Interface Plugin 6.6.2
3
3
  * https://github.com/blueimp/jQuery-File-Upload
4
4
  *
5
5
  * Copyright 2010, Sebastian Tschan
6
6
  * https://blueimp.net
7
7
  *
8
8
  * Licensed under the MIT license:
9
- * http://creativecommons.org/licenses/MIT/
9
+ * http://www.opensource.org/licenses/MIT
10
10
  */
11
11
 
12
12
  /*jslint nomen: true, unparam: true, regexp: true */
13
- /*global window, document, URL, webkitURL, FileReader, jQuery */
13
+ /*global define, window, document, URL, webkitURL, FileReader */
14
14
 
15
- (function ($) {
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
+ 'load-image',
23
+ './jquery.fileupload-ip'
24
+ ], factory);
25
+ } else {
26
+ // Browser globals:
27
+ factory(
28
+ window.jQuery,
29
+ window.tmpl,
30
+ window.loadImage
31
+ );
32
+ }
33
+ }(function ($, tmpl, loadImage) {
16
34
  'use strict';
17
35
 
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, {
36
+ // The UI version extends the IP (image processing) version or the basic
37
+ // file upload widget and adds complete user interface interaction:
38
+ var parentWidget = ($.blueimpIP || $.blueimp).fileupload;
39
+ $.widget('blueimpUI.fileupload', parentWidget, {
22
40
 
23
41
  options: {
24
42
  // By default, files added to the widget are uploaded as soon
@@ -31,13 +49,15 @@
31
49
  // The maximum allowed file size:
32
50
  maxFileSize: undefined,
33
51
  // The minimum allowed file size:
34
- minFileSize: 1,
52
+ minFileSize: undefined,
35
53
  // The regular expression for allowed file types, matches
36
54
  // against either file type or file name:
37
55
  acceptFileTypes: /.+$/i,
38
56
  // The regular expression to define for which files a preview
39
57
  // image is shown, matched against the file type:
40
- previewFileTypes: /^image\/(gif|jpeg|png)$/,
58
+ previewSourceFileTypes: /^image\/(gif|jpeg|png)$/,
59
+ // The maximum file size of images that are to be displayed as preview:
60
+ previewSourceMaxFileSize: 5000000, // 5MB
41
61
  // The maximum width of the preview images:
42
62
  previewMaxWidth: 80,
43
63
  // The maximum height of the preview images:
@@ -46,12 +66,10 @@
46
66
  // if supported by the browser. Set the following option to false
47
67
  // to always display preview images as img elements:
48
68
  previewAsCanvas: true,
49
- // The file upload template that is given as first argument to the
50
- // jQuery.tmpl method to render the file uploads:
51
- uploadTemplate: $('#template-upload'),
52
- // The file download template, that is given as first argument to the
53
- // jQuery.tmpl method to render the file downloads:
54
- downloadTemplate: $('#template-download'),
69
+ // The ID of the upload template:
70
+ uploadTemplateId: 'template-upload',
71
+ // The ID of the download template:
72
+ downloadTemplateId: 'template-download',
55
73
  // The expected data type of the upload response, sets the dataType
56
74
  // option of the $.ajax upload requests:
57
75
  dataType: 'json',
@@ -60,24 +78,33 @@
60
78
  // widget (via file input selection, drag & drop or add API call).
61
79
  // See the basic file upload widget for more information:
62
80
  add: function (e, data) {
63
- var that = $(this).data('fileupload');
64
- that._adjustMaxNumberOfFiles(-data.files.length);
81
+ var that = $(this).data('fileupload'),
82
+ options = that.options,
83
+ files = data.files;
84
+ that._adjustMaxNumberOfFiles(-files.length);
65
85
  data.isAdjusted = true;
66
- data.isValidated = that._validate(data.files);
67
- data.context = that._renderUpload(data.files)
68
- .appendTo($(this).find('.files')).fadeIn(function () {
69
- // Fix for IE7 and lower:
70
- $(this).show();
71
- }).data('data', data);
72
- if ((that.options.autoUpload || data.autoUpload) &&
73
- data.isValidated) {
74
- data.submit();
75
- }
86
+ $(this).fileupload('resize', data).done(data, function () {
87
+ data.files.valid = data.isValidated = that._validate(files);
88
+ data.context = that._renderUpload(files)
89
+ .appendTo(options.filesContainer)
90
+ .data('data', data);
91
+ that._renderPreviews(files, data.context);
92
+ that._forceReflow(data.context);
93
+ that._transition(data.context).done(
94
+ function () {
95
+ if ((that._trigger('added', e, data) !== false) &&
96
+ (options.autoUpload || data.autoUpload) &&
97
+ data.autoUpload !== false && data.isValidated) {
98
+ data.submit();
99
+ }
100
+ }
101
+ );
102
+ });
76
103
  },
77
104
  // Callback for the start of each file upload request:
78
105
  send: function (e, data) {
106
+ var that = $(this).data('fileupload');
79
107
  if (!data.isValidated) {
80
- var that = $(this).data('fileupload');
81
108
  if (!data.isAdjusted) {
82
109
  that._adjustMaxNumberOfFiles(-data.files.length);
83
110
  }
@@ -90,15 +117,22 @@
90
117
  // Iframe Transport does not support progress events.
91
118
  // In lack of an indeterminate progress bar, we set
92
119
  // the progress to 100%, showing the full animated bar:
93
- data.context.find('.ui-progressbar').progressbar(
94
- 'value',
95
- parseInt(100, 10)
96
- );
120
+ data.context
121
+ .find('.progress').addClass(
122
+ !$.support.transition && 'progress-animated'
123
+ )
124
+ .find('.bar').css(
125
+ 'width',
126
+ parseInt(100, 10) + '%'
127
+ );
97
128
  }
129
+ return that._trigger('sent', e, data);
98
130
  },
99
131
  // Callback for successful uploads:
100
132
  done: function (e, data) {
101
- var that = $(this).data('fileupload');
133
+ var that = $(this).data('fileupload'),
134
+ template,
135
+ preview;
102
136
  if (data.context) {
103
137
  data.context.each(function (index) {
104
138
  var file = ($.isArray(data.result) &&
@@ -106,190 +140,133 @@
106
140
  if (file.error) {
107
141
  that._adjustMaxNumberOfFiles(1);
108
142
  }
109
- $(this).fadeOut(function () {
110
- that._renderDownload([file])
111
- .css('display', 'none')
112
- .replaceAll(this)
113
- .fadeIn(function () {
114
- // Fix for IE7 and lower:
115
- $(this).show();
116
- });
117
- });
143
+ that._transition($(this)).done(
144
+ function () {
145
+ var node = $(this);
146
+ template = that._renderDownload([file])
147
+ .css('height', node.height())
148
+ .replaceAll(node);
149
+ that._forceReflow(template);
150
+ that._transition(template).done(
151
+ function () {
152
+ data.context = $(this);
153
+ that._trigger('completed', e, data);
154
+ }
155
+ );
156
+ }
157
+ );
118
158
  });
119
159
  } else {
120
- that._renderDownload(data.result)
121
- .css('display', 'none')
122
- .appendTo($(this).find('.files'))
123
- .fadeIn(function () {
124
- // Fix for IE7 and lower:
125
- $(this).show();
126
- });
160
+ template = that._renderDownload(data.result)
161
+ .appendTo(that.options.filesContainer);
162
+ that._forceReflow(template);
163
+ that._transition(template).done(
164
+ function () {
165
+ data.context = $(this);
166
+ that._trigger('completed', e, data);
167
+ }
168
+ );
127
169
  }
128
170
  },
129
171
  // Callback for failed (abort or error) uploads:
130
172
  fail: function (e, data) {
131
- var that = $(this).data('fileupload');
173
+ var that = $(this).data('fileupload'),
174
+ template;
132
175
  that._adjustMaxNumberOfFiles(data.files.length);
133
176
  if (data.context) {
134
177
  data.context.each(function (index) {
135
- $(this).fadeOut(function () {
136
- if (data.errorThrown !== 'abort') {
137
- var file = data.files[index];
138
- file.error = file.error || data.errorThrown ||
139
- true;
140
- that._renderDownload([file])
141
- .css('display', 'none')
142
- .replaceAll(this)
143
- .fadeIn(function () {
144
- // Fix for IE7 and lower:
145
- $(this).show();
146
- });
147
- } else {
148
- data.context.remove();
149
- }
150
- });
178
+ if (data.errorThrown !== 'abort') {
179
+ var file = data.files[index];
180
+ file.error = file.error || data.errorThrown ||
181
+ true;
182
+ that._transition($(this)).done(
183
+ function () {
184
+ var node = $(this);
185
+ template = that._renderDownload([file])
186
+ .replaceAll(node);
187
+ that._forceReflow(template);
188
+ that._transition(template).done(
189
+ function () {
190
+ data.context = $(this);
191
+ that._trigger('failed', e, data);
192
+ }
193
+ );
194
+ }
195
+ );
196
+ } else {
197
+ that._transition($(this)).done(
198
+ function () {
199
+ $(this).remove();
200
+ that._trigger('failed', e, data);
201
+ }
202
+ );
203
+ }
151
204
  });
152
205
  } else if (data.errorThrown !== 'abort') {
153
206
  that._adjustMaxNumberOfFiles(-data.files.length);
154
207
  data.context = that._renderUpload(data.files)
155
- .css('display', 'none')
156
- .appendTo($(this).find('.files'))
157
- .fadeIn(function () {
158
- // Fix for IE7 and lower:
159
- $(this).show();
160
- }).data('data', data);
208
+ .appendTo(that.options.filesContainer)
209
+ .data('data', data);
210
+ that._forceReflow(data.context);
211
+ that._transition(data.context).done(
212
+ function () {
213
+ data.context = $(this);
214
+ that._trigger('failed', e, data);
215
+ }
216
+ );
217
+ } else {
218
+ that._trigger('failed', e, data);
161
219
  }
162
220
  },
163
221
  // Callback for upload progress events:
164
222
  progress: function (e, data) {
165
223
  if (data.context) {
166
- data.context.find('.ui-progressbar').progressbar(
167
- 'value',
168
- parseInt(data.loaded / data.total * 100, 10)
224
+ data.context.find('.progress .bar').css(
225
+ 'width',
226
+ parseInt(data.loaded / data.total * 100, 10) + '%'
169
227
  );
170
228
  }
171
229
  },
172
230
  // Callback for global upload progress events:
173
231
  progressall: function (e, data) {
174
- $(this).find('.fileupload-progressbar').progressbar(
175
- 'value',
176
- parseInt(data.loaded / data.total * 100, 10)
232
+ $(this).find('.fileupload-buttonbar .progress .bar').css(
233
+ 'width',
234
+ parseInt(data.loaded / data.total * 100, 10) + '%'
177
235
  );
178
236
  },
179
237
  // Callback for uploads start, equivalent to the global ajaxStart event:
180
- start: function () {
181
- $(this).find('.fileupload-progressbar')
182
- .progressbar('value', 0).fadeIn();
238
+ start: function (e) {
239
+ var that = $(this).data('fileupload');
240
+ that._transition($(this).find('.fileupload-buttonbar .progress')).done(
241
+ function () {
242
+ that._trigger('started', e);
243
+ }
244
+ );
183
245
  },
184
246
  // Callback for uploads stop, equivalent to the global ajaxStop event:
185
- stop: function () {
186
- $(this).find('.fileupload-progressbar').fadeOut();
247
+ stop: function (e) {
248
+ var that = $(this).data('fileupload');
249
+ that._transition($(this).find('.fileupload-buttonbar .progress')).done(
250
+ function () {
251
+ $(this).find('.bar').css('width', '0%');
252
+ that._trigger('stopped', e);
253
+ }
254
+ );
187
255
  },
188
256
  // Callback for file deletion:
189
257
  destroy: function (e, data) {
190
258
  var that = $(this).data('fileupload');
191
259
  if (data.url) {
192
- $.ajax(data)
193
- .success(function () {
194
- that._adjustMaxNumberOfFiles(1);
195
- $(this).fadeOut(function () {
196
- $(this).remove();
197
- });
198
- });
199
- } else {
200
- that._adjustMaxNumberOfFiles(1);
201
- data.context.fadeOut(function () {
202
- $(this).remove();
203
- });
260
+ $.ajax(data);
204
261
  }
205
- }
206
- },
207
-
208
- // Scales the given image (img HTML element)
209
- // using the given options.
210
- // Returns a canvas object if the canvas option is true
211
- // and the browser supports canvas, else the scaled image:
212
- _scaleImage: function (img, options) {
213
- options = options || {};
214
- var canvas = document.createElement('canvas'),
215
- scale = Math.min(
216
- (options.maxWidth || img.width) / img.width,
217
- (options.maxHeight || img.height) / img.height
218
- );
219
- if (scale >= 1) {
220
- scale = Math.max(
221
- (options.minWidth || img.width) / img.width,
222
- (options.minHeight || img.height) / img.height
262
+ that._adjustMaxNumberOfFiles(1);
263
+ that._transition(data.context).done(
264
+ function () {
265
+ $(this).remove();
266
+ that._trigger('destroyed', e, data);
267
+ }
223
268
  );
224
269
  }
225
- img.width = parseInt(img.width * scale, 10);
226
- img.height = parseInt(img.height * scale, 10);
227
- if (!options.canvas || !canvas.getContext) {
228
- return img;
229
- }
230
- canvas.width = img.width;
231
- canvas.height = img.height;
232
- canvas.getContext('2d')
233
- .drawImage(img, 0, 0, img.width, img.height);
234
- return canvas;
235
- },
236
-
237
- _createObjectURL: function (file) {
238
- var undef = 'undefined',
239
- urlAPI = (typeof window.createObjectURL !== undef && window) ||
240
- (typeof URL !== undef && URL) ||
241
- (typeof webkitURL !== undef && webkitURL);
242
- return urlAPI ? urlAPI.createObjectURL(file) : false;
243
- },
244
-
245
- _revokeObjectURL: function (url) {
246
- var undef = 'undefined',
247
- urlAPI = (typeof window.revokeObjectURL !== undef && window) ||
248
- (typeof URL !== undef && URL) ||
249
- (typeof webkitURL !== undef && webkitURL);
250
- return urlAPI ? urlAPI.revokeObjectURL(url) : false;
251
- },
252
-
253
- // Loads a given File object via FileReader interface,
254
- // invokes the callback with a data url:
255
- _loadFile: function (file, callback) {
256
- if (typeof FileReader !== 'undefined' &&
257
- FileReader.prototype.readAsDataURL) {
258
- var fileReader = new FileReader();
259
- fileReader.onload = function (e) {
260
- callback(e.target.result);
261
- };
262
- fileReader.readAsDataURL(file);
263
- return true;
264
- }
265
- return false;
266
- },
267
-
268
- // Loads an image for a given File object.
269
- // Invokes the callback with an img or optional canvas
270
- // element (if supported by the browser) as parameter:
271
- _loadImage: function (file, callback, options) {
272
- var that = this,
273
- url,
274
- img;
275
- if (!options || !options.fileTypes ||
276
- options.fileTypes.test(file.type)) {
277
- url = this._createObjectURL(file);
278
- img = $('<img>').bind('load', function () {
279
- $(this).unbind('load');
280
- that._revokeObjectURL(url);
281
- callback(that._scaleImage(img[0], options));
282
- });
283
- if (url) {
284
- img.prop('src', url);
285
- return true;
286
- } else {
287
- return this._loadFile(file, function (url) {
288
- img.prop('src', url);
289
- });
290
- }
291
- }
292
- return false;
293
270
  },
294
271
 
295
272
  // Link handler, that allows to download files
@@ -297,8 +274,7 @@
297
274
  _enableDragToDesktop: function () {
298
275
  var link = $(this),
299
276
  url = link.prop('href'),
300
- name = decodeURIComponent(url.split('/').pop())
301
- .replace(/:/g, '-'),
277
+ name = link.prop('download'),
302
278
  type = 'application/octet-stream';
303
279
  link.bind('dragstart', function (e) {
304
280
  try {
@@ -321,17 +297,17 @@
321
297
  }
322
298
  },
323
299
 
324
- _formatFileSize: function (file) {
325
- if (typeof file.size !== 'number') {
300
+ _formatFileSize: function (bytes) {
301
+ if (typeof bytes !== 'number') {
326
302
  return '';
327
303
  }
328
- if (file.size >= 1000000000) {
329
- return (file.size / 1000000000).toFixed(2) + ' GB';
304
+ if (bytes >= 1000000000) {
305
+ return (bytes / 1000000000).toFixed(2) + ' GB';
330
306
  }
331
- if (file.size >= 1000000) {
332
- return (file.size / 1000000).toFixed(2) + ' MB';
307
+ if (bytes >= 1000000) {
308
+ return (bytes / 1000000).toFixed(2) + ' MB';
333
309
  }
334
- return (file.size / 1000).toFixed(2) + ' KB';
310
+ return (bytes / 1000).toFixed(2) + ' KB';
335
311
  },
336
312
 
337
313
  _hasError: function (file) {
@@ -374,107 +350,92 @@
374
350
  return valid;
375
351
  },
376
352
 
377
- _uploadTemplateHelper: function (file) {
378
- file.sizef = this._formatFileSize(file);
379
- return file;
380
- },
381
-
382
- _renderUploadTemplate: function (files) {
383
- var that = this;
384
- return $.tmpl(
385
- this.options.uploadTemplate,
386
- $.map(files, function (file) {
387
- return that._uploadTemplateHelper(file);
388
- })
389
- );
353
+ _renderTemplate: function (func, files) {
354
+ if (!func) {
355
+ return $();
356
+ }
357
+ var result = func({
358
+ files: files,
359
+ formatFileSize: this._formatFileSize,
360
+ options: this.options
361
+ });
362
+ if (result instanceof $) {
363
+ return result;
364
+ }
365
+ return $(this.options.templatesContainer).html(result).children();
390
366
  },
391
367
 
392
- _renderUpload: function (files) {
368
+ _renderPreview: function (file, node) {
393
369
  var that = this,
394
370
  options = this.options,
395
- tmpl = this._renderUploadTemplate(files),
396
- isValidated = this._validate(files);
397
- if (!(tmpl instanceof $)) {
398
- return $();
399
- }
400
- tmpl.css('display', 'none');
401
- // .slice(1).remove().end().first() removes all but the first
402
- // element and selects only the first for the jQuery collection:
403
- tmpl.find('.progress div').slice(
404
- isValidated ? 1 : 0
405
- ).remove().end().first()
406
- .progressbar();
407
- tmpl.find('.start button').slice(
408
- this.options.autoUpload || !isValidated ? 0 : 1
409
- ).remove().end().first()
410
- .button({
411
- text: false,
412
- icons: {primary: 'ui-icon-circle-arrow-e'}
413
- });
414
- tmpl.find('.cancel button').slice(1).remove().end().first()
415
- .button({
416
- text: false,
417
- icons: {primary: 'ui-icon-cancel'}
418
- });
419
- tmpl.find('.preview').each(function (index, node) {
420
- that._loadImage(
421
- files[index],
422
- function (img) {
423
- $(img).hide().appendTo(node).fadeIn();
424
- },
425
- {
426
- maxWidth: options.previewMaxWidth,
427
- maxHeight: options.previewMaxHeight,
428
- fileTypes: options.previewFileTypes,
429
- canvas: options.previewAsCanvas
430
- }
431
- );
432
- });
433
- return tmpl;
371
+ deferred = $.Deferred();
372
+ return ((loadImage && loadImage(
373
+ file,
374
+ function (img) {
375
+ node.append(img);
376
+ that._forceReflow(node);
377
+ that._transition(node).done(function () {
378
+ deferred.resolveWith(node);
379
+ });
380
+ },
381
+ {
382
+ maxWidth: options.previewMaxWidth,
383
+ maxHeight: options.previewMaxHeight,
384
+ canvas: options.previewAsCanvas
385
+ }
386
+ )) || deferred.resolveWith(node)) && deferred;
434
387
  },
435
388
 
436
- _downloadTemplateHelper: function (file) {
437
- file.sizef = this._formatFileSize(file);
438
- return file;
389
+ _renderPreviews: function (files, nodes) {
390
+ var that = this,
391
+ options = this.options;
392
+ nodes.find('.preview span').each(function (index, element) {
393
+ var file = files[index];
394
+ if (options.previewSourceFileTypes.test(file.type) &&
395
+ ($.type(options.previewSourceMaxFileSize) !== 'number' ||
396
+ file.size < options.previewSourceMaxFileSize)) {
397
+ that._processingQueue = that._processingQueue.pipe(function () {
398
+ var deferred = $.Deferred();
399
+ that._renderPreview(file, $(element)).done(
400
+ function () {
401
+ deferred.resolveWith(that);
402
+ }
403
+ );
404
+ return deferred.promise();
405
+ });
406
+ }
407
+ });
408
+ return this._processingQueue;
439
409
  },
440
410
 
441
- _renderDownloadTemplate: function (files) {
442
- var that = this;
443
- return $.tmpl(
444
- this.options.downloadTemplate,
445
- $.map(files, function (file) {
446
- return that._downloadTemplateHelper(file);
447
- })
411
+ _renderUpload: function (files) {
412
+ return this._renderTemplate(
413
+ this.options.uploadTemplate,
414
+ files
448
415
  );
449
416
  },
450
417
 
451
418
  _renderDownload: function (files) {
452
- var tmpl = this._renderDownloadTemplate(files);
453
- if (!(tmpl instanceof $)) {
454
- return $();
455
- }
456
- tmpl.css('display', 'none');
457
- tmpl.find('.delete button').button({
458
- text: false,
459
- icons: {primary: 'ui-icon-trash'}
460
- });
461
- tmpl.find('a').each(this._enableDragToDesktop);
462
- return tmpl;
419
+ return this._renderTemplate(
420
+ this.options.downloadTemplate,
421
+ files
422
+ ).find('a[download]').each(this._enableDragToDesktop).end();
463
423
  },
464
424
 
465
425
  _startHandler: function (e) {
466
426
  e.preventDefault();
467
- var tmpl = $(this).closest('.template-upload'),
468
- data = tmpl.data('data');
427
+ var button = $(this),
428
+ template = button.closest('.template-upload'),
429
+ data = template.data('data');
469
430
  if (data && data.submit && !data.jqXHR && data.submit()) {
470
- $(this).fadeOut();
431
+ button.prop('disabled', true);
471
432
  }
472
433
  },
473
434
 
474
435
  _cancelHandler: function (e) {
475
436
  e.preventDefault();
476
- var tmpl = $(this).closest('.template-upload'),
477
- data = tmpl.data('data') || {};
437
+ var template = $(this).closest('.template-upload'),
438
+ data = template.data('data') || {};
478
439
  if (!data.jqXHR) {
479
440
  data.errorThrown = 'abort';
480
441
  e.data.fileupload._trigger('fail', e, data);
@@ -489,72 +450,59 @@
489
450
  e.data.fileupload._trigger('destroy', e, {
490
451
  context: button.closest('.template-download'),
491
452
  url: button.attr('data-url'),
492
- type: button.attr('data-type'),
453
+ type: button.attr('data-type') || 'DELETE',
493
454
  dataType: e.data.fileupload.options.dataType
494
455
  });
495
456
  },
496
457
 
497
- _initEventHandlers: function () {
498
- $.blueimp.fileupload.prototype._initEventHandlers.call(this);
499
- var eventData = {fileupload: this};
500
- this.element.find('.files')
501
- .delegate(
502
- '.start button',
503
- 'click.' + this.options.namespace,
504
- eventData,
505
- this._startHandler
506
- )
507
- .delegate(
508
- '.cancel button',
509
- 'click.' + this.options.namespace,
510
- eventData,
511
- this._cancelHandler
512
- )
513
- .delegate(
514
- '.delete button',
515
- 'click.' + this.options.namespace,
516
- eventData,
517
- this._deleteHandler
518
- );
458
+ _forceReflow: function (node) {
459
+ this._reflow = $.support.transition &&
460
+ node.length && node[0].offsetWidth;
519
461
  },
520
462
 
521
- _destroyEventHandlers: function () {
522
- this.element.find('.files')
523
- .undelegate('.start button', 'click.' + this.options.namespace)
524
- .undelegate('.cancel button', 'click.' + this.options.namespace)
525
- .undelegate('.delete button', 'click.' + this.options.namespace);
526
- $.blueimp.fileupload.prototype._destroyEventHandlers.call(this);
463
+ _transition: function (node) {
464
+ var that = this,
465
+ deferred = $.Deferred();
466
+ if ($.support.transition && node.hasClass('fade')) {
467
+ node.bind(
468
+ $.support.transition.end,
469
+ function (e) {
470
+ // Make sure we don't respond to other transitions events
471
+ // in the container element, e.g. from button elements:
472
+ if (e.target === node[0]) {
473
+ node.unbind($.support.transition.end);
474
+ deferred.resolveWith(node);
475
+ }
476
+ }
477
+ ).toggleClass('in');
478
+ } else {
479
+ node.toggleClass('in');
480
+ deferred.resolveWith(node);
481
+ }
482
+ return deferred;
527
483
  },
528
484
 
529
- _initFileUploadButtonBar: function () {
485
+ _initButtonBarEventHandlers: function () {
530
486
  var fileUploadButtonBar = this.element.find('.fileupload-buttonbar'),
531
- filesList = this.element.find('.files'),
487
+ filesList = this.options.filesContainer,
532
488
  ns = this.options.namespace;
533
- fileUploadButtonBar
534
- .addClass('ui-widget-header ui-corner-top');
535
- this.element.find('.fileinput-button').each(function () {
536
- var fileInput = $(this).find('input:file').detach();
537
- $(this).button({icons: {primary: 'ui-icon-plusthick'}})
538
- .append(fileInput);
539
- });
540
489
  fileUploadButtonBar.find('.start')
541
- .button({icons: {primary: 'ui-icon-circle-arrow-e'}})
542
490
  .bind('click.' + ns, function (e) {
543
491
  e.preventDefault();
544
492
  filesList.find('.start button').click();
545
493
  });
546
494
  fileUploadButtonBar.find('.cancel')
547
- .button({icons: {primary: 'ui-icon-cancel'}})
548
495
  .bind('click.' + ns, function (e) {
549
496
  e.preventDefault();
550
497
  filesList.find('.cancel button').click();
551
498
  });
552
499
  fileUploadButtonBar.find('.delete')
553
- .button({icons: {primary: 'ui-icon-trash'}})
554
500
  .bind('click.' + ns, function (e) {
555
501
  e.preventDefault();
556
502
  filesList.find('.delete input:checked')
557
503
  .siblings('button').click();
504
+ fileUploadButtonBar.find('.toggle')
505
+ .prop('checked', false);
558
506
  });
559
507
  fileUploadButtonBar.find('.toggle')
560
508
  .bind('change.' + ns, function (e) {
@@ -565,94 +513,117 @@
565
513
  });
566
514
  },
567
515
 
568
- _destroyFileUploadButtonBar: function () {
569
- this.element.find('.fileupload-buttonbar')
570
- .removeClass('ui-widget-header ui-corner-top');
571
- this.element.find('.fileinput-button').each(function () {
572
- var fileInput = $(this).find('input:file').detach();
573
- $(this).button('destroy')
574
- .append(fileInput);
575
- });
516
+ _destroyButtonBarEventHandlers: function () {
576
517
  this.element.find('.fileupload-buttonbar button')
577
- .unbind('click.' + this.options.namespace)
578
- .button('destroy');
518
+ .unbind('click.' + this.options.namespace);
579
519
  this.element.find('.fileupload-buttonbar .toggle')
580
520
  .unbind('change.' + this.options.namespace);
581
521
  },
582
522
 
523
+ _initEventHandlers: function () {
524
+ parentWidget.prototype._initEventHandlers.call(this);
525
+ var eventData = {fileupload: this};
526
+ this.options.filesContainer
527
+ .delegate(
528
+ '.start button',
529
+ 'click.' + this.options.namespace,
530
+ eventData,
531
+ this._startHandler
532
+ )
533
+ .delegate(
534
+ '.cancel button',
535
+ 'click.' + this.options.namespace,
536
+ eventData,
537
+ this._cancelHandler
538
+ )
539
+ .delegate(
540
+ '.delete button',
541
+ 'click.' + this.options.namespace,
542
+ eventData,
543
+ this._deleteHandler
544
+ );
545
+ this._initButtonBarEventHandlers();
546
+ },
547
+
548
+ _destroyEventHandlers: function () {
549
+ var options = this.options;
550
+ this._destroyButtonBarEventHandlers();
551
+ options.filesContainer
552
+ .undelegate('.start button', 'click.' + options.namespace)
553
+ .undelegate('.cancel button', 'click.' + options.namespace)
554
+ .undelegate('.delete button', 'click.' + options.namespace);
555
+ parentWidget.prototype._destroyEventHandlers.call(this);
556
+ },
557
+
583
558
  _enableFileInputButton: function () {
584
- this.element.find('.fileinput-button input:file:disabled')
585
- .each(function () {
586
- var fileInput = $(this),
587
- button = fileInput.parent();
588
- fileInput.detach().prop('disabled', false);
589
- button.button('enable').append(fileInput);
590
- });
559
+ this.element.find('.fileinput-button input')
560
+ .prop('disabled', false)
561
+ .parent().removeClass('disabled');
591
562
  },
592
563
 
593
564
  _disableFileInputButton: function () {
594
- this.element.find('.fileinput-button input:file:enabled')
595
- .each(function () {
596
- var fileInput = $(this),
597
- button = fileInput.parent();
598
- fileInput.detach().prop('disabled', true);
599
- button.button('disable').append(fileInput);
600
- });
565
+ this.element.find('.fileinput-button input')
566
+ .prop('disabled', true)
567
+ .parent().addClass('disabled');
601
568
  },
602
569
 
603
570
  _initTemplates: function () {
604
- // Handle cases where the templates are defined
605
- // after the widget library has been included:
606
- if (this.options.uploadTemplate instanceof $ &&
607
- !this.options.uploadTemplate.length) {
608
- this.options.uploadTemplate = $(
609
- this.options.uploadTemplate.selector
610
- );
571
+ var options = this.options;
572
+ options.templatesContainer = document.createElement(
573
+ options.filesContainer.prop('nodeName')
574
+ );
575
+ if (tmpl) {
576
+ if (options.uploadTemplateId) {
577
+ options.uploadTemplate = tmpl(options.uploadTemplateId);
578
+ }
579
+ if (options.downloadTemplateId) {
580
+ options.downloadTemplate = tmpl(options.downloadTemplateId);
581
+ }
611
582
  }
612
- if (this.options.downloadTemplate instanceof $ &&
613
- !this.options.downloadTemplate.length) {
614
- this.options.downloadTemplate = $(
615
- this.options.downloadTemplate.selector
616
- );
583
+ },
584
+
585
+ _initFilesContainer: function () {
586
+ var options = this.options;
587
+ if (options.filesContainer === undefined) {
588
+ options.filesContainer = this.element.find('.files');
589
+ } else if (!(options.filesContainer instanceof $)) {
590
+ options.filesContainer = $(options.filesContainer);
617
591
  }
618
592
  },
619
593
 
620
- _create: function () {
621
- $.blueimp.fileupload.prototype._create.call(this);
594
+ _initSpecialOptions: function () {
595
+ parentWidget.prototype._initSpecialOptions.call(this);
596
+ this._initFilesContainer();
622
597
  this._initTemplates();
623
- this.element
624
- .addClass('ui-widget');
625
- this._initFileUploadButtonBar();
626
- this.element.find('.fileupload-content')
627
- .addClass('ui-widget-content ui-corner-bottom');
628
- this.element.find('.fileupload-progressbar')
629
- .hide().progressbar();
630
598
  },
631
599
 
632
- destroy: function () {
633
- this.element.find('.fileupload-progressbar')
634
- .progressbar('destroy');
635
- this.element.find('.fileupload-content')
636
- .removeClass('ui-widget-content ui-corner-bottom');
637
- this._destroyFileUploadButtonBar();
638
- this.element.removeClass('ui-widget');
639
- $.blueimp.fileupload.prototype.destroy.call(this);
600
+ _create: function () {
601
+ parentWidget.prototype._create.call(this);
602
+ this._refreshOptionsList.push(
603
+ 'filesContainer',
604
+ 'uploadTemplateId',
605
+ 'downloadTemplateId'
606
+ );
607
+ if (!$.blueimpIP) {
608
+ this._processingQueue = $.Deferred().resolveWith(this).promise();
609
+ this.resize = function () {
610
+ return this._processingQueue;
611
+ };
612
+ }
640
613
  },
641
614
 
642
615
  enable: function () {
643
- $.blueimp.fileupload.prototype.enable.call(this);
644
- this.element.find(':ui-button').not('.fileinput-button')
645
- .button('enable');
616
+ parentWidget.prototype.enable.call(this);
617
+ this.element.find('input, button').prop('disabled', false);
646
618
  this._enableFileInputButton();
647
619
  },
648
620
 
649
621
  disable: function () {
650
- this.element.find(':ui-button').not('.fileinput-button')
651
- .button('disable');
622
+ this.element.find('input, button').prop('disabled', true);
652
623
  this._disableFileInputButton();
653
- $.blueimp.fileupload.prototype.disable.call(this);
624
+ parentWidget.prototype.disable.call(this);
654
625
  }
655
626
 
656
627
  });
657
628
 
658
- }(jQuery));
629
+ }));