s3_cors_fileupload 0.1.5 → 0.2.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.document +4 -3
  3. data/.gitignore +3 -7
  4. data/CHANGELOG.md +9 -1
  5. data/Gemfile +11 -11
  6. data/Gemfile.lock +66 -74
  7. data/README.md +4 -3
  8. data/Rakefile +7 -9
  9. data/lib/generators/s3_cors_fileupload/install/templates/s3_uploads.js +16 -22
  10. data/lib/generators/s3_cors_fileupload/install/templates/s3_uploads_controller.rb +1 -1
  11. data/lib/generators/s3_cors_fileupload/install/templates/source_file.rb +2 -2
  12. data/lib/generators/s3_cors_fileupload/install/templates/views/erb/_template_download.html.erb +2 -2
  13. data/lib/generators/s3_cors_fileupload/install/templates/views/erb/_template_upload.html.erb +4 -4
  14. data/lib/generators/s3_cors_fileupload/install/templates/views/erb/_template_uploaded.html.erb +1 -1
  15. data/lib/generators/s3_cors_fileupload/install/templates/views/erb/index.html.erb +2 -2
  16. data/lib/generators/s3_cors_fileupload/install/templates/views/haml/_template_download.html.haml +2 -2
  17. data/lib/generators/s3_cors_fileupload/install/templates/views/haml/_template_upload.html.haml +4 -4
  18. data/lib/generators/s3_cors_fileupload/install/templates/views/haml/_template_uploaded.html.haml +2 -2
  19. data/lib/generators/s3_cors_fileupload/install/templates/views/haml/index.html.haml +2 -2
  20. data/lib/s3_cors_fileupload/rails/config.rb +0 -1
  21. data/lib/s3_cors_fileupload/rails/form_helper.rb +2 -4
  22. data/lib/s3_cors_fileupload/rails/policy_helper.rb +2 -2
  23. data/lib/s3_cors_fileupload/version.rb +3 -3
  24. data/s3_cors_fileupload.gemspec +12 -15
  25. data/spec/dummy/Rakefile +7 -0
  26. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  27. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  28. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  29. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  30. data/spec/dummy/app/models/.gitkeep +0 -0
  31. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  32. data/spec/dummy/config.ru +4 -0
  33. data/spec/dummy/config/amazon_s3.yml +17 -0
  34. data/spec/dummy/config/application.rb +64 -0
  35. data/spec/dummy/config/boot.rb +10 -0
  36. data/spec/dummy/config/database.yml +25 -0
  37. data/spec/dummy/config/environment.rb +5 -0
  38. data/spec/dummy/config/environments/development.rb +37 -0
  39. data/spec/dummy/config/environments/production.rb +67 -0
  40. data/spec/dummy/config/environments/test.rb +37 -0
  41. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  42. data/spec/dummy/config/initializers/inflections.rb +15 -0
  43. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  44. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  45. data/spec/dummy/config/initializers/session_store.rb +8 -0
  46. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  47. data/spec/dummy/config/locales/en.yml +5 -0
  48. data/spec/dummy/config/routes.rb +58 -0
  49. data/spec/dummy/db/.gitkeep +0 -0
  50. data/spec/dummy/lib/assets/.gitkeep +0 -0
  51. data/spec/dummy/log/.gitkeep +0 -0
  52. data/spec/dummy/public/404.html +26 -0
  53. data/spec/dummy/public/422.html +26 -0
  54. data/spec/dummy/public/500.html +25 -0
  55. data/spec/dummy/public/favicon.ico +0 -0
  56. data/spec/dummy/script/rails +6 -0
  57. data/spec/lib/generators/install/install_generator_spec.rb +160 -0
  58. data/spec/lib/s3_cors_fileupload/rails/config_spec.rb +43 -0
  59. data/spec/{s3_cors_fileupload → lib/s3_cors_fileupload}/version_spec.rb +0 -0
  60. data/spec/spec_helper.rb +11 -2
  61. data/vendor/assets/javascripts/s3_cors_fileupload/jquery.fileupload-ui.js +117 -43
  62. data/vendor/assets/javascripts/s3_cors_fileupload/jquery.fileupload.js +187 -92
  63. data/vendor/assets/javascripts/s3_cors_fileupload/jquery.iframe-transport.js +20 -7
  64. data/vendor/assets/javascripts/s3_cors_fileupload/vendor/jquery.ui.widget.js +72 -53
  65. data/vendor/assets/javascripts/s3_cors_fileupload/vendor/load-image.js +225 -37
  66. data/vendor/assets/stylesheets/jquery.fileupload-ui.css.erb +6 -8
  67. metadata +78 -21
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'ffaker'
3
+
4
+ describe S3CorsFileupload::Config do
5
+ subject { S3CorsFileupload::Config }
6
+
7
+ it { should be_instance_of(Module) }
8
+
9
+ describe :method_missing do
10
+ context "arguments received" do
11
+ it "should raise a NoMethodError" do
12
+ expect { subject.foobar(:arg) }.to raise_error(NoMethodError)
13
+ expect { subject.access_key_id(:hai) }.to raise_error(NoMethodError)
14
+ end
15
+ end
16
+
17
+ context "block received" do
18
+ it "should raise a NoMethodError" do
19
+ expect { subject.foobar { :foobar } }.to raise_error(NoMethodError)
20
+ expect { subject.access_key_id { :block } }.to raise_error(NoMethodError)
21
+ end
22
+ end
23
+
24
+ context "no arguments or block received" do
25
+ context "key doesn't exist on `config/amazon_s3.yml`" do
26
+ its(:foobar) { should be_nil }
27
+ 10.times do
28
+ its(Faker::Lorem.word.to_sym) { should be_nil }
29
+ end
30
+ end
31
+
32
+ context "key exists on `config/amazon_s3.yml`" do
33
+ describe "it should return the value associated with the key" do
34
+ its(:access_key_id) { should == 'your_access_key_id' }
35
+ its(:secret_access_key) { should == 'your_secret_access_key' }
36
+ its(:acl) { should == 'public-read' }
37
+ its(:max_file_size) { should == 524288000 }
38
+ its(:bucket) { should == 'your_development_bucket_name' }
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  ENV["RAILS_ENV"] ||= 'test'
2
2
  require File.expand_path('../dummy/config/environment', __FILE__)
3
+ # the gem's library gets included through a require statement on 'dummy/config/application.rb'
3
4
  require 'rspec/rails'
4
5
  require 'rspec/autorun'
5
6
 
@@ -10,7 +11,7 @@ Dir[::Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
10
11
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
11
12
  RSpec.configure do |config|
12
13
  config.treat_symbols_as_metadata_keys_with_true_values = true
13
-
14
+
14
15
  # ## Mock Framework
15
16
  #
16
17
  # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
@@ -20,7 +21,7 @@ RSpec.configure do |config|
20
21
  # config.mock_with :rr
21
22
 
22
23
  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
23
- config.fixture_path = "#{::Rails.root}/spec/fixtures"
24
+ # config.fixture_path = "#{::Rails.root}/spec/fixtures"
24
25
 
25
26
  # If you're not using ActiveRecord, or you'd prefer not to run each of your
26
27
  # examples within a transaction, remove the following line or assign false
@@ -37,4 +38,12 @@ RSpec.configure do |config|
37
38
  # the seed, which is printed after each run.
38
39
  # --seed 1234
39
40
  config.order = 'random'
41
+
42
+ # Prep for running the test suite
43
+ config.before(:all) do
44
+ # Invoke the generator for the gem.
45
+ # ::Rails::Generators.invoke('s3_cors_fileupload:install')
46
+ # Run any migrations for the dummy app prior to running the spec suite.
47
+ # ActiveRecord::Migrator.migrate "#{::Rails.root}/db/migrate"
48
+ end
40
49
  end
@@ -1,5 +1,5 @@
1
1
  /*
2
- * jQuery File Upload User Interface Plugin 6.10
2
+ * jQuery File Upload User Interface Plugin 7.4.1
3
3
  * https://github.com/blueimp/jQuery-File-Upload
4
4
  *
5
5
  * Copyright 2010, Sebastian Tschan
@@ -83,7 +83,8 @@
83
83
  // widget (via file input selection, drag & drop or add API call).
84
84
  // See the basic file upload widget for more information:
85
85
  add: function (e, data) {
86
- var that = $(this).data('fileupload'),
86
+ var that = $(this).data('blueimp-fileupload') ||
87
+ $(this).data('fileupload'),
87
88
  options = that.options,
88
89
  files = data.files;
89
90
  $(this).fileupload('process', data).done(function () {
@@ -94,7 +95,7 @@
94
95
  options.filesContainer[
95
96
  options.prependFiles ? 'prepend' : 'append'
96
97
  ](data.context);
97
- that._renderPreviews(files, data.context);
98
+ that._renderPreviews(data);
98
99
  that._forceReflow(data.context);
99
100
  that._transition(data.context).done(
100
101
  function () {
@@ -109,7 +110,8 @@
109
110
  },
110
111
  // Callback for the start of each file upload request:
111
112
  send: function (e, data) {
112
- var that = $(this).data('fileupload');
113
+ var that = $(this).data('blueimp-fileupload') ||
114
+ $(this).data('fileupload');
113
115
  if (!data.isValidated) {
114
116
  if (!data.maxNumberOfFilesAdjusted) {
115
117
  that._adjustMaxNumberOfFiles(-data.files.length);
@@ -138,13 +140,16 @@
138
140
  },
139
141
  // Callback for successful uploads:
140
142
  done: function (e, data) {
141
- var that = $(this).data('fileupload'),
142
- template;
143
+ var that = $(this).data('blueimp-fileupload') ||
144
+ $(this).data('fileupload'),
145
+ files = that._getFilesFromResponse(data),
146
+ template,
147
+ deferred;
143
148
  if (data.context) {
144
149
  data.context.each(function (index) {
145
- var file = ($.isArray(data.result) &&
146
- data.result[index]) ||
147
- {error: 'Empty file upload result'};
150
+ var file = files[index] ||
151
+ {error: 'Empty file upload result'},
152
+ deferred = that._addFinishedDeferreds();
148
153
  if (file.error) {
149
154
  that._adjustMaxNumberOfFiles(1);
150
155
  }
@@ -158,14 +163,16 @@
158
163
  function () {
159
164
  data.context = $(this);
160
165
  that._trigger('completed', e, data);
166
+ that._trigger('finished', e, data);
167
+ deferred.resolve();
161
168
  }
162
169
  );
163
170
  }
164
171
  );
165
172
  });
166
173
  } else {
167
- if ($.isArray(data.result)) {
168
- $.each(data.result, function (index, file) {
174
+ if (files.length) {
175
+ $.each(files, function (index, file) {
169
176
  if (data.maxNumberOfFilesAdjusted && file.error) {
170
177
  that._adjustMaxNumberOfFiles(1);
171
178
  } else if (!data.maxNumberOfFilesAdjusted &&
@@ -175,21 +182,26 @@
175
182
  });
176
183
  data.maxNumberOfFilesAdjusted = true;
177
184
  }
178
- template = that._renderDownload(data.result)
185
+ template = that._renderDownload(files)
179
186
  .appendTo(that.options.filesContainer);
180
187
  that._forceReflow(template);
188
+ deferred = that._addFinishedDeferreds();
181
189
  that._transition(template).done(
182
190
  function () {
183
191
  data.context = $(this);
184
192
  that._trigger('completed', e, data);
193
+ that._trigger('finished', e, data);
194
+ deferred.resolve();
185
195
  }
186
196
  );
187
197
  }
188
198
  },
189
199
  // Callback for failed (abort or error) uploads:
190
200
  fail: function (e, data) {
191
- var that = $(this).data('fileupload'),
192
- template;
201
+ var that = $(this).data('blueimp-fileupload') ||
202
+ $(this).data('fileupload'),
203
+ template,
204
+ deferred;
193
205
  if (data.maxNumberOfFilesAdjusted) {
194
206
  that._adjustMaxNumberOfFiles(data.files.length);
195
207
  }
@@ -199,6 +211,7 @@
199
211
  var file = data.files[index];
200
212
  file.error = file.error || data.errorThrown ||
201
213
  true;
214
+ deferred = that._addFinishedDeferreds();
202
215
  that._transition($(this)).done(
203
216
  function () {
204
217
  var node = $(this);
@@ -209,15 +222,20 @@
209
222
  function () {
210
223
  data.context = $(this);
211
224
  that._trigger('failed', e, data);
225
+ that._trigger('finished', e, data);
226
+ deferred.resolve();
212
227
  }
213
228
  );
214
229
  }
215
230
  );
216
231
  } else {
232
+ deferred = that._addFinishedDeferreds();
217
233
  that._transition($(this)).done(
218
234
  function () {
219
235
  $(this).remove();
220
236
  that._trigger('failed', e, data);
237
+ that._trigger('finished', e, data);
238
+ deferred.resolve();
221
239
  }
222
240
  );
223
241
  }
@@ -227,20 +245,25 @@
227
245
  .appendTo(that.options.filesContainer)
228
246
  .data('data', data);
229
247
  that._forceReflow(data.context);
248
+ deferred = that._addFinishedDeferreds();
230
249
  that._transition(data.context).done(
231
250
  function () {
232
251
  data.context = $(this);
233
252
  that._trigger('failed', e, data);
253
+ that._trigger('finished', e, data);
254
+ deferred.resolve();
234
255
  }
235
256
  );
236
257
  } else {
237
258
  that._trigger('failed', e, data);
259
+ that._trigger('finished', e, data);
260
+ that._addFinishedDeferreds().resolve();
238
261
  }
239
262
  },
240
263
  // Callback for upload progress events:
241
264
  progress: function (e, data) {
242
265
  if (data.context) {
243
- var progress = parseInt(data.loaded / data.total * 100, 10);
266
+ var progress = Math.floor(data.loaded / data.total * 100);
244
267
  data.context.find('.progress')
245
268
  .attr('aria-valuenow', progress)
246
269
  .find('.bar').css(
@@ -252,13 +275,14 @@
252
275
  // Callback for global upload progress events:
253
276
  progressall: function (e, data) {
254
277
  var $this = $(this),
255
- progress = parseInt(data.loaded / data.total * 100, 10),
278
+ progress = Math.floor(data.loaded / data.total * 100),
256
279
  globalProgressNode = $this.find('.fileupload-progress'),
257
280
  extendedProgressNode = globalProgressNode
258
281
  .find('.progress-extended');
259
282
  if (extendedProgressNode.length) {
260
283
  extendedProgressNode.html(
261
- $this.data('fileupload')._renderExtendedProgress(data)
284
+ ($this.data('blueimp-fileupload') || $this.data('fileupload'))
285
+ ._renderExtendedProgress(data)
262
286
  );
263
287
  }
264
288
  globalProgressNode
@@ -271,7 +295,9 @@
271
295
  },
272
296
  // Callback for uploads start, equivalent to the global ajaxStart event:
273
297
  start: function (e) {
274
- var that = $(this).data('fileupload');
298
+ var that = $(this).data('blueimp-fileupload') ||
299
+ $(this).data('fileupload');
300
+ that._resetFinishedDeferreds();
275
301
  that._transition($(this).find('.fileupload-progress')).done(
276
302
  function () {
277
303
  that._trigger('started', e);
@@ -280,22 +306,29 @@
280
306
  },
281
307
  // Callback for uploads stop, equivalent to the global ajaxStop event:
282
308
  stop: function (e) {
283
- var that = $(this).data('fileupload');
309
+ var that = $(this).data('blueimp-fileupload') ||
310
+ $(this).data('fileupload'),
311
+ deferred = that._addFinishedDeferreds();
312
+ $.when.apply($, that._getFinishedDeferreds())
313
+ .done(function () {
314
+ that._trigger('stopped', e);
315
+ });
284
316
  that._transition($(this).find('.fileupload-progress')).done(
285
317
  function () {
286
318
  $(this).find('.progress')
287
319
  .attr('aria-valuenow', '0')
288
320
  .find('.bar').css('width', '0%');
289
321
  $(this).find('.progress-extended').html(' ');
290
- that._trigger('stopped', e);
322
+ deferred.resolve();
291
323
  }
292
324
  );
293
325
  },
294
326
  // Callback for file deletion:
295
327
  destroy: function (e, data) {
296
- if (data.confirm && !confirm(data.confirm))
328
+ if (data.confirmation && !confirm(data.confirmation))
297
329
  return; // abort the deletion if the user rejects the confirmation dialog
298
- var that = $(this).data('fileupload');
330
+ var that = $(this).data('blueimp-fileupload') ||
331
+ $(this).data('fileupload');
299
332
  if (data.url) {
300
333
  $.ajax(data);
301
334
  that._adjustMaxNumberOfFiles(1);
@@ -309,6 +342,29 @@
309
342
  }
310
343
  },
311
344
 
345
+ _resetFinishedDeferreds: function () {
346
+ this._finishedUploads = [];
347
+ },
348
+
349
+ _addFinishedDeferreds: function (deferred) {
350
+ if (!deferred) {
351
+ deferred = $.Deferred();
352
+ }
353
+ this._finishedUploads.push(deferred);
354
+ return deferred;
355
+ },
356
+
357
+ _getFinishedDeferreds: function () {
358
+ return this._finishedUploads;
359
+ },
360
+
361
+ _getFilesFromResponse: function (data) {
362
+ if (data.result && $.isArray(data.result.files)) {
363
+ return data.result.files;
364
+ }
365
+ return [];
366
+ },
367
+
312
368
  // Link handler, that allows to download files
313
369
  // by drag & drop of the links to the desktop:
314
370
  _enableDragToDesktop: function () {
@@ -363,12 +419,12 @@
363
419
  if (bits >= 1000) {
364
420
  return (bits / 1000).toFixed(2) + ' kbit/s';
365
421
  }
366
- return bits + ' bit/s';
422
+ return bits.toFixed(2) + ' bit/s';
367
423
  },
368
424
 
369
425
  _formatTime: function (seconds) {
370
426
  var date = new Date(seconds * 1000),
371
- days = parseInt(seconds / 86400, 10);
427
+ days = Math.floor(seconds / 86400);
372
428
  days = days ? days + 'd ' : '';
373
429
  return days +
374
430
  ('0' + date.getUTCHours()).slice(-2) + ':' +
@@ -465,6 +521,12 @@
465
521
  // so we have to resolve manually:
466
522
  dfd.resolveWith(node);
467
523
  }
524
+ node.on('remove', function () {
525
+ // If the element is removed before the
526
+ // transition finishes, transition events are
527
+ // not triggered, resolve manually:
528
+ dfd.resolveWith(node);
529
+ });
468
530
  },
469
531
  {
470
532
  maxWidth: options.previewMaxWidth,
@@ -474,18 +536,22 @@
474
536
  )) || dfd.resolveWith(node)) && dfd;
475
537
  },
476
538
 
477
- _renderPreviews: function (files, nodes) {
539
+ _renderPreviews: function (data) {
478
540
  var that = this,
479
541
  options = this.options;
480
- nodes.find('.preview span').each(function (index, element) {
481
- var file = files[index];
542
+ data.context.find('.preview span').each(function (index, element) {
543
+ var file = data.files[index];
482
544
  if (options.previewSourceFileTypes.test(file.type) &&
483
545
  ($.type(options.previewSourceMaxFileSize) !== 'number' ||
484
546
  file.size < options.previewSourceMaxFileSize)) {
485
547
  that._processingQueue = that._processingQueue.pipe(function () {
486
- var dfd = $.Deferred();
548
+ var dfd = $.Deferred(),
549
+ ev = $.Event('previewdone', {
550
+ target: element
551
+ });
487
552
  that._renderPreview(file, $(element)).done(
488
553
  function () {
554
+ that._trigger(ev.type, ev, data);
489
555
  dfd.resolveWith(that);
490
556
  }
491
557
  );
@@ -535,13 +601,11 @@
535
601
  _deleteHandler: function (e) {
536
602
  e.preventDefault();
537
603
  var button = $(e.currentTarget);
538
- this._trigger('destroy', e, {
604
+ this._trigger('destroy', e, $.extend({
539
605
  context: button.closest('.template-download'),
540
- url: button.attr('data-url'),
541
- type: button.attr('data-type') || 'DELETE',
542
- confirm: button.attr('data-confirmation'),
606
+ type: 'DELETE',
543
607
  dataType: this.options.dataType
544
- });
608
+ }, button.data()));
545
609
  },
546
610
 
547
611
  _forceReflow: function (node) {
@@ -551,7 +615,7 @@
551
615
 
552
616
  _transition: function (node) {
553
617
  var dfd = $.Deferred();
554
- if ($.support.transition && node.hasClass('fade')) {
618
+ if ($.support.transition && node.hasClass('fade') && node.is(':visible')) {
555
619
  node.bind(
556
620
  $.support.transition.end,
557
621
  function (e) {
@@ -576,27 +640,28 @@
576
640
  this._on(fileUploadButtonBar.find('.start'), {
577
641
  click: function (e) {
578
642
  e.preventDefault();
579
- filesList.find('.start button').click();
643
+ filesList.find('.start').click();
580
644
  }
581
645
  });
582
646
  this._on(fileUploadButtonBar.find('.cancel'), {
583
647
  click: function (e) {
584
648
  e.preventDefault();
585
- filesList.find('.cancel button').click();
649
+ filesList.find('.cancel').click();
586
650
  }
587
651
  });
588
652
  this._on(fileUploadButtonBar.find('.delete'), {
589
653
  click: function (e) {
590
654
  e.preventDefault();
591
- filesList.find('.delete input:checked')
592
- .siblings('button').click();
655
+ filesList.find('.toggle:checked')
656
+ .closest('.template-download')
657
+ .find('.delete').click();
593
658
  fileUploadButtonBar.find('.toggle')
594
659
  .prop('checked', false);
595
660
  }
596
661
  });
597
662
  this._on(fileUploadButtonBar.find('.toggle'), {
598
663
  change: function (e) {
599
- filesList.find('.delete input').prop(
664
+ filesList.find('.toggle').prop(
600
665
  'checked',
601
666
  $(e.currentTarget).is(':checked')
602
667
  );
@@ -606,7 +671,8 @@
606
671
 
607
672
  _destroyButtonBarEventHandlers: function () {
608
673
  this._off(
609
- this.element.find('.fileupload-buttonbar button'),
674
+ this.element.find('.fileupload-buttonbar')
675
+ .find('.start, .cancel, .delete'),
610
676
  'click'
611
677
  );
612
678
  this._off(
@@ -618,9 +684,9 @@
618
684
  _initEventHandlers: function () {
619
685
  this._super();
620
686
  this._on(this.options.filesContainer, {
621
- 'click .start button': this._startHandler,
622
- 'click .cancel button': this._cancelHandler,
623
- 'click .delete button': this._deleteHandler
687
+ 'click .start': this._startHandler,
688
+ 'click .cancel': this._cancelHandler,
689
+ 'click .delete': this._deleteHandler
624
690
  });
625
691
  this._initButtonBarEventHandlers();
626
692
  },
@@ -695,6 +761,13 @@
695
761
  this._initRegExpOptions();
696
762
  },
697
763
 
764
+ _setOption: function (key, value) {
765
+ this._super(key, value);
766
+ if (key === 'maxNumberOfFiles') {
767
+ this._adjustMaxNumberOfFiles(0);
768
+ }
769
+ },
770
+
698
771
  _create: function () {
699
772
  this._super();
700
773
  this._refreshOptionsList.push(
@@ -708,6 +781,7 @@
708
781
  return this._processingQueue;
709
782
  };
710
783
  }
784
+ this._resetFinishedDeferreds();
711
785
  },
712
786
 
713
787
  enable: function () {