uploadbox 0.1.4 → 0.2.0.beta

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 62eaeadebe7535bad0f7073a427adae552ca5f71
4
- data.tar.gz: 2f60ac42239cde465eb8af3b4b93aa10d9e38df6
3
+ metadata.gz: ceb2ca3efe6cd4d8445e02f68131325e8afd0f62
4
+ data.tar.gz: a3c2e0d3bad7ccd9b3b5f48c7f6b906d04e13545
5
5
  SHA512:
6
- metadata.gz: 1cee6a89123479d9ce8c2f3f964ac41a3deea5f303baccfa8db42daf576636fa2cc2721530bbcef671776ca7a7668335c3cb8ab6d9d9d9d417f510974d61d06f
7
- data.tar.gz: 4efde4d34b35e777d9fe107fd603df55271ff4b2e986b51b4a078f0afa3b18296b69eb667a82509afca2ba2441665bcc145c5bdbc520b5a05b26419bbb239a4c
6
+ metadata.gz: 5d82e4d94916edb0360dbde08f0abeca13abd56dcc71d91c9bd5238271ee06a4a0e7451896f8131bb1127f65684874e46ccb43d2ed26583a6cccc1bc66e41f2b
7
+ data.tar.gz: 99e05a4feed7f68e4937257679394877a57258fb6e5a755799339f080092bad9ee13d2fb0dfa6cbe6d428f8835ce5840c8d1356366a6acb218ee5229ae08c96c
data/README.md CHANGED
@@ -14,7 +14,7 @@ Make sure you have [ImageMagick](http://www.imagemagick.org/) installed.
14
14
 
15
15
  Add to Gemfile
16
16
  ```
17
- gem 'uploadbox', '0.1.3'
17
+ gem 'uploadbox', '0.1.4'
18
18
  ```
19
19
 
20
20
  Run generators
@@ -123,4 +123,12 @@ S3_BUCKET=uploads-production \
123
123
  Add Redis
124
124
  ```
125
125
  heroku addons:add rediscloud:20
126
- ```
126
+ ```
127
+
128
+ ## Upgrade from 0.1.x
129
+ If are upgrading from 0.1.x you will need to create a migration to add a column named `original_file` to the `images` table
130
+ ```
131
+ rails g migration add_original_file_to_images original_file:string
132
+ rake db:migrate
133
+ ```
134
+
@@ -1,11 +1,11 @@
1
1
  class @GalleryUploader
2
- constructor: (@container) ->
2
+ constructor: (@container) ->
3
3
  @previews = {}
4
4
 
5
5
  @container.find('input[type="file"]:first').show().fileupload
6
6
  type: 'POST'
7
7
  dataType: 'xml'
8
- replaceFileInput: false
8
+ replaceFileInput: false
9
9
  autoUpload: true
10
10
  formData: @getFormData
11
11
  dropZone: @container
@@ -18,7 +18,7 @@ class @GalleryUploader
18
18
  add: (e, data) =>
19
19
  if @loader
20
20
  @loader.detach()
21
-
21
+
22
22
  if @verifyProcessingInterval
23
23
  clearInterval(@verifyProcessingInterval)
24
24
 
@@ -59,6 +59,6 @@ class @GalleryUploader
59
59
 
60
60
  nextPreview: =>
61
61
  @currentIndex ||= 0
62
- key = Object.keys(@previews)[@currentIndex]
62
+ key = Object.keys(@previews)[@currentIndex]
63
63
  @currentIndex++
64
64
  @previews[key]
@@ -30,12 +30,32 @@ class @ImageUploader
30
30
  clearInterval(@verifyProcessingInterval)
31
31
 
32
32
  if @file.type.match /gif|jpe?g|png/
33
- @loader = $('<div class="progress progress-striped active"><div class="bar" style="width: 0%;"></div></div>').hide()
34
- @preview.prepend(@loader.fadeIn())
33
+ loadImage @file, @appendThumb, {
34
+ maxWidth: @thumbContainer.data('width'),
35
+ maxHeight: @thumbContainer.data('height'),
36
+ minWidth: @thumbContainer.data('width'),
37
+ minHeight: @thumbContainer.data('height'),
38
+ canvas: true,
39
+ crop: true,
40
+ orientation: true
41
+ }
42
+
43
+ @loader = $('<div><div class="progress progress-striped active"><div class="bar" style="width: 0%;"></div></div><div class="uploader-overlay"></div></div>').hide()
44
+ @loader.find('.uploader-overlay').height(@thumbContainer.data('height'))
45
+ @preview.prepend(@loader)
46
+ @loader.show()
47
+
35
48
  data.submit()
36
49
  @container.find('.fileupload').removeClass('processing').addClass('uploading')
37
50
  @container.closest('form').find('[type=submit]').attr("disabled", true)
38
51
 
52
+ appendThumb: (img) =>
53
+ @thumbContainer.html('')
54
+ $(img).hide()
55
+ @container.find('.fileupload-preview.preview').append($(img).show())
56
+ @container.find('.fileupload').removeClass('fileupload-new').addClass('fileupload-uploading')
57
+ @loader.show()
58
+
39
59
  getFormData: (arg) =>
40
60
  file = @file
41
61
  @filePath = @container.find('input[name="key"]').val() + file.name
@@ -55,6 +75,7 @@ class @ImageUploader
55
75
 
56
76
  done: (e, data) =>
57
77
  @container.find('.fileupload').removeClass('uploading').addClass('processing')
78
+
58
79
  $.ajax
59
80
  type: 'POST'
60
81
  url: @fileInput.data('callback-url')
@@ -65,7 +86,7 @@ class @ImageUploader
65
86
  'image[secure_random]': @fileInput.data('secure-random')
66
87
 
67
88
  complete: =>
68
- @verifyProcessingInterval = setInterval(@verifyProcessing, 5000)
89
+ @verifyProcessingInterval = setInterval(@verifyProcessing, 500)
69
90
 
70
91
  error: =>
71
92
  @loader.detach()
@@ -80,10 +101,10 @@ class @ImageUploader
80
101
  dataType: 'json'
81
102
  url: @fileInput.data('find-url')
82
103
  data:
83
- 'name': filename
84
- 'imageable_type': @typeInput.val()
85
- 'upload_name': @uploadNameInput.val()
86
- 'secure_random': @fileInput.data('secure-random')
104
+ image:
105
+ 'imageable_type': @typeInput.val()
106
+ 'upload_name': @uploadNameInput.val()
107
+ 'secure_random': @fileInput.data('secure-random')
87
108
 
88
109
  complete: (data) =>
89
110
  if data.responseJSON.hasOwnProperty('id')
@@ -107,16 +128,11 @@ class @ImageUploader
107
128
  @container.closest('form').find('[type=submit]').attr("disabled", false)
108
129
 
109
130
  showThumb: (image) =>
110
- console.log 'showThumb'
111
- @loader.detach()
131
+ @loader.fadeOut =>
132
+ @loader.detach()
112
133
  @idInput.val(image.id)
113
134
  @container.find('a.btn.fileupload-exists').attr('href', image.url)
114
135
  @thumbContainer.find('img').detach()
115
- img = $('<img/>')
116
- img.attr('src', image.versions[@thumbContainer.data('version')])
117
- img.attr('width', @thumbContainer.data('width'))
118
- img.attr('height', @thumbContainer.data('height')).hide()
119
- @container.find('.fileupload-preview.preview').append(img.fadeIn())
120
136
  @container.find('.fileupload').removeClass('fileupload-new').addClass('fileupload-exists')
121
137
  @container.find('.fileupload').removeClass('uploading').removeClass('processing')
122
138
  @container.closest('form').find('[type=submit]').attr("disabled", false)
@@ -0,0 +1,15 @@
1
+ class @ShowImage
2
+ constructor: (@container) ->
3
+ if @container.data('processing') == true
4
+ loadImage @container.data('original'), @append, {
5
+ maxWidth: @container.find('img').attr('width'),
6
+ maxHeight: @container.find('img').attr('height'),
7
+ minWidth: @container.find('img').attr('width'),
8
+ minHeight: @container.find('img').attr('height'),
9
+ canvas: true,
10
+ crop: true,
11
+ orientation: true
12
+ }
13
+ append: (img) =>
14
+ @container.append(img)
15
+
@@ -1,15 +1,16 @@
1
1
  class @UploaderPreview
2
2
  constructor: (@container, @file) ->
3
- @loader = $('<div class="progress progress-striped active"><div class="bar" style="width: 0%;"></div></div>').hide()
3
+ @thumbContainer = @container.find('.fileupload-preview.thumbnail')
4
+ @loader = $('<div><div class="progress progress-striped active"><div class="bar" style="width: 0%;"></div></div><div class="uploader-overlay"></div></div>').hide()
4
5
 
5
6
  @startLoader() if @isUploadStarting()
6
-
7
+
7
8
  @container.find('a.btn.fileupload-exists').bind('ajax:success', @delete)
8
9
 
9
10
  @container.find('input[type="file"]:first').show().fileupload
10
11
  type: 'POST'
11
12
  dataType: 'xml'
12
- replaceFileInput: false
13
+ replaceFileInput: false
13
14
  autoUpload: true
14
15
  formData: @getFormData
15
16
  dropZone: @container
@@ -26,28 +27,44 @@ class @UploaderPreview
26
27
  @thumbContainer = @container.find('.fileupload-preview.thumbnail')
27
28
 
28
29
  startLoader: =>
29
- @container.prepend(@loader.fadeIn())
30
+ loadImage @file, @appendThumb, {
31
+ maxWidth: @thumbContainer.data('width'),
32
+ maxHeight: @thumbContainer.data('height'),
33
+ minWidth: @thumbContainer.data('width'),
34
+ minHeight: @thumbContainer.data('height'),
35
+ canvas: true,
36
+ crop: true,
37
+ orientation: true
38
+ }
39
+ @loader.find('.uploader-overlay').height(@thumbContainer.data('height'))
40
+ @container.prepend(@loader.show())
30
41
  @container.find('.fileupload').removeClass('processing').addClass('uploading')
31
42
 
32
-
33
43
  add: (e, data) =>
34
44
  @file = data.files[0]
35
45
 
36
46
  if @loader
37
47
  @loader.detach()
38
-
48
+
39
49
  if @verifyProcessingInterval
40
50
  clearInterval(@verifyProcessingInterval)
41
51
 
42
52
  if @file.type.match /gif|jpe?g|png/
53
+
43
54
  data.context = @id()
44
55
  @startLoader()
45
56
  @container.closest('form').find('[type=submit]').attr("disabled", true)
46
57
  data.submit()
47
58
 
59
+ appendThumb: (img) =>
60
+ @thumbContainer.html('')
61
+ @thumbContainer.append(img)
62
+ @container.find('.fileupload').removeClass('fileupload-new').addClass('fileupload-uploading')
63
+ @loader.show()
64
+
48
65
  getFormData: =>
49
66
  @filePath = "uploads/#{@id()}/" + @file.name
50
-
67
+
51
68
  [
52
69
  { name: 'key', value: @filePath },
53
70
  { name: 'acl', value: @container.find('input[name="acl"]').val() },
@@ -58,7 +75,7 @@ class @UploaderPreview
58
75
  { name: 'file', value: @file }
59
76
  ]
60
77
 
61
-
78
+
62
79
  isUploadStarting: =>
63
80
  @container.find('.fileupload').hasClass('fileupload-new')
64
81
 
@@ -71,18 +88,20 @@ class @UploaderPreview
71
88
 
72
89
  done: (data) =>
73
90
  @container.find('.fileupload').removeClass('uploading').addClass('processing')
91
+ @container.closest('form').find('[type=submit]').attr("disabled", false)
92
+
74
93
  $.ajax
75
94
  type: 'POST'
76
95
  url: @fileInput.data('callback-url')
77
- data:
96
+ data:
78
97
  'image[remote_file_url]': @fileInput.data('url') + @filePath
79
98
  'image[imageable_type]': @typeInput.val()
80
99
  'image[upload_name]': @uploadNameInput.val()
81
100
  'image[secure_random]': @id()
82
-
101
+
83
102
  complete: =>
84
- @verifyProcessingInterval = setInterval(@verifyProcessing, 5000)
85
-
103
+ @verifyProcessingInterval = setInterval(@verifyProcessing, 500)
104
+
86
105
  error: =>
87
106
  @loader.detach()
88
107
  @container.find('.fileupload').removeClass('uploading').removeClass('processing')
@@ -96,33 +115,28 @@ class @UploaderPreview
96
115
  dataType: 'json'
97
116
  url: @fileInput.data('find-url')
98
117
  data:
99
- 'name': filename
100
- 'imageable_type': @typeInput.val()
101
- 'upload_name': @uploadNameInput.val()
102
- 'secure_random': @id()
118
+ image:
119
+ imageable_type: @typeInput.val()
120
+ upload_name: @uploadNameInput.val()
121
+ secure_random: @id()
103
122
 
104
123
  complete: (data) =>
105
124
  if data.responseJSON.hasOwnProperty('id')
106
125
  clearInterval(@verifyProcessingInterval)
107
126
  @showThumb(data.responseJSON)
108
-
127
+
109
128
  error: =>
110
129
  @loader.detach()
111
130
  @container.detach()
112
131
 
113
132
  showThumb: (image) =>
114
- @loader.detach()
133
+ console.log 'showThumb'
134
+ @loader.fadeOut =>
135
+ @loader.detach()
115
136
  @idInput.val(image.id)
116
137
  @container.find('a.btn.fileupload-exists').attr('href', image.url)
117
- @thumbContainer.find('img').detach()
118
- img = $('<img/>')
119
- img.attr('src', image.versions[@thumbContainer.data('version')])
120
- img.attr('width', @thumbContainer.data('width'))
121
- img.attr('height', @thumbContainer.data('height')).hide()
122
- @container.find('.fileupload-preview.thumbnail').append(img.fadeIn())
123
- @container.find('.fileupload').removeClass('fileupload-new').addClass('fileupload-exists')
138
+ @container.find('.fileupload').removeClass('fileupload-new').removeClass('fileupload-uploading').addClass('fileupload-exists')
124
139
  @container.find('.fileupload').removeClass('uploading').removeClass('processing')
125
- @container.closest('form').find('[type=submit]').attr("disabled", false)
126
140
 
127
141
  fail: =>
128
142
  @loader.detach()
@@ -0,0 +1 @@
1
+ !function(a){"use strict";var b=a.HTMLCanvasElement&&a.HTMLCanvasElement.prototype,c=a.Blob&&function(){try{return Boolean(new Blob)}catch(a){return!1}}(),d=c&&a.Uint8Array&&function(){try{return 100===new Blob([new Uint8Array(100)]).size}catch(a){return!1}}(),e=a.BlobBuilder||a.WebKitBlobBuilder||a.MozBlobBuilder||a.MSBlobBuilder,f=(c||e)&&a.atob&&a.ArrayBuffer&&a.Uint8Array&&function(a){var b,f,g,h,i,j;for(b=a.split(",")[0].indexOf("base64")>=0?atob(a.split(",")[1]):decodeURIComponent(a.split(",")[1]),f=new ArrayBuffer(b.length),g=new Uint8Array(f),h=0;h<b.length;h+=1)g[h]=b.charCodeAt(h);return i=a.split(",")[0].split(":")[1].split(";")[0],c?new Blob([d?g:f],{type:i}):(j=new e,j.append(f),j.getBlob(i))};a.HTMLCanvasElement&&!b.toBlob&&(b.mozGetAsFile?b.toBlob=function(a,c,d){d&&b.toDataURL&&f?a(f(this.toDataURL(c,d))):a(this.mozGetAsFile("blob",c))}:b.toDataURL&&f&&(b.toBlob=function(a,b,c){a(f(this.toDataURL(b,c)))})),"function"==typeof define&&define.amd?define(function(){return f}):a.dataURLtoBlob=f}(this);
@@ -1,5 +1,5 @@
1
1
  /*
2
- * jQuery File Upload Plugin 5.32.3
2
+ * jQuery File Upload Plugin 5.40.1
3
3
  * https://github.com/blueimp/jQuery-File-Upload
4
4
  *
5
5
  * Copyright 2010, Sebastian Tschan
@@ -9,8 +9,8 @@
9
9
  * http://www.opensource.org/licenses/MIT
10
10
  */
11
11
 
12
- /*jslint nomen: true, unparam: true, regexp: true */
13
- /*global define, window, document, location, File, Blob, FormData */
12
+ /* jshint nomen:false */
13
+ /* global define, window, document, location, Blob, FormData */
14
14
 
15
15
  (function (factory) {
16
16
  'use strict';
@@ -40,9 +40,11 @@
40
40
  $('<input type="file">').prop('disabled'));
41
41
 
42
42
  // The FileReader API is not actually used, but works as feature detection,
43
- // as e.g. Safari supports XHR file uploads via the FormData API,
44
- // but not non-multipart XHR file uploads:
45
- $.support.xhrFileUpload = !!(window.XMLHttpRequestUpload && window.FileReader);
43
+ // as some Safari versions (5?) support XHR file uploads via the FormData API,
44
+ // but not non-multipart XHR file uploads.
45
+ // window.XMLHttpRequestUpload is not available on IE10, so we check for
46
+ // window.ProgressEvent instead to detect XHR2 file upload capability:
47
+ $.support.xhrFileUpload = !!(window.ProgressEvent && window.FileReader);
46
48
  $.support.xhrFormDataFileUpload = !!window.FormData;
47
49
 
48
50
  // Detect support for Blob slicing (required for chunked uploads):
@@ -88,6 +90,14 @@
88
90
  // To limit the number of files uploaded with one XHR request,
89
91
  // set the following option to an integer greater than 0:
90
92
  limitMultiFileUploads: undefined,
93
+ // The following option limits the number of files uploaded with one
94
+ // XHR request to keep the request size under or equal to the defined
95
+ // limit in bytes:
96
+ limitMultiFileUploadSize: undefined,
97
+ // Multipart file uploads add a number of bytes to each uploaded file,
98
+ // therefore the following option adds an overhead for each file used
99
+ // in the limitMultiFileUploadSize configuration:
100
+ limitMultiFileUploadSizeOverhead: 512,
91
101
  // Set the following option to true to issue all file upload requests
92
102
  // in a sequential order:
93
103
  sequentialUploads: false,
@@ -174,6 +184,9 @@
174
184
  // handlers using jQuery's Deferred callbacks:
175
185
  // data.submit().done(func).fail(func).always(func);
176
186
  add: function (e, data) {
187
+ if (e.isDefaultPrevented()) {
188
+ return false;
189
+ }
177
190
  if (data.autoUpload || (data.autoUpload !== false &&
178
191
  $(this).fileupload('option', 'autoUpload'))) {
179
192
  data.process().done(function () {
@@ -280,7 +293,7 @@
280
293
 
281
294
  _getFormData: function (options) {
282
295
  var formData;
283
- if (typeof options.formData === 'function') {
296
+ if ($.type(options.formData) === 'function') {
284
297
  return options.formData(options.form);
285
298
  }
286
299
  if ($.isArray(options.formData)) {
@@ -360,10 +373,18 @@
360
373
  // Trigger a custom progress event with a total data property set
361
374
  // to the file size(s) of the current upload and a loaded data
362
375
  // property calculated accordingly:
363
- this._trigger('progress', e, data);
376
+ this._trigger(
377
+ 'progress',
378
+ $.Event('progress', {delegatedEvent: e}),
379
+ data
380
+ );
364
381
  // Trigger a global progress event for all current file uploads,
365
382
  // including ajax calls queued for sequential file uploads:
366
- this._trigger('progressall', e, this._progress);
383
+ this._trigger(
384
+ 'progressall',
385
+ $.Event('progressall', {delegatedEvent: e}),
386
+ this._progress
387
+ );
367
388
  }
368
389
  },
369
390
 
@@ -398,7 +419,8 @@
398
419
  file = options.files[0],
399
420
  // Ignore non-multipart setting if not supported:
400
421
  multipart = options.multipart || !$.support.xhrFileUpload,
401
- paramName = options.paramName[0];
422
+ paramName = $.type(options.paramName) === 'array' ?
423
+ options.paramName[0] : options.paramName;
402
424
  options.headers = $.extend({}, options.headers);
403
425
  if (options.contentRange) {
404
426
  options.headers['Content-Range'] = options.contentRange;
@@ -408,7 +430,7 @@
408
430
  encodeURI(file.name) + '"';
409
431
  }
410
432
  if (!multipart) {
411
- options.contentType = file.type;
433
+ options.contentType = file.type || 'application/octet-stream';
412
434
  options.data = options.blob || file;
413
435
  } else if ($.support.xhrFormDataFileUpload) {
414
436
  if (options.postMessage) {
@@ -425,7 +447,8 @@
425
447
  } else {
426
448
  $.each(options.files, function (index, file) {
427
449
  formData.push({
428
- name: options.paramName[index] || paramName,
450
+ name: ($.type(options.paramName) === 'array' &&
451
+ options.paramName[index]) || paramName,
429
452
  value: file
430
453
  });
431
454
  });
@@ -448,9 +471,10 @@
448
471
  if (that._isInstanceOf('File', file) ||
449
472
  that._isInstanceOf('Blob', file)) {
450
473
  formData.append(
451
- options.paramName[index] || paramName,
474
+ ($.type(options.paramName) === 'array' &&
475
+ options.paramName[index]) || paramName,
452
476
  file,
453
- file.name
477
+ file.uploadName || file.name
454
478
  );
455
479
  }
456
480
  });
@@ -534,8 +558,10 @@
534
558
  options.url = options.form.prop('action') || location.href;
535
559
  }
536
560
  // The HTTP request method must be "POST" or "PUT":
537
- options.type = (options.type || options.form.prop('method') || '')
538
- .toUpperCase();
561
+ options.type = (options.type ||
562
+ ($.type(options.form.prop('method')) === 'string' &&
563
+ options.form.prop('method')) || ''
564
+ ).toUpperCase();
539
565
  if (options.type !== 'POST' && options.type !== 'PUT' &&
540
566
  options.type !== 'PATCH') {
541
567
  options.type = 'POST';
@@ -594,22 +620,32 @@
594
620
  // Adds convenience methods to the data callback argument:
595
621
  _addConvenienceMethods: function (e, data) {
596
622
  var that = this,
597
- getPromise = function (data) {
598
- return $.Deferred().resolveWith(that, [data]).promise();
623
+ getPromise = function (args) {
624
+ return $.Deferred().resolveWith(that, args).promise();
599
625
  };
600
626
  data.process = function (resolveFunc, rejectFunc) {
601
627
  if (resolveFunc || rejectFunc) {
602
628
  data._processQueue = this._processQueue =
603
- (this._processQueue || getPromise(this))
604
- .pipe(resolveFunc, rejectFunc);
629
+ (this._processQueue || getPromise([this])).pipe(
630
+ function () {
631
+ if (data.errorThrown) {
632
+ return $.Deferred()
633
+ .rejectWith(that, [data]).promise();
634
+ }
635
+ return getPromise(arguments);
636
+ }
637
+ ).pipe(resolveFunc, rejectFunc);
605
638
  }
606
- return this._processQueue || getPromise(this);
639
+ return this._processQueue || getPromise([this]);
607
640
  };
608
641
  data.submit = function () {
609
642
  if (this.state() !== 'pending') {
610
643
  data.jqXHR = this.jqXHR =
611
- (that._trigger('submit', e, this) !== false) &&
612
- that._onSend(e, this);
644
+ (that._trigger(
645
+ 'submit',
646
+ $.Event('submit', {delegatedEvent: e}),
647
+ this
648
+ ) !== false) && that._onSend(e, this);
613
649
  }
614
650
  return this.jqXHR || that._getXHRPromise();
615
651
  };
@@ -617,7 +653,9 @@
617
653
  if (this.jqXHR) {
618
654
  return this.jqXHR.abort();
619
655
  }
620
- return that._getXHRPromise();
656
+ this.errorThrown = 'abort';
657
+ that._trigger('fail', null, this);
658
+ return that._getXHRPromise(false);
621
659
  };
622
660
  data.state = function () {
623
661
  if (this.jqXHR) {
@@ -627,6 +665,10 @@
627
665
  return that._getDeferredState(this._processQueue);
628
666
  }
629
667
  };
668
+ data.processing = function () {
669
+ return !this.jqXHR && this._processQueue && that
670
+ ._getDeferredState(this._processQueue) === 'pending';
671
+ };
630
672
  data.progress = function () {
631
673
  return this._progress;
632
674
  };
@@ -829,7 +871,11 @@
829
871
  // Set timer for bitrate progress calculation:
830
872
  options._bitrateTimer = new that._BitrateTimer();
831
873
  jqXHR = jqXHR || (
832
- ((aborted || that._trigger('send', e, options) === false) &&
874
+ ((aborted || that._trigger(
875
+ 'send',
876
+ $.Event('send', {delegatedEvent: e}),
877
+ options
878
+ ) === false) &&
833
879
  that._getXHRPromise(false, options.context, aborted)) ||
834
880
  that._chunkedUpload(options) || $.ajax(options)
835
881
  ).done(function (result, textStatus, jqXHR) {
@@ -900,39 +946,70 @@
900
946
  var that = this,
901
947
  result = true,
902
948
  options = $.extend({}, this.options, data),
949
+ files = data.files,
950
+ filesLength = files.length,
903
951
  limit = options.limitMultiFileUploads,
952
+ limitSize = options.limitMultiFileUploadSize,
953
+ overhead = options.limitMultiFileUploadSizeOverhead,
954
+ batchSize = 0,
904
955
  paramName = this._getParamName(options),
905
956
  paramNameSet,
906
957
  paramNameSlice,
907
958
  fileSet,
908
- i;
909
- if (!(options.singleFileUploads || limit) ||
959
+ i,
960
+ j = 0;
961
+ if (limitSize && (!filesLength || files[0].size === undefined)) {
962
+ limitSize = undefined;
963
+ }
964
+ if (!(options.singleFileUploads || limit || limitSize) ||
910
965
  !this._isXHRUpload(options)) {
911
- fileSet = [data.files];
966
+ fileSet = [files];
912
967
  paramNameSet = [paramName];
913
- } else if (!options.singleFileUploads && limit) {
968
+ } else if (!(options.singleFileUploads || limitSize) && limit) {
914
969
  fileSet = [];
915
970
  paramNameSet = [];
916
- for (i = 0; i < data.files.length; i += limit) {
917
- fileSet.push(data.files.slice(i, i + limit));
971
+ for (i = 0; i < filesLength; i += limit) {
972
+ fileSet.push(files.slice(i, i + limit));
918
973
  paramNameSlice = paramName.slice(i, i + limit);
919
974
  if (!paramNameSlice.length) {
920
975
  paramNameSlice = paramName;
921
976
  }
922
977
  paramNameSet.push(paramNameSlice);
923
978
  }
979
+ } else if (!options.singleFileUploads && limitSize) {
980
+ fileSet = [];
981
+ paramNameSet = [];
982
+ for (i = 0; i < filesLength; i = i + 1) {
983
+ batchSize += files[i].size + overhead;
984
+ if (i + 1 === filesLength ||
985
+ ((batchSize + files[i + 1].size + overhead) > limitSize) ||
986
+ (limit && i + 1 - j >= limit)) {
987
+ fileSet.push(files.slice(j, i + 1));
988
+ paramNameSlice = paramName.slice(j, i + 1);
989
+ if (!paramNameSlice.length) {
990
+ paramNameSlice = paramName;
991
+ }
992
+ paramNameSet.push(paramNameSlice);
993
+ j = i + 1;
994
+ batchSize = 0;
995
+ }
996
+ }
924
997
  } else {
925
998
  paramNameSet = paramName;
926
999
  }
927
- data.originalFiles = data.files;
928
- $.each(fileSet || data.files, function (index, element) {
1000
+ data.originalFiles = files;
1001
+ $.each(fileSet || files, function (index, element) {
929
1002
  var newData = $.extend({}, data);
930
1003
  newData.files = fileSet ? element : [element];
931
1004
  newData.paramName = paramNameSet[index];
932
1005
  that._initResponseObject(newData);
933
1006
  that._initProgressObject(newData);
934
1007
  that._addConvenienceMethods(e, newData);
935
- result = that._trigger('add', e, newData);
1008
+ result = that._trigger(
1009
+ 'add',
1010
+ $.Event('add', {delegatedEvent: e}),
1011
+ newData
1012
+ );
936
1013
  return result;
937
1014
  });
938
1015
  return result;
@@ -1101,7 +1178,11 @@
1101
1178
  if (that.options.replaceFileInput) {
1102
1179
  that._replaceFileInput(data.fileInput);
1103
1180
  }
1104
- if (that._trigger('change', e, data) !== false) {
1181
+ if (that._trigger(
1182
+ 'change',
1183
+ $.Event('change', {delegatedEvent: e}),
1184
+ data
1185
+ ) !== false) {
1105
1186
  that._onAdd(e, data);
1106
1187
  }
1107
1188
  });
@@ -1118,9 +1199,12 @@
1118
1199
  data.files.push(file);
1119
1200
  }
1120
1201
  });
1121
- if (this._trigger('paste', e, data) === false ||
1122
- this._onAdd(e, data) === false) {
1123
- return false;
1202
+ if (this._trigger(
1203
+ 'paste',
1204
+ $.Event('paste', {delegatedEvent: e}),
1205
+ data
1206
+ ) !== false) {
1207
+ this._onAdd(e, data);
1124
1208
  }
1125
1209
  }
1126
1210
  },
@@ -1134,7 +1218,11 @@
1134
1218
  e.preventDefault();
1135
1219
  this._getDroppedFiles(dataTransfer).always(function (files) {
1136
1220
  data.files = files;
1137
- if (that._trigger('drop', e, data) !== false) {
1221
+ if (that._trigger(
1222
+ 'drop',
1223
+ $.Event('drop', {delegatedEvent: e}),
1224
+ data
1225
+ ) !== false) {
1138
1226
  that._onAdd(e, data);
1139
1227
  }
1140
1228
  });
@@ -1144,14 +1232,13 @@
1144
1232
  _onDragOver: function (e) {
1145
1233
  e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
1146
1234
  var dataTransfer = e.dataTransfer;
1147
- if (dataTransfer) {
1148
- if (this._trigger('dragover', e) === false) {
1149
- return false;
1150
- }
1151
- if ($.inArray('Files', dataTransfer.types) !== -1) {
1152
- dataTransfer.dropEffect = 'copy';
1153
- e.preventDefault();
1154
- }
1235
+ if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1 &&
1236
+ this._trigger(
1237
+ 'dragover',
1238
+ $.Event('dragover', {delegatedEvent: e})
1239
+ ) !== false) {
1240
+ e.preventDefault();
1241
+ dataTransfer.dropEffect = 'copy';
1155
1242
  }
1156
1243
  },
1157
1244
 
@@ -1220,15 +1307,21 @@
1220
1307
 
1221
1308
  _initDataAttributes: function () {
1222
1309
  var that = this,
1223
- options = this.options;
1310
+ options = this.options,
1311
+ clone = $(this.element[0].cloneNode(false));
1224
1312
  // Initialize options set via HTML5 data-attributes:
1225
1313
  $.each(
1226
- $(this.element[0].cloneNode(false)).data(),
1314
+ clone.data(),
1227
1315
  function (key, value) {
1228
- if (that._isRegExpOption(key, value)) {
1229
- value = that._getRegExp(value);
1316
+ var dataAttributeName = 'data-' +
1317
+ // Convert camelCase to hyphen-ated key:
1318
+ key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
1319
+ if (clone.attr(dataAttributeName)) {
1320
+ if (that._isRegExpOption(key, value)) {
1321
+ value = that._getRegExp(value);
1322
+ }
1323
+ options[key] = value;
1230
1324
  }
1231
- options[key] = value;
1232
1325
  }
1233
1326
  );
1234
1327
  },
@@ -1,5 +1,5 @@
1
1
  /*
2
- * jQuery Iframe Transport Plugin 1.7
2
+ * jQuery Iframe Transport Plugin 1.8.2
3
3
  * https://github.com/blueimp/jQuery-File-Upload
4
4
  *
5
5
  * Copyright 2011, Sebastian Tschan
@@ -9,8 +9,7 @@
9
9
  * http://www.opensource.org/licenses/MIT
10
10
  */
11
11
 
12
- /*jslint unparam: true, nomen: true */
13
- /*global define, window, document */
12
+ /* global define, window, document */
14
13
 
15
14
  (function (factory) {
16
15
  'use strict';
@@ -27,7 +26,7 @@
27
26
  // Helper variable to create unique names for the transport iframes:
28
27
  var counter = 0;
29
28
 
30
- // The iframe transport accepts three additional options:
29
+ // The iframe transport accepts four additional options:
31
30
  // options.fileInput: a jQuery collection of file input fields
32
31
  // options.paramName: the parameter name for the file form data,
33
32
  // overrides the name property of the file input field(s),
@@ -35,9 +34,16 @@
35
34
  // options.formData: an array of objects with name and value properties,
36
35
  // equivalent to the return data of .serializeArray(), e.g.:
37
36
  // [{name: 'a', value: 1}, {name: 'b', value: 2}]
37
+ // options.initialIframeSrc: the URL of the initial iframe src,
38
+ // by default set to "javascript:false;"
38
39
  $.ajaxTransport('iframe', function (options) {
39
40
  if (options.async) {
40
- var form,
41
+ // javascript:false as initial iframe src
42
+ // prevents warning popups on HTTPS in IE6:
43
+ /*jshint scripturl: true */
44
+ var initialIframeSrc = options.initialIframeSrc || 'javascript:false;',
45
+ /*jshint scripturl: false */
46
+ form,
41
47
  iframe,
42
48
  addParamChar;
43
49
  return {
@@ -56,15 +62,13 @@
56
62
  options.url = options.url + addParamChar + '_method=PATCH';
57
63
  options.type = 'POST';
58
64
  }
59
- // javascript:false as initial iframe src
60
- // prevents warning popups on HTTPS in IE6.
61
65
  // IE versions below IE8 cannot set the name property of
62
66
  // elements that have already been added to the DOM,
63
67
  // so we set the name along with the iframe HTML markup:
64
68
  counter += 1;
65
69
  iframe = $(
66
- '<iframe src="javascript:false;" name="iframe-transport-' +
67
- counter + '"></iframe>'
70
+ '<iframe src="' + initialIframeSrc +
71
+ '" name="iframe-transport-' + counter + '"></iframe>'
68
72
  ).bind('load', function () {
69
73
  var fileInputClones,
70
74
  paramNames = $.isArray(options.paramName) ?
@@ -95,7 +99,7 @@
95
99
  );
96
100
  // Fix for IE endless progress bar activity bug
97
101
  // (happens on form submits to iframe targets):
98
- $('<iframe src="javascript:false;"></iframe>')
102
+ $('<iframe src="' + initialIframeSrc + '"></iframe>')
99
103
  .appendTo(form);
100
104
  window.setTimeout(function () {
101
105
  // Removing the form in a setTimeout call
@@ -138,6 +142,8 @@
138
142
  .prop('enctype', 'multipart/form-data')
139
143
  // enctype must be set as encoding for IE:
140
144
  .prop('encoding', 'multipart/form-data');
145
+ // Remove the HTML5 form attribute from the input(s):
146
+ options.fileInput.removeAttr('form');
141
147
  }
142
148
  form.submit();
143
149
  // Insert the file input fields at their original location
@@ -145,7 +151,10 @@
145
151
  if (fileInputClones && fileInputClones.length) {
146
152
  options.fileInput.each(function (index, input) {
147
153
  var clone = $(fileInputClones[index]);
148
- $(input).prop('name', clone.prop('name'));
154
+ // Restore the original name and form properties:
155
+ $(input)
156
+ .prop('name', clone.prop('name'))
157
+ .attr('form', clone.attr('form'));
149
158
  clone.replaceWith(input);
150
159
  });
151
160
  }
@@ -159,7 +168,7 @@
159
168
  // concat is used to avoid the "Script URL" JSLint error:
160
169
  iframe
161
170
  .unbind('load')
162
- .prop('src', 'javascript'.concat(':false;'));
171
+ .prop('src', initialIframeSrc);
163
172
  }
164
173
  if (form) {
165
174
  form.remove();
@@ -0,0 +1 @@
1
+ !function(a){"use strict";var b=function(a,c,d){var e,f,g=document.createElement("img");if(g.onerror=c,g.onload=function(){!f||d&&d.noRevoke||b.revokeObjectURL(f),c&&c(b.scale(g,d))},b.isInstanceOf("Blob",a)||b.isInstanceOf("File",a))e=f=b.createObjectURL(a),g._type=a.type;else{if("string"!=typeof a)return!1;e=a,d&&d.crossOrigin&&(g.crossOrigin=d.crossOrigin)}return e?(g.src=e,g):b.readFile(a,function(a){var b=a.target;b&&b.result?g.src=b.result:c&&c(a)})},c=window.createObjectURL&&window||window.URL&&URL.revokeObjectURL&&URL||window.webkitURL&&webkitURL;b.isInstanceOf=function(a,b){return Object.prototype.toString.call(b)==="[object "+a+"]"},b.transformCoordinates=function(){},b.getTransformedOptions=function(a){return a},b.renderImageToCanvas=function(a,b,c,d,e,f,g,h,i,j){return a.getContext("2d").drawImage(b,c,d,e,f,g,h,i,j),a},b.hasCanvasOption=function(a){return a.canvas||a.crop},b.scale=function(a,c){c=c||{};var d,e,f,g,h,i,j,k,l,m=document.createElement("canvas"),n=a.getContext||b.hasCanvasOption(c)&&m.getContext,o=a.naturalWidth||a.width,p=a.naturalHeight||a.height,q=o,r=p,s=function(){var a=Math.max((f||q)/q,(g||r)/r);a>1&&(q=Math.ceil(q*a),r=Math.ceil(r*a))},t=function(){var a=Math.min((d||q)/q,(e||r)/r);1>a&&(q=Math.ceil(q*a),r=Math.ceil(r*a))};return n&&(c=b.getTransformedOptions(c),j=c.left||0,k=c.top||0,c.sourceWidth?(h=c.sourceWidth,void 0!==c.right&&void 0===c.left&&(j=o-h-c.right)):h=o-j-(c.right||0),c.sourceHeight?(i=c.sourceHeight,void 0!==c.bottom&&void 0===c.top&&(k=p-i-c.bottom)):i=p-k-(c.bottom||0),q=h,r=i),d=c.maxWidth,e=c.maxHeight,f=c.minWidth,g=c.minHeight,n&&d&&e&&c.crop?(q=d,r=e,l=h/i-d/e,0>l?(i=e*h/d,void 0===c.top&&void 0===c.bottom&&(k=(p-i)/2)):l>0&&(h=d*i/e,void 0===c.left&&void 0===c.right&&(j=(o-h)/2))):((c.contain||c.cover)&&(f=d=d||f,g=e=e||g),c.cover?(t(),s()):(s(),t())),n?(m.width=q,m.height=r,b.transformCoordinates(m,c),b.renderImageToCanvas(m,a,j,k,h,i,0,0,q,r)):(a.width=q,a.height=r,a)},b.createObjectURL=function(a){return c?c.createObjectURL(a):!1},b.revokeObjectURL=function(a){return c?c.revokeObjectURL(a):!1},b.readFile=function(a,b,c){if(window.FileReader){var d=new FileReader;if(d.onload=d.onerror=b,c=c||"readAsDataURL",d[c])return d[c](a),d}return!1},"function"==typeof define&&define.amd?define(function(){return b}):a.loadImage=b}(this),function(a){"use strict";"function"==typeof define&&define.amd?define(["load-image"],a):a(window.loadImage)}(function(a){"use strict";if(window.navigator&&window.navigator.platform&&/iP(hone|od|ad)/.test(window.navigator.platform)){var b=a.renderImageToCanvas;a.detectSubsampling=function(a){var b,c;return a.width*a.height>1048576?(b=document.createElement("canvas"),b.width=b.height=1,c=b.getContext("2d"),c.drawImage(a,-a.width+1,0),0===c.getImageData(0,0,1,1).data[3]):!1},a.detectVerticalSquash=function(a,b){var c,d,e,f,g,h=a.naturalHeight||a.height,i=document.createElement("canvas"),j=i.getContext("2d");for(b&&(h/=2),i.width=1,i.height=h,j.drawImage(a,0,0),c=j.getImageData(0,0,1,h).data,d=0,e=h,f=h;f>d;)g=c[4*(f-1)+3],0===g?e=f:d=f,f=e+d>>1;return f/h||1},a.renderImageToCanvas=function(c,d,e,f,g,h,i,j,k,l){if("image/jpeg"===d._type){var m,n,o,p,q=c.getContext("2d"),r=document.createElement("canvas"),s=1024,t=r.getContext("2d");if(r.width=s,r.height=s,q.save(),m=a.detectSubsampling(d),m&&(e/=2,f/=2,g/=2,h/=2),n=a.detectVerticalSquash(d,m),m||1!==n){for(f*=n,k=Math.ceil(s*k/g),l=Math.ceil(s*l/h/n),j=0,p=0;h>p;){for(i=0,o=0;g>o;)t.clearRect(0,0,s,s),t.drawImage(d,e,f,g,h,-o,-p,g,h),q.drawImage(r,0,0,s,s,i,j,k,l),o+=s,i+=k;p+=s,j+=l}return q.restore(),c}}return b(c,d,e,f,g,h,i,j,k,l)}}}),function(a){"use strict";"function"==typeof define&&define.amd?define(["load-image"],a):a(window.loadImage)}(function(a){"use strict";var b=a.hasCanvasOption;a.hasCanvasOption=function(a){return b(a)||a.orientation},a.transformCoordinates=function(a,b){var c=a.getContext("2d"),d=a.width,e=a.height,f=b.orientation;if(f)switch(f>4&&(a.width=e,a.height=d),f){case 2:c.translate(d,0),c.scale(-1,1);break;case 3:c.translate(d,e),c.rotate(Math.PI);break;case 4:c.translate(0,e),c.scale(1,-1);break;case 5:c.rotate(.5*Math.PI),c.scale(1,-1);break;case 6:c.rotate(.5*Math.PI),c.translate(0,-e);break;case 7:c.rotate(.5*Math.PI),c.translate(d,-e),c.scale(-1,1);break;case 8:c.rotate(-.5*Math.PI),c.translate(-d,0)}},a.getTransformedOptions=function(a){if(!a.orientation||1===a.orientation)return a;var b,c={};for(b in a)a.hasOwnProperty(b)&&(c[b]=a[b]);switch(a.orientation){case 2:c.left=a.right,c.right=a.left;break;case 3:c.left=a.right,c.top=a.bottom,c.right=a.left,c.bottom=a.top;break;case 4:c.top=a.bottom,c.bottom=a.top;break;case 5:c.left=a.top,c.top=a.left,c.right=a.bottom,c.bottom=a.right;break;case 6:c.left=a.top,c.top=a.right,c.right=a.bottom,c.bottom=a.left;break;case 7:c.left=a.bottom,c.top=a.right,c.right=a.top,c.bottom=a.left;break;case 8:c.left=a.bottom,c.top=a.left,c.right=a.top,c.bottom=a.right}return a.orientation>4&&(c.maxWidth=a.maxHeight,c.maxHeight=a.maxWidth,c.minWidth=a.minHeight,c.minHeight=a.minWidth,c.sourceWidth=a.sourceHeight,c.sourceHeight=a.sourceWidth),c}}),function(a){"use strict";"function"==typeof define&&define.amd?define(["load-image"],a):a(window.loadImage)}(function(a){"use strict";var b=window.Blob&&(Blob.prototype.slice||Blob.prototype.webkitSlice||Blob.prototype.mozSlice);a.blobSlice=b&&function(){var a=this.slice||this.webkitSlice||this.mozSlice;return a.apply(this,arguments)},a.metaDataParsers={jpeg:{65505:[]}},a.parseMetaData=function(b,c,d){d=d||{};var e=this,f=d.maxMetaDataSize||262144,g={},h=!(window.DataView&&b&&b.size>=12&&"image/jpeg"===b.type&&a.blobSlice);(h||!a.readFile(a.blobSlice.call(b,0,f),function(b){if(b.target.error)return console.log(b.target.error),c(g),void 0;var f,h,i,j,k=b.target.result,l=new DataView(k),m=2,n=l.byteLength-4,o=m;if(65496===l.getUint16(0)){for(;n>m&&(f=l.getUint16(m),f>=65504&&65519>=f||65534===f);){if(h=l.getUint16(m+2)+2,m+h>l.byteLength){console.log("Invalid meta data: Invalid segment size.");break}if(i=a.metaDataParsers.jpeg[f])for(j=0;j<i.length;j+=1)i[j].call(e,l,m,h,g,d);m+=h,o=m}!d.disableImageHead&&o>6&&(g.imageHead=k.slice?k.slice(0,o):new Uint8Array(k).subarray(0,o))}else console.log("Invalid JPEG file: Missing JPEG marker.");c(g)},"readAsArrayBuffer"))&&c(g)}}),function(a){"use strict";"function"==typeof define&&define.amd?define(["load-image","load-image-meta"],a):a(window.loadImage)}(function(a){"use strict";a.ExifMap=function(){return this},a.ExifMap.prototype.map={Orientation:274},a.ExifMap.prototype.get=function(a){return this[a]||this[this.map[a]]},a.getExifThumbnail=function(a,b,c){var d,e,f;if(!c||b+c>a.byteLength)return console.log("Invalid Exif data: Invalid thumbnail data."),void 0;for(d=[],e=0;c>e;e+=1)f=a.getUint8(b+e),d.push((16>f?"0":"")+f.toString(16));return"data:image/jpeg,%"+d.join("%")},a.exifTagTypes={1:{getValue:function(a,b){return a.getUint8(b)},size:1},2:{getValue:function(a,b){return String.fromCharCode(a.getUint8(b))},size:1,ascii:!0},3:{getValue:function(a,b,c){return a.getUint16(b,c)},size:2},4:{getValue:function(a,b,c){return a.getUint32(b,c)},size:4},5:{getValue:function(a,b,c){return a.getUint32(b,c)/a.getUint32(b+4,c)},size:8},9:{getValue:function(a,b,c){return a.getInt32(b,c)},size:4},10:{getValue:function(a,b,c){return a.getInt32(b,c)/a.getInt32(b+4,c)},size:8}},a.exifTagTypes[7]=a.exifTagTypes[1],a.getExifValue=function(b,c,d,e,f,g){var h,i,j,k,l,m,n=a.exifTagTypes[e];if(!n)return console.log("Invalid Exif data: Invalid tag type."),void 0;if(h=n.size*f,i=h>4?c+b.getUint32(d+8,g):d+8,i+h>b.byteLength)return console.log("Invalid Exif data: Invalid data offset."),void 0;if(1===f)return n.getValue(b,i,g);for(j=[],k=0;f>k;k+=1)j[k]=n.getValue(b,i+k*n.size,g);if(n.ascii){for(l="",k=0;k<j.length&&(m=j[k],"\x00"!==m);k+=1)l+=m;return l}return j},a.parseExifTag=function(b,c,d,e,f){var g=b.getUint16(d,e);f.exif[g]=a.getExifValue(b,c,d,b.getUint16(d+2,e),b.getUint32(d+4,e),e)},a.parseExifTags=function(a,b,c,d,e){var f,g,h;if(c+6>a.byteLength)return console.log("Invalid Exif data: Invalid directory offset."),void 0;if(f=a.getUint16(c,d),g=c+2+12*f,g+4>a.byteLength)return console.log("Invalid Exif data: Invalid directory size."),void 0;for(h=0;f>h;h+=1)this.parseExifTag(a,b,c+2+12*h,d,e);return a.getUint32(g,d)},a.parseExifData=function(b,c,d,e,f){if(!f.disableExif){var g,h,i,j=c+10;if(1165519206===b.getUint32(c+4)){if(j+8>b.byteLength)return console.log("Invalid Exif data: Invalid segment size."),void 0;if(0!==b.getUint16(c+8))return console.log("Invalid Exif data: Missing byte alignment offset."),void 0;switch(b.getUint16(j)){case 18761:g=!0;break;case 19789:g=!1;break;default:return console.log("Invalid Exif data: Invalid byte alignment marker."),void 0}if(42!==b.getUint16(j+2,g))return console.log("Invalid Exif data: Missing TIFF marker."),void 0;h=b.getUint32(j+4,g),e.exif=new a.ExifMap,h=a.parseExifTags(b,j,j+h,g,e),h&&!f.disableExifThumbnail&&(i={exif:{}},h=a.parseExifTags(b,j,j+h,g,i),i.exif[513]&&(e.exif.Thumbnail=a.getExifThumbnail(b,j+i.exif[513],i.exif[514]))),e.exif[34665]&&!f.disableExifSub&&a.parseExifTags(b,j,j+e.exif[34665],g,e),e.exif[34853]&&!f.disableExifGps&&a.parseExifTags(b,j,j+e.exif[34853],g,e)}}},a.metaDataParsers.jpeg[65505].push(a.parseExifData)}),function(a){"use strict";"function"==typeof define&&define.amd?define(["load-image","load-image-exif"],a):a(window.loadImage)}(function(a){"use strict";a.ExifMap.prototype.tags={256:"ImageWidth",257:"ImageHeight",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer",40965:"InteroperabilityIFDPointer",258:"BitsPerSample",259:"Compression",262:"PhotometricInterpretation",274:"Orientation",277:"SamplesPerPixel",284:"PlanarConfiguration",530:"YCbCrSubSampling",531:"YCbCrPositioning",282:"XResolution",283:"YResolution",296:"ResolutionUnit",273:"StripOffsets",278:"RowsPerStrip",279:"StripByteCounts",513:"JPEGInterchangeFormat",514:"JPEGInterchangeFormatLength",301:"TransferFunction",318:"WhitePoint",319:"PrimaryChromaticities",529:"YCbCrCoefficients",532:"ReferenceBlackWhite",306:"DateTime",270:"ImageDescription",271:"Make",272:"Model",305:"Software",315:"Artist",33432:"Copyright",36864:"ExifVersion",40960:"FlashpixVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",42240:"Gamma",37121:"ComponentsConfiguration",37122:"CompressedBitsPerPixel",37500:"MakerNote",37510:"UserComment",40964:"RelatedSoundFile",36867:"DateTimeOriginal",36868:"DateTimeDigitized",37520:"SubSecTime",37521:"SubSecTimeOriginal",37522:"SubSecTimeDigitized",33434:"ExposureTime",33437:"FNumber",34850:"ExposureProgram",34852:"SpectralSensitivity",34855:"PhotographicSensitivity",34856:"OECF",34864:"SensitivityType",34865:"StandardOutputSensitivity",34866:"RecommendedExposureIndex",34867:"ISOSpeed",34868:"ISOSpeedLatitudeyyy",34869:"ISOSpeedLatitudezzz",37377:"ShutterSpeedValue",37378:"ApertureValue",37379:"BrightnessValue",37380:"ExposureBias",37381:"MaxApertureValue",37382:"SubjectDistance",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37396:"SubjectArea",37386:"FocalLength",41483:"FlashEnergy",41484:"SpatialFrequencyResponse",41486:"FocalPlaneXResolution",41487:"FocalPlaneYResolution",41488:"FocalPlaneResolutionUnit",41492:"SubjectLocation",41493:"ExposureIndex",41495:"SensingMethod",41728:"FileSource",41729:"SceneType",41730:"CFAPattern",41985:"CustomRendered",41986:"ExposureMode",41987:"WhiteBalance",41988:"DigitalZoomRatio",41989:"FocalLengthIn35mmFilm",41990:"SceneCaptureType",41991:"GainControl",41992:"Contrast",41993:"Saturation",41994:"Sharpness",41995:"DeviceSettingDescription",41996:"SubjectDistanceRange",42016:"ImageUniqueID",42032:"CameraOwnerName",42033:"BodySerialNumber",42034:"LensSpecification",42035:"LensMake",42036:"LensModel",42037:"LensSerialNumber",0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude",5:"GPSAltitudeRef",6:"GPSAltitude",7:"GPSTimeStamp",8:"GPSSatellites",9:"GPSStatus",10:"GPSMeasureMode",11:"GPSDOP",12:"GPSSpeedRef",13:"GPSSpeed",14:"GPSTrackRef",15:"GPSTrack",16:"GPSImgDirectionRef",17:"GPSImgDirection",18:"GPSMapDatum",19:"GPSDestLatitudeRef",20:"GPSDestLatitude",21:"GPSDestLongitudeRef",22:"GPSDestLongitude",23:"GPSDestBearingRef",24:"GPSDestBearing",25:"GPSDestDistanceRef",26:"GPSDestDistance",27:"GPSProcessingMethod",28:"GPSAreaInformation",29:"GPSDateStamp",30:"GPSDifferential",31:"GPSHPositioningError"},a.ExifMap.prototype.stringValues={ExposureProgram:{0:"Undefined",1:"Manual",2:"Normal program",3:"Aperture priority",4:"Shutter priority",5:"Creative program",6:"Action program",7:"Portrait mode",8:"Landscape mode"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{0:"Unknown",1:"Daylight",2:"Fluorescent",3:"Tungsten (incandescent light)",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 - 5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire",1:"Flash fired",5:"Strobe return light not detected",7:"Strobe return light detected",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},SensingMethod:{1:"Undefined",2:"One-chip color area sensor",3:"Two-chip color area sensor",4:"Three-chip color area sensor",5:"Color sequential area sensor",7:"Trilinear sensor",8:"Color sequential linear sensor"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},SceneType:{1:"Directly photographed"},CustomRendered:{0:"Normal process",1:"Custom process"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},GainControl:{0:"None",1:"Low gain up",2:"High gain up",3:"Low gain down",4:"High gain down"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},SubjectDistanceRange:{0:"Unknown",1:"Macro",2:"Close view",3:"Distant view"},FileSource:{3:"DSC"},ComponentsConfiguration:{0:"",1:"Y",2:"Cb",3:"Cr",4:"R",5:"G",6:"B"},Orientation:{1:"top-left",2:"top-right",3:"bottom-right",4:"bottom-left",5:"left-top",6:"right-top",7:"right-bottom",8:"left-bottom"}},a.ExifMap.prototype.getText=function(a){var b=this.get(a);switch(a){case"LightSource":case"Flash":case"MeteringMode":case"ExposureProgram":case"SensingMethod":case"SceneCaptureType":case"SceneType":case"CustomRendered":case"WhiteBalance":case"GainControl":case"Contrast":case"Saturation":case"Sharpness":case"SubjectDistanceRange":case"FileSource":case"Orientation":return this.stringValues[a][b];case"ExifVersion":case"FlashpixVersion":return String.fromCharCode(b[0],b[1],b[2],b[3]);case"ComponentsConfiguration":return this.stringValues[a][b[0]]+this.stringValues[a][b[1]]+this.stringValues[a][b[2]]+this.stringValues[a][b[3]];case"GPSVersionID":return b[0]+"."+b[1]+"."+b[2]+"."+b[3]}return String(b)},function(a){var b,c=a.tags,d=a.map;for(b in c)c.hasOwnProperty(b)&&(d[c[b]]=b)}(a.ExifMap.prototype),a.ExifMap.prototype.getAll=function(){var a,b,c={};for(a in this)this.hasOwnProperty(a)&&(b=this.tags[a],b&&(c[b]=this.getText(b)));return c}});
@@ -1,10 +1,13 @@
1
1
  #= require jquery.ui.widget
2
+ #= require _uuid
3
+ #= require load-image.min
4
+ #= require canvas-to-blob.min
2
5
  #= require jquery.iframe-transport
3
6
  #= require cors/jquery.postmessage-transport
4
7
  #= require cors/jquery.xdr-transport
5
- #= require _uuid
6
8
  #= require jquery.fileupload
7
9
  #= require _image_uploader
8
10
  #= require _uploader_preview
9
11
  #= require _gallery_uploader
10
- #= require _manager
12
+ #= require _show_image
13
+ #= require _manager
@@ -1,8 +1,24 @@
1
1
  @import bootstrap/progress
2
2
 
3
+ .uploadbox-image-container
4
+ background: #eee
5
+ display: inline-block
6
+ img, canvas
7
+ display: inline-block
8
+ vertical-align: bottom
9
+
10
+ .uploadbox-image-container.uploadbox-processing
11
+ background: #eee
12
+
3
13
  .uploadbox-image-uploader
4
14
  position: relative
5
15
 
16
+ .uploader-overlay
17
+ width: 100%
18
+ background: rgba(0, 0, 0, .6)
19
+ position: absolute
20
+ z-index: 1
21
+
6
22
  .btn
7
23
  background-color: #f7f7f7
8
24
  text-align: center
@@ -25,11 +41,11 @@
25
41
  width: 100%
26
42
  top: 10px
27
43
 
28
- &.uploading:before
29
- content: 'Enviando'
44
+ // &.uploading:before
45
+ // content: 'Enviando'
30
46
 
31
- &.processing:before
32
- content: 'Processando'
47
+ // &.processing:before
48
+ // content: 'Processando'
33
49
 
34
50
 
35
51
  .fileupload-new .btn.fileupload-exists
@@ -110,7 +126,7 @@
110
126
  .btn
111
127
  vertical-align: middle
112
128
 
113
- .fileupload-exists .fileupload-new, .fileupload-new .fileupload-exists
129
+ .fileupload-exists .fileupload-new, .fileupload-new .fileupload-exists, .fileupload-uploading .fileupload-new
114
130
  display: none
115
131
 
116
132
  .fileupload-inline .fileupload-controls
@@ -157,7 +173,7 @@
157
173
  width: 100%
158
174
 
159
175
  .progress
160
- height: 10px
176
+ height: 7px
161
177
  width: 100%
162
178
  margin-bottom: 0
163
179
  border-radius: 0
@@ -183,4 +199,8 @@
183
199
  border: 0
184
200
  &:hover
185
201
  background: black
186
- color: white
202
+ color: white
203
+
204
+ .fileupload-uploading
205
+ .btn.fileupload-exists
206
+ display: none
@@ -3,19 +3,29 @@ module Uploadbox
3
3
  layout false
4
4
 
5
5
  def create
6
+ attributes = image_params
7
+ attributes["imageable_type"].constantize # load class
8
+ attributes["original_file"] = attributes["remote_file_url"]
9
+
10
+ attributes.delete("upload_name")
11
+ attributes.delete("remote_file_url")
12
+
13
+ upload = Uploadbox.const_get(upload_class_name).create!(attributes)
14
+
6
15
  if Uploadbox.background_processing
7
- Resque.enqueue(ProcessImage, image_params)
16
+ Resque.enqueue(ProcessImage, {id: upload.id, upload_class_name: upload_class_name})
8
17
  else
9
- Image.create_upload(image_params)
18
+ upload.process
10
19
  end
20
+
11
21
  render nothing: true
12
22
  end
13
23
 
14
24
  def find
15
- params[:imageable_type].constantize # load class
25
+ # binding.pry
26
+ image_params["imageable_type"].constantize # load class
16
27
 
17
- upload_class_name = params[:imageable_type] + params[:upload_name].camelize
18
- @image = Uploadbox.const_get(upload_class_name).find_by(secure_random: params[:secure_random])
28
+ @image = Uploadbox.const_get(upload_class_name).find_by(secure_random: image_params[:secure_random])
19
29
  end
20
30
 
21
31
  def destroy
@@ -26,5 +36,9 @@ module Uploadbox
26
36
  def image_params
27
37
  params.require(:image).permit(:remote_file_url, :imageable_type, :upload_name, :secure_random)
28
38
  end
39
+
40
+ def upload_class_name
41
+ image_params["imageable_type"] + image_params["upload_name"].camelize
42
+ end
29
43
  end
30
44
  end
@@ -4,7 +4,6 @@ module Uploadbox
4
4
  Base64.encode64(policy_data.to_json).gsub("\n", "")
5
5
  end
6
6
 
7
-
8
7
  def s3_signature
9
8
  Base64.encode64(
10
9
  OpenSSL::HMAC.digest(
@@ -17,7 +16,21 @@ module Uploadbox
17
16
 
18
17
  def img(source, options={})
19
18
  if source.respond_to?(:url) and source.respond_to?(:width) and source.respond_to?(:height)
20
- image_tag(source.url, {width: source.width, height: source.height}.merge(options))
19
+ if source.processing?
20
+ data = {
21
+ processing: source.processing?,
22
+ original: source.original_file,
23
+ component: 'ShowImage'
24
+ }
25
+ content_tag :div, class: 'uploadbox-image-container uploadbox-processing', style: "width: #{source.width}px; height: #{source.height}px", data: data do
26
+ image_tag(source.url, {width: source.width, height: source.height, style: 'display: none'}.merge(options))
27
+ end
28
+ else
29
+ data = {}
30
+ content_tag :div, class: 'uploadbox-image-container', width: source.width, height: source.height, data: data do
31
+ image_tag(source.url, {width: source.width, height: source.height}.merge(options))
32
+ end
33
+ end
21
34
  else
22
35
  image_tag(source, options)
23
36
  end
@@ -1,9 +1,9 @@
1
1
  class ProcessImage
2
2
  extend HerokuResqueAutoScale
3
-
3
+
4
4
  @queue = :process_image
5
5
 
6
- def self.perform(image_params)
7
- Image.create_upload(image_params)
6
+ def self.perform(attributes)
7
+ Uploadbox.const_get(attributes['upload_class_name']).find(attributes['id']).process
8
8
  end
9
9
  end
data/app/models/image.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  class Image < ActiveRecord::Base
2
2
  belongs_to :imageable, polymorphic: true
3
3
 
4
- def self.create_upload(attributes)
5
- attributes["imageable_type"].constantize # load class
4
+ def process
5
+ update(remote_file_url: original_file)
6
+ end
6
7
 
7
- upload_class_name = attributes["imageable_type"] + attributes["upload_name"].camelize
8
- attributes.delete("upload_name")
9
- Uploadbox.const_get(upload_class_name).create!(attributes)
8
+ def processing?
9
+ file.blank?
10
10
  end
11
11
  end
data/config/routes.rb CHANGED
@@ -3,5 +3,7 @@ Uploadbox::Engine.routes.draw do
3
3
  resources :images, only: [:create, :update, :destroy] do
4
4
  get 'find', on: :collection
5
5
  end
6
- # mount Resque::Server.new, :at => "/resque"
6
+ if Uploadbox.resque_server
7
+ mount Resque::Server.new, :at => "/resque"
8
+ end
7
9
  end
@@ -3,11 +3,17 @@ Uploadbox.retina_quality = 30
3
3
  Uploadbox.image_quality = 70
4
4
 
5
5
  if Rails.env.production?
6
+ Uploadbox.background_processing = true
7
+
6
8
  REDIS = Redis.connect(url: ENV["REDISCLOUD_URL"])
7
9
  Resque.redis = REDIS
8
10
  Resque.after_fork = Proc.new { ActiveRecord::Base.establish_connection }
9
11
  end
10
12
 
13
+ if Rails.env.development?
14
+ Uploadbox.resque_server = true
15
+ end
16
+
11
17
  CarrierWave.configure do |config|
12
18
  config.storage = :fog
13
19
 
@@ -8,6 +8,7 @@ class CreateImages < ActiveRecord::Migration
8
8
  t.boolean :retina, default: false
9
9
  t.string :upload_name
10
10
  t.string :secure_random, index: true
11
+ t.string :original_file
11
12
 
12
13
  t.timestamps
13
14
  end
@@ -22,7 +22,7 @@ module Uploadbox
22
22
  # @post.picture?
23
23
  define_method("#{upload_name}?") do
24
24
  upload = send("#{upload_name}_upload")
25
- !!(upload and upload.file?)
25
+ !!(upload and (upload.processing? or upload.file?))
26
26
  end
27
27
 
28
28
  # @post.picture
@@ -36,6 +36,10 @@ module Uploadbox
36
36
  def to_s
37
37
  url
38
38
  end
39
+
40
+ def processing?
41
+ false
42
+ end
39
43
  end
40
44
 
41
45
  placeholder = Class.new do
@@ -66,7 +70,7 @@ module Uploadbox
66
70
 
67
71
  # Post.update_picture_versions!
68
72
  self.define_singleton_method "update_#{upload_name}_versions!" do
69
- Uploadbox.const_get(upload_class_name).find_each{|upload| upload.file.recreate_versions!}
73
+ Uploadbox.const_get(upload_class_name).find_each{ |upload| upload.file.recreate_versions! if upload.file? }
70
74
  end
71
75
 
72
76
  # Uploadbox::PostPicture < Image
@@ -111,6 +115,14 @@ module Uploadbox
111
115
  def height
112
116
  dimensions[1]
113
117
  end
118
+
119
+ def processing?
120
+ model.processing?
121
+ end
122
+
123
+ def original_file
124
+ model.original_file
125
+ end
114
126
  end
115
127
  end
116
128
  mount_uploader :file, dynamic_uploader
@@ -209,6 +221,14 @@ module Uploadbox
209
221
  def height
210
222
  dimensions[1]
211
223
  end
224
+
225
+ def processing?
226
+ model.processing?
227
+ end
228
+
229
+ def original_file
230
+ model.original_file
231
+ end
212
232
  end
213
233
  end
214
234
  mount_uploader :file, dynamic_uploader
@@ -1,3 +1,3 @@
1
1
  module Uploadbox
2
- VERSION = "0.1.4"
2
+ VERSION = "0.2.0.beta"
3
3
  end
data/lib/uploadbox.rb CHANGED
@@ -5,4 +5,5 @@ module Uploadbox
5
5
  mattr_accessor :image_quality
6
6
  mattr_accessor :retina_quality
7
7
  mattr_accessor :background_processing
8
+ mattr_accessor :resque_server
8
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uploadbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.0.beta
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julio Protzek
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-03-25 00:00:00.000000000 Z
12
+ date: 2014-03-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -332,25 +332,25 @@ dependencies:
332
332
  - !ruby/object:Gem::Version
333
333
  version: 0.7.2
334
334
  - !ruby/object:Gem::Dependency
335
- name: sqlite3
335
+ name: pg
336
336
  requirement: !ruby/object:Gem::Requirement
337
337
  requirements:
338
338
  - - ~>
339
339
  - !ruby/object:Gem::Version
340
- version: '1.3'
340
+ version: '0.17'
341
341
  - - '>='
342
342
  - !ruby/object:Gem::Version
343
- version: 1.3.7
343
+ version: 0.17.1
344
344
  type: :development
345
345
  prerelease: false
346
346
  version_requirements: !ruby/object:Gem::Requirement
347
347
  requirements:
348
348
  - - ~>
349
349
  - !ruby/object:Gem::Version
350
- version: '1.3'
350
+ version: '0.17'
351
351
  - - '>='
352
352
  - !ruby/object:Gem::Version
353
- version: 1.3.7
353
+ version: 0.17.1
354
354
  - !ruby/object:Gem::Dependency
355
355
  name: rspec-rails
356
356
  requirement: !ruby/object:Gem::Requirement
@@ -536,13 +536,16 @@ files:
536
536
  - app/assets/javascripts/_gallery_uploader.coffee
537
537
  - app/assets/javascripts/_image_uploader.coffee
538
538
  - app/assets/javascripts/_manager.coffee
539
+ - app/assets/javascripts/_show_image.coffee
539
540
  - app/assets/javascripts/_uploader_preview.coffee
540
541
  - app/assets/javascripts/_uuid.js
542
+ - app/assets/javascripts/canvas-to-blob.min.js
541
543
  - app/assets/javascripts/cors/jquery.postmessage-transport.js
542
544
  - app/assets/javascripts/cors/jquery.xdr-transport.js
543
545
  - app/assets/javascripts/jquery.fileupload.js
544
546
  - app/assets/javascripts/jquery.iframe-transport.js
545
547
  - app/assets/javascripts/jquery.ui.widget.js
548
+ - app/assets/javascripts/load-image.min.js
546
549
  - app/assets/javascripts/uploadbox.coffee
547
550
  - app/assets/stylesheets/bootstrap/_progress.css
548
551
  - app/assets/stylesheets/uploadbox.sass
@@ -589,9 +592,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
589
592
  version: 1.9.3
590
593
  required_rubygems_version: !ruby/object:Gem::Requirement
591
594
  requirements:
592
- - - '>='
595
+ - - '>'
593
596
  - !ruby/object:Gem::Version
594
- version: '0'
597
+ version: 1.3.1
595
598
  requirements: []
596
599
  rubyforge_project:
597
600
  rubygems_version: 2.1.11