jquery.fileupload-rails 0.1.0 → 0.1.1

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 CHANGED
@@ -5,10 +5,20 @@ The plugin is developed by Sebastian Tschan (@blueimp) and well maintained.
5
5
 
6
6
  This is a simple gem package for this plugin.
7
7
 
8
- [See the original project page](https://github.com/blueimp/jQuery-File-Upload) for reference & documentation.
8
+ [See the original project page][1] for reference & documentation.
9
9
 
10
10
  ## Changelog
11
11
 
12
- 0.1.0. jquery.fileupload 5.9.0 and jquery.fileupload-ui 6.6.2, added readme.
12
+ 0.1.1. Core 5.11.2, UI 6.9.1, minor gemspec change.
13
13
 
14
- 0.0.1. jquery.fileupload 5.5.2 and jquery.fileupload-ui 5.1.1.
14
+ 0.1.0. Core 5.9.0, UI 6.6.2, added readme.
15
+
16
+ 0.0.1. Core 5.5.2, UI 5.1.1.
17
+
18
+ ## Todo
19
+
20
+ * Add convinient file-package with jquery.fileupload and all it's dependencies.
21
+ * Add example usage in Rails here.
22
+ * Add script to automate updating the library from [the official repo][1].
23
+
24
+ [1]: https://github.com/blueimp/jQuery-File-Upload
@@ -18,7 +18,5 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
- # specify any dependencies here; for example:
22
- # s.add_development_dependency "rspec"
23
- # s.add_runtime_dependency "rest-client"
21
+ s.add_dependency 'sprockets', '~> 2.0'
24
22
  end
@@ -1,5 +1,5 @@
1
1
  module JqueryFileUpload
2
2
  module Rails
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.1"
4
4
  end
5
5
  end
@@ -0,0 +1,219 @@
1
+ /*
2
+ * jQuery File Upload File Processing Plugin 1.0
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
+ );
31
+ }
32
+ }(function ($, loadImage) {
33
+ 'use strict';
34
+
35
+ // The File Upload IP version extends the basic fileupload widget
36
+ // with file processing functionality:
37
+ $.widget('blueimpFP.fileupload', $.blueimp.fileupload, {
38
+
39
+ options: {
40
+ // The list of file processing actions:
41
+ process: [
42
+ /*
43
+ {
44
+ action: 'load',
45
+ fileTypes: /^image\/(gif|jpeg|png)$/,
46
+ maxFileSize: 20000000 // 20MB
47
+ },
48
+ {
49
+ action: 'resize',
50
+ maxWidth: 1920,
51
+ maxHeight: 1200,
52
+ minWidth: 800,
53
+ minHeight: 600
54
+ },
55
+ {
56
+ action: 'save'
57
+ }
58
+ */
59
+ ],
60
+
61
+ // The add callback is invoked as soon as files are added to the
62
+ // fileupload widget (via file input selection, drag & drop or add
63
+ // API call). See the basic file upload widget for more information:
64
+ add: function (e, data) {
65
+ $(this).fileupload('process', data).done(function () {
66
+ data.submit();
67
+ });
68
+ }
69
+ },
70
+
71
+ processActions: {
72
+ // Loads the image given via data.files and data.index
73
+ // as canvas element.
74
+ // Accepts the options fileTypes (regular expression)
75
+ // and maxFileSize (integer) to limit the files to load:
76
+ load: function (data, options) {
77
+ var that = this,
78
+ file = data.files[data.index],
79
+ dfd = $.Deferred();
80
+ if (window.HTMLCanvasElement &&
81
+ window.HTMLCanvasElement.prototype.toBlob &&
82
+ ($.type(options.maxFileSize) !== 'number' ||
83
+ file.size < options.maxFileSize) &&
84
+ (!options.fileTypes ||
85
+ options.fileTypes.test(file.type))) {
86
+ loadImage(
87
+ file,
88
+ function (canvas) {
89
+ data.canvas = canvas;
90
+ dfd.resolveWith(that, [data]);
91
+ },
92
+ {canvas: true}
93
+ );
94
+ } else {
95
+ dfd.rejectWith(that, [data]);
96
+ }
97
+ return dfd.promise();
98
+ },
99
+ // Resizes the image given as data.canvas and updates
100
+ // data.canvas with the resized image.
101
+ // Accepts the options maxWidth, maxHeight, minWidth and
102
+ // minHeight to scale the given image:
103
+ resize: function (data, options) {
104
+ if (data.canvas) {
105
+ var canvas = loadImage.scale(data.canvas, options);
106
+ if (canvas.width !== data.canvas.width ||
107
+ canvas.height !== data.canvas.height) {
108
+ data.canvas = canvas;
109
+ data.processed = true;
110
+ }
111
+ }
112
+ return data;
113
+ },
114
+ // Saves the processed image given as data.canvas
115
+ // inplace at data.index of data.files:
116
+ save: function (data, options) {
117
+ // Do nothing if no processing has happened:
118
+ if (!data.canvas || !data.processed) {
119
+ return data;
120
+ }
121
+ var that = this,
122
+ file = data.files[data.index],
123
+ name = file.name,
124
+ dfd = $.Deferred(),
125
+ callback = function (blob) {
126
+ if (!blob.name) {
127
+ if (file.type === blob.type) {
128
+ blob.name = file.name;
129
+ } else if (file.name) {
130
+ blob.name = file.name.replace(
131
+ /\..+$/,
132
+ '.' + blob.type.substr(6)
133
+ );
134
+ }
135
+ }
136
+ // Store the created blob at the position
137
+ // of the original file in the files list:
138
+ data.files[data.index] = blob;
139
+ dfd.resolveWith(that, [data]);
140
+ };
141
+ // Use canvas.mozGetAsFile directly, to retain the filename, as
142
+ // Gecko doesn't support the filename option for FormData.append:
143
+ if (data.canvas.mozGetAsFile) {
144
+ callback(data.canvas.mozGetAsFile(
145
+ (/^image\/(jpeg|png)$/.test(file.type) && name) ||
146
+ ((name && name.replace(/\..+$/, '')) ||
147
+ 'blob') + '.png',
148
+ file.type
149
+ ));
150
+ } else {
151
+ data.canvas.toBlob(callback, file.type);
152
+ }
153
+ return dfd.promise();
154
+ }
155
+ },
156
+
157
+ // Resizes the file at the given index and stores the created blob at
158
+ // the original position of the files list, returns a Promise object:
159
+ _processFile: function (files, index, options) {
160
+ var that = this,
161
+ dfd = $.Deferred().resolveWith(that, [{
162
+ files: files,
163
+ index: index
164
+ }]),
165
+ chain = dfd.promise();
166
+ that._processing += 1;
167
+ $.each(options.process, function (i, settings) {
168
+ chain = chain.pipe(function (data) {
169
+ return that.processActions[settings.action]
170
+ .call(this, data, settings);
171
+ });
172
+ });
173
+ chain.always(function () {
174
+ that._processing -= 1;
175
+ if (that._processing === 0) {
176
+ that.element
177
+ .removeClass('fileupload-processing');
178
+ }
179
+ });
180
+ if (that._processing === 1) {
181
+ that.element.addClass('fileupload-processing');
182
+ }
183
+ return chain;
184
+ },
185
+
186
+ // Processes the files given as files property of the data parameter,
187
+ // returns a Promise object that allows to bind a done handler, which
188
+ // will be invoked after processing all files (inplace) is done:
189
+ process: function (data) {
190
+ var that = this,
191
+ options = $.extend({}, this.options, data);
192
+ if (options.process && options.process.length &&
193
+ this._isXHRUpload(options)) {
194
+ $.each(data.files, function (index, file) {
195
+ that._processingQueue = that._processingQueue.pipe(
196
+ function () {
197
+ var dfd = $.Deferred();
198
+ that._processFile(data.files, index, options)
199
+ .always(function () {
200
+ dfd.resolveWith(that);
201
+ });
202
+ return dfd.promise();
203
+ }
204
+ );
205
+ });
206
+ }
207
+ return this._processingQueue;
208
+ },
209
+
210
+ _create: function () {
211
+ $.blueimp.fileupload.prototype._create.call(this);
212
+ this._processing = 0;
213
+ this._processingQueue = $.Deferred().resolveWith(this)
214
+ .promise();
215
+ }
216
+
217
+ });
218
+
219
+ }));
@@ -1,5 +1,5 @@
1
1
  /*
2
- * jQuery File Upload User Interface Plugin 6.6.2
2
+ * jQuery File Upload User Interface Plugin 6.9.1
3
3
  * https://github.com/blueimp/jQuery-File-Upload
4
4
  *
5
5
  * Copyright 2010, Sebastian Tschan
@@ -20,7 +20,7 @@
20
20
  'jquery',
21
21
  'tmpl',
22
22
  'load-image',
23
- './jquery.fileupload-ip'
23
+ './jquery.fileupload-fp'
24
24
  ], factory);
25
25
  } else {
26
26
  // Browser globals:
@@ -33,9 +33,9 @@
33
33
  }(function ($, tmpl, loadImage) {
34
34
  'use strict';
35
35
 
36
- // The UI version extends the IP (image processing) version or the basic
36
+ // The UI version extends the FP (file processing) version or the basic
37
37
  // file upload widget and adds complete user interface interaction:
38
- var parentWidget = ($.blueimpIP || $.blueimp).fileupload;
38
+ var parentWidget = ($.blueimpFP || $.blueimp).fileupload;
39
39
  $.widget('blueimpUI.fileupload', parentWidget, {
40
40
 
41
41
  options: {
@@ -70,6 +70,12 @@
70
70
  uploadTemplateId: 'template-upload',
71
71
  // The ID of the download template:
72
72
  downloadTemplateId: 'template-download',
73
+ // The container for the list of files. If undefined, it is set to
74
+ // an element with class "files" inside of the widget element:
75
+ filesContainer: undefined,
76
+ // By default, files are appended to the files container.
77
+ // Set the following option to true, to prepend files instead:
78
+ prependFiles: false,
73
79
  // The expected data type of the upload response, sets the dataType
74
80
  // option of the $.ajax upload requests:
75
81
  dataType: 'json',
@@ -81,13 +87,14 @@
81
87
  var that = $(this).data('fileupload'),
82
88
  options = that.options,
83
89
  files = data.files;
84
- that._adjustMaxNumberOfFiles(-files.length);
85
- data.isAdjusted = true;
86
- $(this).fileupload('resize', data).done(data, function () {
90
+ $(this).fileupload('process', data).done(function () {
91
+ that._adjustMaxNumberOfFiles(-files.length);
92
+ data.isAdjusted = true;
87
93
  data.files.valid = data.isValidated = that._validate(files);
88
- data.context = that._renderUpload(files)
89
- .appendTo(options.filesContainer)
90
- .data('data', data);
94
+ data.context = that._renderUpload(files).data('data', data);
95
+ options.filesContainer[
96
+ options.prependFiles ? 'prepend' : 'append'
97
+ ](data.context);
91
98
  that._renderPreviews(files, data.context);
92
99
  that._forceReflow(data.context);
93
100
  that._transition(data.context).done(
@@ -121,9 +128,10 @@
121
128
  .find('.progress').addClass(
122
129
  !$.support.transition && 'progress-animated'
123
130
  )
131
+ .attr('aria-valuenow', 100)
124
132
  .find('.bar').css(
125
133
  'width',
126
- parseInt(100, 10) + '%'
134
+ '100%'
127
135
  );
128
136
  }
129
137
  return that._trigger('sent', e, data);
@@ -131,8 +139,7 @@
131
139
  // Callback for successful uploads:
132
140
  done: function (e, data) {
133
141
  var that = $(this).data('fileupload'),
134
- template,
135
- preview;
142
+ template;
136
143
  if (data.context) {
137
144
  data.context.each(function (index) {
138
145
  var file = ($.isArray(data.result) &&
@@ -221,23 +228,39 @@
221
228
  // Callback for upload progress events:
222
229
  progress: function (e, data) {
223
230
  if (data.context) {
224
- data.context.find('.progress .bar').css(
225
- 'width',
226
- parseInt(data.loaded / data.total * 100, 10) + '%'
227
- );
231
+ var progress = parseInt(data.loaded / data.total * 100, 10);
232
+ data.context.find('.progress')
233
+ .attr('aria-valuenow', progress)
234
+ .find('.bar').css(
235
+ 'width',
236
+ progress + '%'
237
+ );
228
238
  }
229
239
  },
230
240
  // Callback for global upload progress events:
231
241
  progressall: function (e, data) {
232
- $(this).find('.fileupload-buttonbar .progress .bar').css(
233
- 'width',
234
- parseInt(data.loaded / data.total * 100, 10) + '%'
235
- );
242
+ var $this = $(this),
243
+ progress = parseInt(data.loaded / data.total * 100, 10),
244
+ globalProgressNode = $this.find('.fileupload-progress'),
245
+ extendedProgressNode = globalProgressNode
246
+ .find('.progress-extended');
247
+ if (extendedProgressNode.length) {
248
+ extendedProgressNode.html(
249
+ $this.data('fileupload')._renderExtendedProgress(data)
250
+ );
251
+ }
252
+ globalProgressNode
253
+ .find('.progress')
254
+ .attr('aria-valuenow', progress)
255
+ .find('.bar').css(
256
+ 'width',
257
+ progress + '%'
258
+ );
236
259
  },
237
260
  // Callback for uploads start, equivalent to the global ajaxStart event:
238
261
  start: function (e) {
239
262
  var that = $(this).data('fileupload');
240
- that._transition($(this).find('.fileupload-buttonbar .progress')).done(
263
+ that._transition($(this).find('.fileupload-progress')).done(
241
264
  function () {
242
265
  that._trigger('started', e);
243
266
  }
@@ -246,9 +269,12 @@
246
269
  // Callback for uploads stop, equivalent to the global ajaxStop event:
247
270
  stop: function (e) {
248
271
  var that = $(this).data('fileupload');
249
- that._transition($(this).find('.fileupload-buttonbar .progress')).done(
272
+ that._transition($(this).find('.fileupload-progress')).done(
250
273
  function () {
251
- $(this).find('.bar').css('width', '0%');
274
+ $(this).find('.progress')
275
+ .attr('aria-valuenow', '0')
276
+ .find('.bar').css('width', '0%');
277
+ $(this).find('.progress-extended').html('&nbsp;');
252
278
  that._trigger('stopped', e);
253
279
  }
254
280
  );
@@ -258,8 +284,8 @@
258
284
  var that = $(this).data('fileupload');
259
285
  if (data.url) {
260
286
  $.ajax(data);
287
+ that._adjustMaxNumberOfFiles(1);
261
288
  }
262
- that._adjustMaxNumberOfFiles(1);
263
289
  that._transition(data.context).done(
264
290
  function () {
265
291
  $(this).remove();
@@ -310,6 +336,48 @@
310
336
  return (bytes / 1000).toFixed(2) + ' KB';
311
337
  },
312
338
 
339
+ _formatBitrate: function (bits) {
340
+ if (typeof bits !== 'number') {
341
+ return '';
342
+ }
343
+ if (bits >= 1000000000) {
344
+ return (bits / 1000000000).toFixed(2) + ' Gbit/s';
345
+ }
346
+ if (bits >= 1000000) {
347
+ return (bits / 1000000).toFixed(2) + ' Mbit/s';
348
+ }
349
+ if (bits >= 1000) {
350
+ return (bits / 1000).toFixed(2) + ' kbit/s';
351
+ }
352
+ return bits + ' bit/s';
353
+ },
354
+
355
+ _formatTime: function (seconds) {
356
+ var date = new Date(seconds * 1000),
357
+ days = parseInt(seconds / 86400, 10);
358
+ days = days ? days + 'd ' : '';
359
+ return days +
360
+ ('0' + date.getUTCHours()).slice(-2) + ':' +
361
+ ('0' + date.getUTCMinutes()).slice(-2) + ':' +
362
+ ('0' + date.getUTCSeconds()).slice(-2);
363
+ },
364
+
365
+ _formatPercentage: function (floatValue) {
366
+ return (floatValue * 100).toFixed(2) + ' %';
367
+ },
368
+
369
+ _renderExtendedProgress: function (data) {
370
+ return this._formatBitrate(data.bitrate) + ' | ' +
371
+ this._formatTime(
372
+ (data.total - data.loaded) * 8 / data.bitrate
373
+ ) + ' | ' +
374
+ this._formatPercentage(
375
+ data.loaded / data.total
376
+ ) + ' | ' +
377
+ this._formatFileSize(data.loaded) + ' / ' +
378
+ this._formatFileSize(data.total);
379
+ },
380
+
313
381
  _hasError: function (file) {
314
382
  if (file.error) {
315
383
  return file.error;
@@ -368,22 +436,28 @@
368
436
  _renderPreview: function (file, node) {
369
437
  var that = this,
370
438
  options = this.options,
371
- deferred = $.Deferred();
439
+ dfd = $.Deferred();
372
440
  return ((loadImage && loadImage(
373
441
  file,
374
442
  function (img) {
375
443
  node.append(img);
376
444
  that._forceReflow(node);
377
445
  that._transition(node).done(function () {
378
- deferred.resolveWith(node);
446
+ dfd.resolveWith(node);
379
447
  });
448
+ if (!$.contains(document.body, node[0])) {
449
+ // If the element is not part of the DOM,
450
+ // transition events are not triggered,
451
+ // so we have to resolve manually:
452
+ dfd.resolveWith(node);
453
+ }
380
454
  },
381
455
  {
382
456
  maxWidth: options.previewMaxWidth,
383
457
  maxHeight: options.previewMaxHeight,
384
458
  canvas: options.previewAsCanvas
385
459
  }
386
- )) || deferred.resolveWith(node)) && deferred;
460
+ )) || dfd.resolveWith(node)) && dfd;
387
461
  },
388
462
 
389
463
  _renderPreviews: function (files, nodes) {
@@ -395,13 +469,13 @@
395
469
  ($.type(options.previewSourceMaxFileSize) !== 'number' ||
396
470
  file.size < options.previewSourceMaxFileSize)) {
397
471
  that._processingQueue = that._processingQueue.pipe(function () {
398
- var deferred = $.Deferred();
472
+ var dfd = $.Deferred();
399
473
  that._renderPreview(file, $(element)).done(
400
474
  function () {
401
- deferred.resolveWith(that);
475
+ dfd.resolveWith(that);
402
476
  }
403
477
  );
404
- return deferred.promise();
478
+ return dfd.promise();
405
479
  });
406
480
  }
407
481
  });
@@ -456,13 +530,12 @@
456
530
  },
457
531
 
458
532
  _forceReflow: function (node) {
459
- this._reflow = $.support.transition &&
460
- node.length && node[0].offsetWidth;
533
+ return $.support.transition && node.length &&
534
+ node[0].offsetWidth;
461
535
  },
462
536
 
463
537
  _transition: function (node) {
464
- var that = this,
465
- deferred = $.Deferred();
538
+ var dfd = $.Deferred();
466
539
  if ($.support.transition && node.hasClass('fade')) {
467
540
  node.bind(
468
541
  $.support.transition.end,
@@ -471,15 +544,15 @@
471
544
  // in the container element, e.g. from button elements:
472
545
  if (e.target === node[0]) {
473
546
  node.unbind($.support.transition.end);
474
- deferred.resolveWith(node);
547
+ dfd.resolveWith(node);
475
548
  }
476
549
  }
477
550
  ).toggleClass('in');
478
551
  } else {
479
552
  node.toggleClass('in');
480
- deferred.resolveWith(node);
553
+ dfd.resolveWith(node);
481
554
  }
482
- return deferred;
555
+ return dfd;
483
556
  },
484
557
 
485
558
  _initButtonBarEventHandlers: function () {
@@ -604,9 +677,9 @@
604
677
  'uploadTemplateId',
605
678
  'downloadTemplateId'
606
679
  );
607
- if (!$.blueimpIP) {
680
+ if (!$.blueimpFP) {
608
681
  this._processingQueue = $.Deferred().resolveWith(this).promise();
609
- this.resize = function () {
682
+ this.process = function () {
610
683
  return this._processingQueue;
611
684
  };
612
685
  }
@@ -1,5 +1,5 @@
1
1
  /*
2
- * jQuery File Upload Plugin 5.9
2
+ * jQuery File Upload Plugin 5.11.2
3
3
  * https://github.com/blueimp/jQuery-File-Upload
4
4
  *
5
5
  * Copyright 2010, Sebastian Tschan
@@ -63,7 +63,8 @@
63
63
  replaceFileInput: true,
64
64
  // The parameter name for the file form data (the request argument name).
65
65
  // If undefined or empty, the name property of the file input field is
66
- // used, or "files[]" if the file input name property is also empty:
66
+ // used, or "files[]" if the file input name property is also empty,
67
+ // can be a string or an array of strings:
67
68
  paramName: undefined,
68
69
  // By default, each file of a selection is uploaded using an individual
69
70
  // request for XHR type uploads. Set to false to upload file
@@ -108,6 +109,10 @@
108
109
  // global progress calculation. Set the following option to false to
109
110
  // prevent recalculating the global progress data:
110
111
  recalculateProgress: true,
112
+ // Interval in milliseconds to calculate and trigger progress events:
113
+ progressInterval: 100,
114
+ // Interval in milliseconds to calculate progress bitrate:
115
+ bitrateInterval: 500,
111
116
 
112
117
  // Additional form data to be sent along with the file uploads can be set
113
118
  // using this option, which accepts an array of objects with name and
@@ -179,6 +184,21 @@
179
184
  'forceIframeTransport'
180
185
  ],
181
186
 
187
+ _BitrateTimer: function () {
188
+ this.timestamp = +(new Date());
189
+ this.loaded = 0;
190
+ this.bitrate = 0;
191
+ this.getBitrate = function (now, loaded, interval) {
192
+ var timeDiff = now - this.timestamp;
193
+ if (!this.bitrate || !interval || timeDiff > interval) {
194
+ this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8;
195
+ this.loaded = loaded;
196
+ this.timestamp = now;
197
+ }
198
+ return this.bitrate;
199
+ };
200
+ },
201
+
182
202
  _isXHRUpload: function (options) {
183
203
  return !options.forceIframeTransport &&
184
204
  ((!options.multipart && $.support.xhrFileUpload) ||
@@ -189,9 +209,11 @@
189
209
  var formData;
190
210
  if (typeof options.formData === 'function') {
191
211
  return options.formData(options.form);
192
- } else if ($.isArray(options.formData)) {
212
+ }
213
+ if ($.isArray(options.formData)) {
193
214
  return options.formData;
194
- } else if (options.formData) {
215
+ }
216
+ if (options.formData) {
195
217
  formData = [];
196
218
  $.each(options.formData, function (name, value) {
197
219
  formData.push({name: name, value: value});
@@ -211,15 +233,29 @@
211
233
 
212
234
  _onProgress: function (e, data) {
213
235
  if (e.lengthComputable) {
214
- var total = data.total || this._getTotal(data.files),
215
- loaded = parseInt(
216
- e.loaded / e.total * (data.chunkSize || total),
217
- 10
218
- ) + (data.uploadedBytes || 0);
236
+ var now = +(new Date()),
237
+ total,
238
+ loaded;
239
+ if (data._time && data.progressInterval &&
240
+ (now - data._time < data.progressInterval) &&
241
+ e.loaded !== e.total) {
242
+ return;
243
+ }
244
+ data._time = now;
245
+ total = data.total || this._getTotal(data.files);
246
+ loaded = parseInt(
247
+ e.loaded / e.total * (data.chunkSize || total),
248
+ 10
249
+ ) + (data.uploadedBytes || 0);
219
250
  this._loaded += loaded - (data.loaded || data.uploadedBytes || 0);
220
251
  data.lengthComputable = true;
221
252
  data.loaded = loaded;
222
253
  data.total = total;
254
+ data.bitrate = data._bitrateTimer.getBitrate(
255
+ now,
256
+ loaded,
257
+ data.bitrateInterval
258
+ );
223
259
  // Trigger a custom progress event with a total data property set
224
260
  // to the file size(s) of the current upload and a loaded data
225
261
  // property calculated accordingly:
@@ -229,7 +265,12 @@
229
265
  this._trigger('progressall', e, {
230
266
  lengthComputable: true,
231
267
  loaded: this._loaded,
232
- total: this._total
268
+ total: this._total,
269
+ bitrate: this._bitrateTimer.getBitrate(
270
+ now,
271
+ this._loaded,
272
+ data.bitrateInterval
273
+ )
233
274
  });
234
275
  }
235
276
  },
@@ -258,7 +299,8 @@
258
299
  var formData,
259
300
  file = options.files[0],
260
301
  // Ignore non-multipart setting if not supported:
261
- multipart = options.multipart || !$.support.xhrFileUpload;
302
+ multipart = options.multipart || !$.support.xhrFileUpload,
303
+ paramName = options.paramName[0];
262
304
  if (!multipart || options.blob) {
263
305
  // For non-multipart uploads and chunked uploads,
264
306
  // file meta data is not part of the request body,
@@ -290,13 +332,13 @@
290
332
  formData = this._getFormData(options);
291
333
  if (options.blob) {
292
334
  formData.push({
293
- name: options.paramName,
335
+ name: paramName,
294
336
  value: options.blob
295
337
  });
296
338
  } else {
297
339
  $.each(options.files, function (index, file) {
298
340
  formData.push({
299
- name: options.paramName,
341
+ name: options.paramName[index] || paramName,
300
342
  value: file
301
343
  });
302
344
  });
@@ -311,14 +353,18 @@
311
353
  });
312
354
  }
313
355
  if (options.blob) {
314
- formData.append(options.paramName, options.blob, file.name);
356
+ formData.append(paramName, options.blob, file.name);
315
357
  } else {
316
358
  $.each(options.files, function (index, file) {
317
359
  // File objects are also Blob instances.
318
360
  // This check allows the tests to run with
319
361
  // dummy objects:
320
362
  if (file instanceof Blob) {
321
- formData.append(options.paramName, file, file.name);
363
+ formData.append(
364
+ options.paramName[index] || paramName,
365
+ file,
366
+ file.name
367
+ );
322
368
  }
323
369
  });
324
370
  }
@@ -362,16 +408,36 @@
362
408
  }
363
409
  },
364
410
 
411
+ _getParamName: function (options) {
412
+ var fileInput = $(options.fileInput),
413
+ paramName = options.paramName;
414
+ if (!paramName) {
415
+ paramName = [];
416
+ fileInput.each(function () {
417
+ var input = $(this),
418
+ name = input.prop('name') || 'files[]',
419
+ i = (input.prop('files') || [1]).length;
420
+ while (i) {
421
+ paramName.push(name);
422
+ i -= 1;
423
+ }
424
+ });
425
+ if (!paramName.length) {
426
+ paramName = [fileInput.prop('name') || 'files[]'];
427
+ }
428
+ } else if (!$.isArray(paramName)) {
429
+ paramName = [paramName];
430
+ }
431
+ return paramName;
432
+ },
433
+
365
434
  _initFormSettings: function (options) {
366
435
  // Retrieve missing options from the input field and the
367
436
  // associated form, if available:
368
437
  if (!options.form || !options.form.length) {
369
438
  options.form = $(options.fileInput.prop('form'));
370
439
  }
371
- if (!options.paramName) {
372
- options.paramName = options.fileInput.prop('name') ||
373
- 'files[]';
374
- }
440
+ options.paramName = this._getParamName(options);
375
441
  if (!options.url) {
376
442
  options.url = options.form.prop('action') || location.href;
377
443
  }
@@ -504,6 +570,8 @@
504
570
  // and no other uploads are currently running,
505
571
  // equivalent to the global ajaxStart event:
506
572
  this._trigger('start');
573
+ // Set timer for global bitrate progress calculation:
574
+ this._bitrateTimer = new this._BitrateTimer();
507
575
  }
508
576
  this._active += 1;
509
577
  // Initialize the global progress values:
@@ -556,6 +624,7 @@
556
624
  this._trigger('stop');
557
625
  // Reset the global progress values:
558
626
  this._loaded = this._total = 0;
627
+ this._bitrateTimer = null;
559
628
  }
560
629
  },
561
630
 
@@ -567,6 +636,8 @@
567
636
  options = that._getAJAXSettings(data),
568
637
  send = function (resolve, args) {
569
638
  that._sending += 1;
639
+ // Set timer for bitrate progress calculation:
640
+ options._bitrateTimer = new that._BitrateTimer();
570
641
  jqXHR = jqXHR || (
571
642
  (resolve !== false &&
572
643
  that._trigger('send', e, options) !== false &&
@@ -634,21 +705,34 @@
634
705
  result = true,
635
706
  options = $.extend({}, this.options, data),
636
707
  limit = options.limitMultiFileUploads,
708
+ paramName = this._getParamName(options),
709
+ paramNameSet,
710
+ paramNameSlice,
637
711
  fileSet,
638
712
  i;
639
713
  if (!(options.singleFileUploads || limit) ||
640
714
  !this._isXHRUpload(options)) {
641
715
  fileSet = [data.files];
716
+ paramNameSet = [paramName];
642
717
  } else if (!options.singleFileUploads && limit) {
643
718
  fileSet = [];
719
+ paramNameSet = [];
644
720
  for (i = 0; i < data.files.length; i += limit) {
645
721
  fileSet.push(data.files.slice(i, i + limit));
722
+ paramNameSlice = paramName.slice(i, i + limit);
723
+ if (!paramNameSlice.length) {
724
+ paramNameSlice = paramName;
725
+ }
726
+ paramNameSet.push(paramNameSlice);
646
727
  }
728
+ } else {
729
+ paramNameSet = paramName;
647
730
  }
648
731
  data.originalFiles = data.files;
649
732
  $.each(fileSet || data.files, function (index, element) {
650
- var files = fileSet ? element : [element],
651
- newData = $.extend({}, data, {files: files});
733
+ var newData = $.extend({}, data);
734
+ newData.files = fileSet ? element : [element];
735
+ newData.paramName = paramNameSet[index];
652
736
  newData.submit = function () {
653
737
  newData.jqXHR = this.jqXHR =
654
738
  (that._trigger('submit', e, this) !== false) &&
@@ -807,10 +891,9 @@
807
891
  },
808
892
 
809
893
  _create: function () {
810
- var options = this.options,
811
- dataOpts = $.extend({}, this.element.data());
812
- dataOpts[this.widgetName] = undefined;
813
- $.extend(options, dataOpts);
894
+ var options = this.options;
895
+ // Initialize options set via HTML5 data-attributes:
896
+ $.extend(options, $(this.element[0].cloneNode(false)).data());
814
897
  options.namespace = options.namespace || this.widgetName;
815
898
  this._initSpecialOptions();
816
899
  this._slots = [];
@@ -1,5 +1,5 @@
1
1
  /*
2
- * jQuery Iframe Transport Plugin 1.3
2
+ * jQuery Iframe Transport Plugin 1.4
3
3
  * https://github.com/blueimp/jQuery-File-Upload
4
4
  *
5
5
  * Copyright 2011, Sebastian Tschan
@@ -30,7 +30,8 @@
30
30
  // The iframe transport accepts three additional options:
31
31
  // options.fileInput: a jQuery collection of file input fields
32
32
  // options.paramName: the parameter name for the file form data,
33
- // overrides the name property of the file input field(s)
33
+ // overrides the name property of the file input field(s),
34
+ // can be a string or an array of strings.
34
35
  // options.formData: an array of objects with name and value properties,
35
36
  // equivalent to the return data of .serializeArray(), e.g.:
36
37
  // [{name: 'a', value: 1}, {name: 'b', value: 2}]
@@ -50,7 +51,9 @@
50
51
  '<iframe src="javascript:false;" name="iframe-transport-' +
51
52
  (counter += 1) + '"></iframe>'
52
53
  ).bind('load', function () {
53
- var fileInputClones;
54
+ var fileInputClones,
55
+ paramNames = $.isArray(options.paramName) ?
56
+ options.paramName : [options.paramName];
54
57
  iframe
55
58
  .unbind('load')
56
59
  .bind('load', function () {
@@ -101,8 +104,11 @@
101
104
  return fileInputClones[index];
102
105
  });
103
106
  if (options.paramName) {
104
- options.fileInput.each(function () {
105
- $(this).prop('name', options.paramName);
107
+ options.fileInput.each(function (index) {
108
+ $(this).prop(
109
+ 'name',
110
+ paramNames[index] || options.paramName
111
+ );
106
112
  });
107
113
  }
108
114
  // Appending the file input fields to the hidden form
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jquery.fileupload-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-15 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2012-06-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: sprockets
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '2.0'
14
30
  description: This gem packages jQuery File Upload plugin and it's dependencies for
15
31
  Rails asset pipeline.
16
32
  email:
@@ -26,6 +42,7 @@ files:
26
42
  - jquery.fileupload-rails.gemspec
27
43
  - lib/jquery.fileupload-rails.rb
28
44
  - lib/jquery.fileupload-rails/version.rb
45
+ - vendor/assets/javascripts/jquery.fileupload-fp.js
29
46
  - vendor/assets/javascripts/jquery.fileupload-ip.js
30
47
  - vendor/assets/javascripts/jquery.fileupload-ui.js
31
48
  - vendor/assets/javascripts/jquery.fileupload.js
@@ -53,9 +70,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
53
70
  version: '0'
54
71
  requirements: []
55
72
  rubyforge_project: jquery.fileupload-rails
56
- rubygems_version: 1.8.11
73
+ rubygems_version: 1.8.23
57
74
  signing_key:
58
75
  specification_version: 3
59
76
  summary: Use jQuery File Upload plugin with Rails 3
60
77
  test_files: []
61
- has_rdoc: