jquery.fileupload-rails 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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: