jquery.fileupload-rails 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }));