glebtv-rails-uploader 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +48 -146
  3. data/Rakefile +2 -2
  4. data/app/assets/javascripts/uploader/application.js +5 -6
  5. data/app/assets/javascripts/uploader/rails_admin.js +6 -25
  6. data/app/assets/stylesheets/uploader/application.css.sass +2 -0
  7. data/app/assets/stylesheets/uploader/{application.css → application.css.scss} +0 -0
  8. data/app/controllers/uploader/attachments_controller.rb +28 -50
  9. data/app/views/rails_admin/main/_form_rails_uploader.haml +1 -10
  10. data/app/views/uploader/default/_container.html.erb +49 -64
  11. data/app/views/uploader/default/_download.html.erb +16 -12
  12. data/app/views/uploader/default/_upload.html.erb +2 -2
  13. data/config/routes.rb +1 -5
  14. data/lib/glebtv-rails-uploader.rb +0 -1
  15. data/lib/uploader.rb +5 -5
  16. data/lib/uploader/asset.rb +84 -41
  17. data/lib/uploader/engine.rb +10 -6
  18. data/lib/uploader/fileuploads.rb +53 -31
  19. data/lib/uploader/helpers/field_tag.rb +24 -35
  20. data/lib/uploader/helpers/form_builder.rb +1 -1
  21. data/lib/uploader/helpers/form_tag_helper.rb +2 -3
  22. data/lib/uploader/hooks/formtastic.rb +10 -4
  23. data/lib/uploader/hooks/simple_form.rb +1 -3
  24. data/lib/uploader/version.rb +1 -1
  25. data/spec/dummy/app/models/article.rb +3 -7
  26. data/spec/dummy/app/models/asset.rb +26 -19
  27. data/spec/dummy/app/models/picture.rb +4 -4
  28. data/spec/dummy/config/application.rb +5 -7
  29. data/spec/dummy/config/environments/development.rb +1 -5
  30. data/spec/dummy/config/environments/production.rb +0 -4
  31. data/spec/dummy/config/environments/test.rb +2 -6
  32. data/spec/dummy/db/migrate/20120508093416_create_assets.rb +3 -1
  33. data/spec/factories/articles.rb +1 -0
  34. data/spec/factories/assets.rb +1 -0
  35. data/spec/fileuploads_spec.rb +2 -2
  36. data/spec/mongoid_spec.rb +4 -6
  37. data/spec/requests/attachments_controller_spec.rb +10 -2
  38. data/spec/spec_helper.rb +7 -3
  39. data/spec/uploader_spec.rb +1 -1
  40. data/{app → vendor}/assets/images/uploader/but_del_tag2.png +0 -0
  41. data/{app → vendor}/assets/images/uploader/ico_attach.png +0 -0
  42. data/{app → vendor}/assets/images/uploader/preloader.gif +0 -0
  43. data/{app → vendor}/assets/images/uploader/progressBarFillBg.png +0 -0
  44. data/vendor/assets/javascripts/uploader/jquery.fileupload-fp.js +8 -4
  45. data/{app → vendor}/assets/javascripts/uploader/jquery.fileupload-ui.js +219 -44
  46. data/{app → vendor}/assets/javascripts/uploader/jquery.fileupload.js +16 -74
  47. data/{app → vendor}/assets/javascripts/uploader/jquery.iframe-transport.js +3 -9
  48. data/vendor/assets/javascripts/uploader/load-image.min.js +1 -0
  49. data/{app → vendor}/assets/javascripts/uploader/locales/en.js +0 -0
  50. data/{app → vendor}/assets/javascripts/uploader/locales/ru.js +0 -0
  51. data/{app → vendor}/assets/javascripts/uploader/locales/uk.js +0 -0
  52. data/vendor/assets/javascripts/uploader/tmpl.min.js +1 -0
  53. data/{app/assets/stylesheets/uploader/default.css → vendor/assets/stylesheets/uploader/default.css.scss} +3 -11
  54. data/{app/assets/stylesheets/uploader/jquery.fileupload-ui.css → vendor/assets/stylesheets/uploader/jquery.fileupload-ui.css.scss} +0 -0
  55. metadata +78 -146
  56. data/app/assets/javascripts/uploader/canvas-to-blob.js +0 -95
  57. data/app/assets/javascripts/uploader/jquery.fileupload-angular.js +0 -348
  58. data/app/assets/javascripts/uploader/jquery.fileupload-process.js +0 -158
  59. data/app/assets/javascripts/uploader/jquery.fileupload-resize.js +0 -212
  60. data/app/assets/javascripts/uploader/jquery.fileupload-validate.js +0 -116
  61. data/app/assets/javascripts/uploader/jquery.ui.widget.js +0 -530
  62. data/app/assets/javascripts/uploader/load-image.js +0 -381
  63. data/app/assets/javascripts/uploader/tmpl.js +0 -86
  64. data/lib/file_size_validator.rb +0 -68
  65. data/spec/dummy/config/mongoid.yml +0 -12
@@ -8,7 +8,7 @@ describe Uploader do
8
8
  it "should generate random string" do
9
9
  value = Uploader.guid
10
10
  value.should_not be_blank
11
- value.size.should == 10
11
+ value.size.should == 20
12
12
  end
13
13
 
14
14
  it "should find all precompile assets" do
@@ -1,5 +1,5 @@
1
1
  /*
2
- * jQuery File Upload File Processing Plugin 1.2.1
2
+ * jQuery File Upload File Processing Plugin 1.2.3
3
3
  * https://github.com/blueimp/jQuery-File-Upload
4
4
  *
5
5
  * Copyright 2012, Sebastian Tschan
@@ -62,9 +62,13 @@
62
62
  // fileupload widget (via file input selection, drag & drop or add
63
63
  // API call). See the basic file upload widget for more information:
64
64
  add: function (e, data) {
65
- $(this).fileupload('process', data).done(function () {
66
- data.submit();
67
- });
65
+ if (data.autoUpload || (data.autoUpload !== false &&
66
+ ($(this).data('blueimp-fileupload') ||
67
+ $(this).data('fileupload')).options.autoUpload)) {
68
+ $(this).fileupload('process', data).done(function () {
69
+ data.submit();
70
+ });
71
+ }
68
72
  }
69
73
  },
70
74
 
@@ -1,5 +1,5 @@
1
1
  /*
2
- * jQuery File Upload User Interface Plugin 8.2.1
2
+ * jQuery File Upload User Interface Plugin 7.4.4
3
3
  * https://github.com/blueimp/jQuery-File-Upload
4
4
  *
5
5
  * Copyright 2010, Sebastian Tschan
@@ -19,25 +19,20 @@
19
19
  define([
20
20
  'jquery',
21
21
  'tmpl',
22
- './jquery.fileupload-resize',
23
- './jquery.fileupload-validate'
22
+ 'load-image',
23
+ './jquery.fileupload-fp'
24
24
  ], factory);
25
25
  } else {
26
26
  // Browser globals:
27
27
  factory(
28
28
  window.jQuery,
29
- window.tmpl
29
+ window.tmpl,
30
+ window.loadImage
30
31
  );
31
32
  }
32
33
  }(function ($, tmpl, loadImage) {
33
34
  'use strict';
34
35
 
35
- $.blueimp.fileupload.prototype._specialOptions.push(
36
- 'filesContainer',
37
- 'uploadTemplateId',
38
- 'downloadTemplateId'
39
- );
40
-
41
36
  // The UI version extends the file upload widget
42
37
  // and adds complete user interface interaction:
43
38
  $.widget('blueimp.fileupload', $.blueimp.fileupload, {
@@ -47,6 +42,29 @@
47
42
  // as the user clicks on the start buttons. To enable automatic
48
43
  // uploads, set the following option to true:
49
44
  autoUpload: false,
45
+ // The following option limits the number of files that are
46
+ // allowed to be uploaded using this widget:
47
+ maxNumberOfFiles: undefined,
48
+ // The maximum allowed file size:
49
+ maxFileSize: undefined,
50
+ // The minimum allowed file size:
51
+ minFileSize: undefined,
52
+ // The regular expression for allowed file types, matches
53
+ // against either file type or file name:
54
+ acceptFileTypes: /.+$/i,
55
+ // The regular expression to define for which files a preview
56
+ // image is shown, matched against the file type:
57
+ previewSourceFileTypes: /^image\/(gif|jpeg|png)$/,
58
+ // The maximum file size of images that are to be displayed as preview:
59
+ previewSourceMaxFileSize: 5000000, // 5MB
60
+ // The maximum width of the preview images:
61
+ previewMaxWidth: 80,
62
+ // The maximum height of the preview images:
63
+ previewMaxHeight: 80,
64
+ // By default, preview images are displayed as canvas elements
65
+ // if supported by the browser. Set the following option to false
66
+ // to always display preview images as img elements:
67
+ previewAsCanvas: true,
50
68
  // The ID of the upload template:
51
69
  uploadTemplateId: 'template-upload',
52
70
  // The ID of the download template:
@@ -61,43 +79,29 @@
61
79
  // option of the $.ajax upload requests:
62
80
  dataType: 'json',
63
81
 
64
- // Function returning the current number of files,
65
- // used by the maxNumberOfFiles validation:
66
- getNumberOfFiles: function () {
67
- return this.filesContainer.children().length;
68
- },
69
-
70
- // Callback to retrieve the list of files from the server response:
71
- getFilesFromResponse: function (data) {
72
- if (data.result && $.isArray(data.result.files)) {
73
- return data.result.files;
74
- }
75
- return [];
76
- },
77
-
78
82
  // The add callback is invoked as soon as files are added to the fileupload
79
83
  // widget (via file input selection, drag & drop or add API call).
80
84
  // See the basic file upload widget for more information:
81
85
  add: function (e, data) {
82
- var $this = $(this),
83
- that = $this.data('blueimp-fileupload') ||
84
- $this.data('fileupload'),
86
+ var that = $(this).data('blueimp-fileupload') ||
87
+ $(this).data('fileupload'),
85
88
  options = that.options,
86
89
  files = data.files;
87
- data.process(function () {
88
- return $this.fileupload('process', data);
89
- }).always(function () {
90
+ $(this).fileupload('process', data).done(function () {
91
+ that._adjustMaxNumberOfFiles(-files.length);
92
+ data.maxNumberOfFilesAdjusted = true;
93
+ data.files.valid = data.isValidated = that._validate(files);
90
94
  data.context = that._renderUpload(files).data('data', data);
91
- that._renderPreviews(data);
92
95
  options.filesContainer[
93
96
  options.prependFiles ? 'prepend' : 'append'
94
97
  ](data.context);
98
+ that._renderPreviews(data);
95
99
  that._forceReflow(data.context);
96
100
  that._transition(data.context).done(
97
101
  function () {
98
102
  if ((that._trigger('added', e, data) !== false) &&
99
103
  (options.autoUpload || data.autoUpload) &&
100
- data.autoUpload !== false && !data.files.error) {
104
+ data.autoUpload !== false && data.isValidated) {
101
105
  data.submit();
102
106
  }
103
107
  }
@@ -108,6 +112,15 @@
108
112
  send: function (e, data) {
109
113
  var that = $(this).data('blueimp-fileupload') ||
110
114
  $(this).data('fileupload');
115
+ if (!data.isValidated) {
116
+ if (!data.maxNumberOfFilesAdjusted) {
117
+ that._adjustMaxNumberOfFiles(-data.files.length);
118
+ data.maxNumberOfFilesAdjusted = true;
119
+ }
120
+ if (!that._validate(data.files)) {
121
+ return false;
122
+ }
123
+ }
111
124
  if (data.context && data.dataType &&
112
125
  data.dataType.substr(0, 6) === 'iframe') {
113
126
  // Iframe Transport does not support progress events.
@@ -129,9 +142,7 @@
129
142
  done: function (e, data) {
130
143
  var that = $(this).data('blueimp-fileupload') ||
131
144
  $(this).data('fileupload'),
132
- getFilesFromResponse = data.getFilesFromResponse ||
133
- that.options.getFilesFromResponse,
134
- files = getFilesFromResponse(data),
145
+ files = that._getFilesFromResponse(data),
135
146
  template,
136
147
  deferred;
137
148
  if (data.context) {
@@ -139,6 +150,9 @@
139
150
  var file = files[index] ||
140
151
  {error: 'Empty file upload result'},
141
152
  deferred = that._addFinishedDeferreds();
153
+ if (file.error) {
154
+ that._adjustMaxNumberOfFiles(1);
155
+ }
142
156
  that._transition($(this)).done(
143
157
  function () {
144
158
  var node = $(this);
@@ -157,6 +171,17 @@
157
171
  );
158
172
  });
159
173
  } else {
174
+ if (files.length) {
175
+ $.each(files, function (index, file) {
176
+ if (data.maxNumberOfFilesAdjusted && file.error) {
177
+ that._adjustMaxNumberOfFiles(1);
178
+ } else if (!data.maxNumberOfFilesAdjusted &&
179
+ !file.error) {
180
+ that._adjustMaxNumberOfFiles(-1);
181
+ }
182
+ });
183
+ data.maxNumberOfFilesAdjusted = true;
184
+ }
160
185
  template = that._renderDownload(files)
161
186
  .appendTo(that.options.filesContainer);
162
187
  that._forceReflow(template);
@@ -177,6 +202,9 @@
177
202
  $(this).data('fileupload'),
178
203
  template,
179
204
  deferred;
205
+ if (data.maxNumberOfFilesAdjusted) {
206
+ that._adjustMaxNumberOfFiles(data.files.length);
207
+ }
180
208
  if (data.context) {
181
209
  data.context.each(function (index) {
182
210
  if (data.errorThrown !== 'abort') {
@@ -295,12 +323,6 @@
295
323
  }
296
324
  );
297
325
  },
298
- processstart: function () {
299
- $(this).addClass('fileupload-processing');
300
- },
301
- processstop: function () {
302
- $(this).removeClass('fileupload-processing');
303
- },
304
326
  // Callback for file deletion:
305
327
  destroy: function (e, data) {
306
328
  var that = $(this).data('blueimp-fileupload') ||
@@ -310,6 +332,7 @@
310
332
  that._transition(data.context).done(
311
333
  function () {
312
334
  $(this).remove();
335
+ that._adjustMaxNumberOfFiles(1);
313
336
  that._trigger('destroyed', e, data);
314
337
  }
315
338
  );
@@ -334,6 +357,13 @@
334
357
  return this._finishedUploads;
335
358
  },
336
359
 
360
+ _getFilesFromResponse: function (data) {
361
+ if (data.result && $.isArray(data.result.files)) {
362
+ return data.result.files;
363
+ }
364
+ return [];
365
+ },
366
+
337
367
  // Link handler, that allows to download files
338
368
  // by drag & drop of the links to the desktop:
339
369
  _enableDragToDesktop: function () {
@@ -347,10 +377,21 @@
347
377
  'DownloadURL',
348
378
  [type, name, url].join(':')
349
379
  );
350
- } catch (ignore) {}
380
+ } catch (err) {}
351
381
  });
352
382
  },
353
383
 
384
+ _adjustMaxNumberOfFiles: function (operand) {
385
+ if (typeof this.options.maxNumberOfFiles === 'number') {
386
+ this.options.maxNumberOfFiles += operand;
387
+ if (this.options.maxNumberOfFiles < 1) {
388
+ this._disableFileInputButton();
389
+ } else {
390
+ this._enableFileInputButton();
391
+ }
392
+ }
393
+ },
394
+
354
395
  _formatFileSize: function (bytes) {
355
396
  if (typeof bytes !== 'number') {
356
397
  return '';
@@ -406,6 +447,46 @@
406
447
  this._formatFileSize(data.total);
407
448
  },
408
449
 
450
+ _hasError: function (file) {
451
+ if (file.error) {
452
+ return file.error;
453
+ }
454
+ // The number of added files is subtracted from
455
+ // maxNumberOfFiles before validation, so we check if
456
+ // maxNumberOfFiles is below 0 (instead of below 1):
457
+ if (this.options.maxNumberOfFiles < 0) {
458
+ return 'Maximum number of files exceeded';
459
+ }
460
+ // Files are accepted if either the file type or the file name
461
+ // matches against the acceptFileTypes regular expression, as
462
+ // only browsers with support for the File API report the type:
463
+ if (!(this.options.acceptFileTypes.test(file.type) ||
464
+ this.options.acceptFileTypes.test(file.name))) {
465
+ return 'Filetype not allowed';
466
+ }
467
+ if (this.options.maxFileSize &&
468
+ file.size > this.options.maxFileSize) {
469
+ return 'File is too big';
470
+ }
471
+ if (typeof file.size === 'number' &&
472
+ file.size < this.options.minFileSize) {
473
+ return 'File is too small';
474
+ }
475
+ return null;
476
+ },
477
+
478
+ _validate: function (files) {
479
+ var that = this,
480
+ valid = !!files.length;
481
+ $.each(files, function (index, file) {
482
+ file.error = that._hasError(file);
483
+ if (file.error) {
484
+ valid = false;
485
+ }
486
+ });
487
+ return valid;
488
+ },
489
+
409
490
  _renderTemplate: function (func, files) {
410
491
  if (!func) {
411
492
  return $();
@@ -421,10 +502,63 @@
421
502
  return $(this.options.templatesContainer).html(result).children();
422
503
  },
423
504
 
505
+ _renderPreview: function (file, node) {
506
+ var that = this,
507
+ options = this.options,
508
+ dfd = $.Deferred();
509
+ return ((loadImage && loadImage(
510
+ file,
511
+ function (img) {
512
+ node.append(img);
513
+ that._forceReflow(node);
514
+ that._transition(node).done(function () {
515
+ dfd.resolveWith(node);
516
+ });
517
+ if (!$.contains(that.document[0].body, node[0])) {
518
+ // If the element is not part of the DOM,
519
+ // transition events are not triggered,
520
+ // so we have to resolve manually:
521
+ dfd.resolveWith(node);
522
+ }
523
+ node.on('remove', function () {
524
+ // If the element is removed before the
525
+ // transition finishes, transition events are
526
+ // not triggered, resolve manually:
527
+ dfd.resolveWith(node);
528
+ });
529
+ },
530
+ {
531
+ maxWidth: options.previewMaxWidth,
532
+ maxHeight: options.previewMaxHeight,
533
+ canvas: options.previewAsCanvas
534
+ }
535
+ )) || dfd.resolveWith(node)) && dfd;
536
+ },
537
+
424
538
  _renderPreviews: function (data) {
425
- data.context.find('.preview').each(function (index, elm) {
426
- $(elm).append(data.files[index].preview);
539
+ var that = this,
540
+ options = this.options;
541
+ data.context.find('.preview span').each(function (index, element) {
542
+ var file = data.files[index];
543
+ if (options.previewSourceFileTypes.test(file.type) &&
544
+ ($.type(options.previewSourceMaxFileSize) !== 'number' ||
545
+ file.size < options.previewSourceMaxFileSize)) {
546
+ that._processingQueue = that._processingQueue.pipe(function () {
547
+ var dfd = $.Deferred(),
548
+ ev = $.Event('previewdone', {
549
+ target: element
550
+ });
551
+ that._renderPreview(file, $(element)).done(
552
+ function () {
553
+ that._trigger(ev.type, ev, data);
554
+ dfd.resolveWith(that);
555
+ }
556
+ );
557
+ return dfd.promise();
558
+ });
559
+ }
427
560
  });
561
+ return this._processingQueue;
428
562
  },
429
563
 
430
564
  _renderUpload: function (files) {
@@ -435,6 +569,7 @@
435
569
  },
436
570
 
437
571
  _renderDownload: function (files) {
572
+ console.log(files);
438
573
  return this._renderTemplate(
439
574
  this.options.downloadTemplate,
440
575
  files
@@ -597,14 +732,54 @@
597
732
  }
598
733
  },
599
734
 
735
+ _stringToRegExp: function (str) {
736
+ var parts = str.split('/'),
737
+ modifiers = parts.pop();
738
+ parts.shift();
739
+ return new RegExp(parts.join('/'), modifiers);
740
+ },
741
+
742
+ _initRegExpOptions: function () {
743
+ var options = this.options;
744
+ if ($.type(options.acceptFileTypes) === 'string') {
745
+ options.acceptFileTypes = this._stringToRegExp(
746
+ options.acceptFileTypes
747
+ );
748
+ }
749
+ if ($.type(options.previewSourceFileTypes) === 'string') {
750
+ options.previewSourceFileTypes = this._stringToRegExp(
751
+ options.previewSourceFileTypes
752
+ );
753
+ }
754
+ },
755
+
600
756
  _initSpecialOptions: function () {
601
757
  this._super();
602
758
  this._initFilesContainer();
603
759
  this._initTemplates();
760
+ this._initRegExpOptions();
761
+ },
762
+
763
+ _setOption: function (key, value) {
764
+ this._super(key, value);
765
+ if (key === 'maxNumberOfFiles') {
766
+ this._adjustMaxNumberOfFiles(0);
767
+ }
604
768
  },
605
769
 
606
770
  _create: function () {
607
771
  this._super();
772
+ this._refreshOptionsList.push(
773
+ 'filesContainer',
774
+ 'uploadTemplateId',
775
+ 'downloadTemplateId'
776
+ );
777
+ if (!this._processingQueue) {
778
+ this._processingQueue = $.Deferred().resolveWith(this).promise();
779
+ this.process = function () {
780
+ return this._processingQueue;
781
+ };
782
+ }
608
783
  this._resetFinishedDeferreds();
609
784
  },
610
785