rails-uploader 0.2.8 → 0.3.0

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +162 -86
  4. data/app/assets/javascripts/uploader/application.js +6 -4
  5. data/app/assets/javascripts/uploader/jquery.uploader.js.coffee +58 -0
  6. data/app/controllers/uploader/attachments_controller.rb +63 -39
  7. data/app/views/uploader/default/_container.html.erb +19 -45
  8. data/app/views/uploader/default/_download.html.erb +4 -5
  9. data/app/views/uploader/default/_upload.html.erb +0 -1
  10. data/config/locales/en.yml +2 -0
  11. data/config/locales/ru.yml +3 -0
  12. data/config/locales/uk.yml +3 -0
  13. data/config/routes.rb +1 -1
  14. data/lib/uploader/asset.rb +63 -84
  15. data/lib/uploader/authorization.rb +52 -0
  16. data/lib/uploader/authorization_adapter.rb +24 -0
  17. data/lib/uploader/chunked_uploads.rb +15 -0
  18. data/lib/uploader/engine.rb +6 -0
  19. data/lib/uploader/file_part.rb +18 -0
  20. data/lib/uploader/fileuploads.rb +42 -65
  21. data/lib/uploader/helpers/field_tag.rb +10 -5
  22. data/lib/uploader/hooks/formtastic.rb +0 -13
  23. data/lib/uploader/upload_request.rb +72 -0
  24. data/lib/uploader/version.rb +1 -1
  25. data/lib/uploader.rb +41 -8
  26. data/spec/dummy/app/models/asset.rb +12 -0
  27. data/spec/dummy/app/models/picture.rb +6 -0
  28. data/spec/dummy/db/test.sqlite3 +0 -0
  29. data/spec/dummy/log/test.log +325 -0
  30. data/spec/dummy/public/uploads/picture/data/1/thumb_rails.png +0 -0
  31. data/spec/dummy/public/uploads/picture/data/3/thumb_rails.png +0 -0
  32. data/spec/fileuploads_spec.rb +4 -4
  33. data/spec/requests/attachments_controller_spec.rb +11 -12
  34. data/vendor/assets/javascripts/uploader/jquery.fileupload-process.js +175 -0
  35. data/vendor/assets/javascripts/uploader/jquery.fileupload-ui.js +164 -261
  36. data/vendor/assets/javascripts/uploader/jquery.fileupload-validate.js +122 -0
  37. data/vendor/assets/javascripts/uploader/jquery.fileupload.js +335 -101
  38. data/vendor/assets/javascripts/uploader/jquery.iframe-transport.js +47 -15
  39. data/vendor/assets/javascripts/uploader/vendor/jquery.ui.widget.js +572 -0
  40. data/vendor/assets/javascripts/uploader/vendor/tmpl.min.js +1 -0
  41. data/vendor/assets/stylesheets/uploader/default.css +26 -19
  42. metadata +12 -9
  43. data/vendor/assets/javascripts/uploader/jquery.fileupload-fp.js +0 -227
  44. data/vendor/assets/javascripts/uploader/jquery.ui.widget.js +0 -530
  45. data/vendor/assets/javascripts/uploader/load-image.min.js +0 -1
  46. data/vendor/assets/javascripts/uploader/locales/en.js +0 -27
  47. data/vendor/assets/javascripts/uploader/locales/ru.js +0 -27
  48. data/vendor/assets/javascripts/uploader/locales/uk.js +0 -27
  49. data/vendor/assets/javascripts/uploader/tmpl.min.js +0 -1
@@ -8,11 +8,11 @@ describe Uploader::Fileuploads do
8
8
  it "should be a Module" do
9
9
  Uploader::Fileuploads.should be_a(Module)
10
10
  end
11
-
11
+
12
12
  it "should return asset class" do
13
13
  Article.fileupload_klass("picture").should == Picture
14
14
  end
15
-
15
+
16
16
  it "should find asset by guid" do
17
17
  asset = Article.fileupload_find("picture", @picture.guid)
18
18
  asset.should == @picture
@@ -51,7 +51,7 @@ describe Uploader::Fileuploads do
51
51
  end
52
52
 
53
53
  it "should return fileuploads columns" do
54
- @article.fileuploads_columns.should include(:picture)
54
+ @article.fileupload_associations.should include(:picture)
55
55
  end
56
56
  end
57
- end
57
+ end
@@ -2,42 +2,41 @@ require 'spec_helper'
2
2
 
3
3
  describe Uploader::AttachmentsController do
4
4
  include Rack::Test::Methods
5
-
5
+
6
6
  def app
7
7
  Dummy::Application
8
8
  end
9
-
9
+
10
10
  it "should create new asset" do
11
11
  file = Rack::Test::UploadedFile.new('spec/factories/files/rails.png', "image/png")
12
12
  post "/uploader/attachments", {
13
- :klass => "Picture",
13
+ :klass => "Picture",
14
14
  :assetable_id => "1",
15
15
  :assetable_type => "Article",
16
16
  :guid => "SOMESTRING",
17
17
  :asset => {:data => file}
18
18
  }
19
-
20
- last_response.body.should include("assetable_type")
21
- last_response.body.should include("SOMESTRING")
22
- last_response.body.should include("data")
19
+
20
+ last_response.body.should include('thumb_url')
21
+ last_response.body.should include('name')
23
22
  end
24
-
23
+
25
24
  it "should destroy asset" do
26
25
  @asset = FactoryGirl.create(:picture)
27
-
26
+
28
27
  lambda {
29
- delete "/uploader/attachments/#{@asset.public_token}", {:klass => "Picture"}
28
+ delete "/uploader/attachments/#{@asset.id}", {:klass => "Picture"}
30
29
  }.should change { Picture.count }.by(-1)
31
30
  end
32
31
 
33
32
  it "should not destroy asset with not exists guid" do
34
33
  @asset = FactoryGirl.create(:picture)
35
-
34
+
36
35
  lambda {
37
36
  delete "/uploader/attachments/wrong", {:klass => "Picture"}
38
37
  }.should raise_error(ActionController::RoutingError)
39
38
  end
40
-
39
+
41
40
  it "should raise 404 error with wrong class" do
42
41
  lambda {
43
42
  post "/uploader/attachments", {:klass => "wrong"}
@@ -0,0 +1,175 @@
1
+ /*
2
+ * jQuery File Upload Processing Plugin
3
+ * https://github.com/blueimp/jQuery-File-Upload
4
+ *
5
+ * Copyright 2012, Sebastian Tschan
6
+ * https://blueimp.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ /* jshint nomen:false */
13
+ /* global define, require, window */
14
+
15
+ ;(function (factory) {
16
+ 'use strict';
17
+ if (typeof define === 'function' && define.amd) {
18
+ // Register as an anonymous AMD module:
19
+ define([
20
+ 'jquery',
21
+ './jquery.fileupload'
22
+ ], factory);
23
+ } else if (typeof exports === 'object') {
24
+ // Node/CommonJS:
25
+ factory(require('jquery'));
26
+ } else {
27
+ // Browser globals:
28
+ factory(
29
+ window.jQuery
30
+ );
31
+ }
32
+ }(function ($) {
33
+ 'use strict';
34
+
35
+ var originalAdd = $.blueimp.fileupload.prototype.options.add;
36
+
37
+ // The File Upload Processing plugin extends the fileupload widget
38
+ // with file processing functionality:
39
+ $.widget('blueimp.fileupload', $.blueimp.fileupload, {
40
+
41
+ options: {
42
+ // The list of processing actions:
43
+ processQueue: [
44
+ /*
45
+ {
46
+ action: 'log',
47
+ type: 'debug'
48
+ }
49
+ */
50
+ ],
51
+ add: function (e, data) {
52
+ var $this = $(this);
53
+ data.process(function () {
54
+ return $this.fileupload('process', data);
55
+ });
56
+ originalAdd.call(this, e, data);
57
+ }
58
+ },
59
+
60
+ processActions: {
61
+ /*
62
+ log: function (data, options) {
63
+ console[options.type](
64
+ 'Processing "' + data.files[data.index].name + '"'
65
+ );
66
+ }
67
+ */
68
+ },
69
+
70
+ _processFile: function (data, originalData) {
71
+ var that = this,
72
+ dfd = $.Deferred().resolveWith(that, [data]),
73
+ chain = dfd.promise();
74
+ this._trigger('process', null, data);
75
+ $.each(data.processQueue, function (i, settings) {
76
+ var func = function (data) {
77
+ if (originalData.errorThrown) {
78
+ return $.Deferred()
79
+ .rejectWith(that, [originalData]).promise();
80
+ }
81
+ return that.processActions[settings.action].call(
82
+ that,
83
+ data,
84
+ settings
85
+ );
86
+ };
87
+ chain = chain.then(func, settings.always && func);
88
+ });
89
+ chain
90
+ .done(function () {
91
+ that._trigger('processdone', null, data);
92
+ that._trigger('processalways', null, data);
93
+ })
94
+ .fail(function () {
95
+ that._trigger('processfail', null, data);
96
+ that._trigger('processalways', null, data);
97
+ });
98
+ return chain;
99
+ },
100
+
101
+ // Replaces the settings of each processQueue item that
102
+ // are strings starting with an "@", using the remaining
103
+ // substring as key for the option map,
104
+ // e.g. "@autoUpload" is replaced with options.autoUpload:
105
+ _transformProcessQueue: function (options) {
106
+ var processQueue = [];
107
+ $.each(options.processQueue, function () {
108
+ var settings = {},
109
+ action = this.action,
110
+ prefix = this.prefix === true ? action : this.prefix;
111
+ $.each(this, function (key, value) {
112
+ if ($.type(value) === 'string' &&
113
+ value.charAt(0) === '@') {
114
+ settings[key] = options[
115
+ value.slice(1) || (prefix ? prefix +
116
+ key.charAt(0).toUpperCase() + key.slice(1) : key)
117
+ ];
118
+ } else {
119
+ settings[key] = value;
120
+ }
121
+
122
+ });
123
+ processQueue.push(settings);
124
+ });
125
+ options.processQueue = processQueue;
126
+ },
127
+
128
+ // Returns the number of files currently in the processsing queue:
129
+ processing: function () {
130
+ return this._processing;
131
+ },
132
+
133
+ // Processes the files given as files property of the data parameter,
134
+ // returns a Promise object that allows to bind callbacks:
135
+ process: function (data) {
136
+ var that = this,
137
+ options = $.extend({}, this.options, data);
138
+ if (options.processQueue && options.processQueue.length) {
139
+ this._transformProcessQueue(options);
140
+ if (this._processing === 0) {
141
+ this._trigger('processstart');
142
+ }
143
+ $.each(data.files, function (index) {
144
+ var opts = index ? $.extend({}, options) : options,
145
+ func = function () {
146
+ if (data.errorThrown) {
147
+ return $.Deferred()
148
+ .rejectWith(that, [data]).promise();
149
+ }
150
+ return that._processFile(opts, data);
151
+ };
152
+ opts.index = index;
153
+ that._processing += 1;
154
+ that._processingQueue = that._processingQueue.then(func, func)
155
+ .always(function () {
156
+ that._processing -= 1;
157
+ if (that._processing === 0) {
158
+ that._trigger('processstop');
159
+ }
160
+ });
161
+ });
162
+ }
163
+ return this._processingQueue;
164
+ },
165
+
166
+ _create: function () {
167
+ this._super();
168
+ this._processing = 0;
169
+ this._processingQueue = $.Deferred().resolveWith(this)
170
+ .promise();
171
+ }
172
+
173
+ });
174
+
175
+ }));
@@ -1,5 +1,5 @@
1
1
  /*
2
- * jQuery File Upload User Interface Plugin 7.4.4
2
+ * jQuery File Upload User Interface Plugin
3
3
  * https://github.com/blueimp/jQuery-File-Upload
4
4
  *
5
5
  * Copyright 2010, Sebastian Tschan
@@ -9,30 +9,43 @@
9
9
  * http://www.opensource.org/licenses/MIT
10
10
  */
11
11
 
12
- /*jslint nomen: true, unparam: true, regexp: true */
13
- /*global define, window, URL, webkitURL, FileReader */
12
+ /* jshint nomen:false */
13
+ /* global define, require, window */
14
14
 
15
- (function (factory) {
15
+ ;(function (factory) {
16
16
  'use strict';
17
17
  if (typeof define === 'function' && define.amd) {
18
18
  // Register as an anonymous AMD module:
19
19
  define([
20
20
  'jquery',
21
21
  'tmpl',
22
- 'load-image',
23
- './jquery.fileupload-fp'
22
+ './jquery.fileupload-image',
23
+ './jquery.fileupload-audio',
24
+ './jquery.fileupload-video',
25
+ './jquery.fileupload-validate'
24
26
  ], factory);
27
+ } else if (typeof exports === 'object') {
28
+ // Node/CommonJS:
29
+ factory(
30
+ require('jquery'),
31
+ require('tmpl')
32
+ );
25
33
  } else {
26
34
  // Browser globals:
27
35
  factory(
28
36
  window.jQuery,
29
- window.tmpl,
30
- window.loadImage
37
+ window.tmpl
31
38
  );
32
39
  }
33
- }(function ($, tmpl, loadImage) {
40
+ }(function ($, tmpl) {
34
41
  'use strict';
35
42
 
43
+ $.blueimp.fileupload.prototype._specialOptions.push(
44
+ 'filesContainer',
45
+ 'uploadTemplateId',
46
+ 'downloadTemplateId'
47
+ );
48
+
36
49
  // The UI version extends the file upload widget
37
50
  // and adds complete user interface interaction:
38
51
  $.widget('blueimp.fileupload', $.blueimp.fileupload, {
@@ -42,29 +55,6 @@
42
55
  // as the user clicks on the start buttons. To enable automatic
43
56
  // uploads, set the following option to true:
44
57
  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,
68
58
  // The ID of the upload template:
69
59
  uploadTemplateId: 'template-upload',
70
60
  // The ID of the download template:
@@ -79,48 +69,79 @@
79
69
  // option of the $.ajax upload requests:
80
70
  dataType: 'json',
81
71
 
72
+ // Error and info messages:
73
+ messages: {
74
+ unknownError: 'Unknown error'
75
+ },
76
+
77
+ // Function returning the current number of files,
78
+ // used by the maxNumberOfFiles validation:
79
+ getNumberOfFiles: function () {
80
+ return this.filesContainer.children()
81
+ .not('.processing').length;
82
+ },
83
+
84
+ // Callback to retrieve the list of files from the server response:
85
+ getFilesFromResponse: function (data) {
86
+ if (data.result && $.isArray(data.result.files)) {
87
+ return data.result.files;
88
+ }
89
+ return [];
90
+ },
91
+
82
92
  // The add callback is invoked as soon as files are added to the fileupload
83
93
  // widget (via file input selection, drag & drop or add API call).
84
94
  // See the basic file upload widget for more information:
85
95
  add: function (e, data) {
86
- var that = $(this).data('blueimp-fileupload') ||
87
- $(this).data('fileupload'),
88
- options = that.options,
89
- files = data.files;
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);
94
- data.context = that._renderUpload(files).data('data', data);
95
- options.filesContainer[
96
- options.prependFiles ? 'prepend' : 'append'
97
- ](data.context);
96
+ if (e.isDefaultPrevented()) {
97
+ return false;
98
+ }
99
+ var $this = $(this),
100
+ that = $this.data('blueimp-fileupload') ||
101
+ $this.data('fileupload'),
102
+ options = that.options;
103
+ data.context = that._renderUpload(data.files)
104
+ .data('data', data)
105
+ .addClass('processing');
106
+ options.filesContainer[
107
+ options.prependFiles ? 'prepend' : 'append'
108
+ ](data.context);
109
+ that._forceReflow(data.context);
110
+ that._transition(data.context);
111
+ data.process(function () {
112
+ return $this.fileupload('process', data);
113
+ }).always(function () {
114
+ data.context.each(function (index) {
115
+ $(this).find('.size').text(
116
+ that._formatFileSize(data.files[index].size)
117
+ );
118
+ }).removeClass('processing');
98
119
  that._renderPreviews(data);
99
- that._forceReflow(data.context);
100
- that._transition(data.context).done(
101
- function () {
102
- if ((that._trigger('added', e, data) !== false) &&
103
- (options.autoUpload || data.autoUpload) &&
104
- data.autoUpload !== false && data.isValidated) {
105
- data.submit();
120
+ }).done(function () {
121
+ data.context.find('.start').prop('disabled', false);
122
+ if ((that._trigger('added', e, data) !== false) &&
123
+ (options.autoUpload || data.autoUpload) &&
124
+ data.autoUpload !== false) {
125
+ data.submit();
126
+ }
127
+ }).fail(function () {
128
+ if (data.files.error) {
129
+ data.context.each(function (index) {
130
+ var error = data.files[index].error;
131
+ if (error) {
132
+ $(this).find('.error').text(error);
106
133
  }
107
- }
108
- );
134
+ });
135
+ }
109
136
  });
110
137
  },
111
138
  // Callback for the start of each file upload request:
112
139
  send: function (e, data) {
140
+ if (e.isDefaultPrevented()) {
141
+ return false;
142
+ }
113
143
  var that = $(this).data('blueimp-fileupload') ||
114
144
  $(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
- }
124
145
  if (data.context && data.dataType &&
125
146
  data.dataType.substr(0, 6) === 'iframe') {
126
147
  // Iframe Transport does not support progress events.
@@ -131,7 +152,7 @@
131
152
  !$.support.transition && 'progress-animated'
132
153
  )
133
154
  .attr('aria-valuenow', 100)
134
- .find('.bar').css(
155
+ .children().first().css(
135
156
  'width',
136
157
  '100%'
137
158
  );
@@ -140,19 +161,21 @@
140
161
  },
141
162
  // Callback for successful uploads:
142
163
  done: function (e, data) {
164
+ if (e.isDefaultPrevented()) {
165
+ return false;
166
+ }
143
167
  var that = $(this).data('blueimp-fileupload') ||
144
168
  $(this).data('fileupload'),
145
- files = that._getFilesFromResponse(data),
169
+ getFilesFromResponse = data.getFilesFromResponse ||
170
+ that.options.getFilesFromResponse,
171
+ files = getFilesFromResponse(data),
146
172
  template,
147
173
  deferred;
148
174
  if (data.context) {
149
175
  data.context.each(function (index) {
150
176
  var file = files[index] ||
151
- {error: 'Empty file upload result'},
152
- deferred = that._addFinishedDeferreds();
153
- if (file.error) {
154
- that._adjustMaxNumberOfFiles(1);
155
- }
177
+ {error: 'Empty file upload result'};
178
+ deferred = that._addFinishedDeferreds();
156
179
  that._transition($(this)).done(
157
180
  function () {
158
181
  var node = $(this);
@@ -171,19 +194,9 @@
171
194
  );
172
195
  });
173
196
  } 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
- }
185
- template = that._renderDownload(files)
186
- .appendTo(that.options.filesContainer);
197
+ template = that._renderDownload(files)[
198
+ that.options.prependFiles ? 'prependTo' : 'appendTo'
199
+ ](that.options.filesContainer);
187
200
  that._forceReflow(template);
188
201
  deferred = that._addFinishedDeferreds();
189
202
  that._transition(template).done(
@@ -198,19 +211,19 @@
198
211
  },
199
212
  // Callback for failed (abort or error) uploads:
200
213
  fail: function (e, data) {
214
+ if (e.isDefaultPrevented()) {
215
+ return false;
216
+ }
201
217
  var that = $(this).data('blueimp-fileupload') ||
202
218
  $(this).data('fileupload'),
203
219
  template,
204
220
  deferred;
205
- if (data.maxNumberOfFilesAdjusted) {
206
- that._adjustMaxNumberOfFiles(data.files.length);
207
- }
208
221
  if (data.context) {
209
222
  data.context.each(function (index) {
210
223
  if (data.errorThrown !== 'abort') {
211
224
  var file = data.files[index];
212
225
  file.error = file.error || data.errorThrown ||
213
- true;
226
+ data.i18n('unknownError');
214
227
  deferred = that._addFinishedDeferreds();
215
228
  that._transition($(this)).done(
216
229
  function () {
@@ -241,8 +254,9 @@
241
254
  }
242
255
  });
243
256
  } else if (data.errorThrown !== 'abort') {
244
- data.context = that._renderUpload(data.files)
245
- .appendTo(that.options.filesContainer)
257
+ data.context = that._renderUpload(data.files)[
258
+ that.options.prependFiles ? 'prependTo' : 'appendTo'
259
+ ](that.options.filesContainer)
246
260
  .data('data', data);
247
261
  that._forceReflow(data.context);
248
262
  deferred = that._addFinishedDeferreds();
@@ -262,18 +276,26 @@
262
276
  },
263
277
  // Callback for upload progress events:
264
278
  progress: function (e, data) {
279
+ if (e.isDefaultPrevented()) {
280
+ return false;
281
+ }
282
+ var progress = Math.floor(data.loaded / data.total * 100);
265
283
  if (data.context) {
266
- var progress = Math.floor(data.loaded / data.total * 100);
267
- data.context.find('.progress')
268
- .attr('aria-valuenow', progress)
269
- .find('.bar').css(
270
- 'width',
271
- progress + '%'
272
- );
284
+ data.context.each(function () {
285
+ $(this).find('.progress')
286
+ .attr('aria-valuenow', progress)
287
+ .children().first().css(
288
+ 'width',
289
+ progress + '%'
290
+ );
291
+ });
273
292
  }
274
293
  },
275
294
  // Callback for global upload progress events:
276
295
  progressall: function (e, data) {
296
+ if (e.isDefaultPrevented()) {
297
+ return false;
298
+ }
277
299
  var $this = $(this),
278
300
  progress = Math.floor(data.loaded / data.total * 100),
279
301
  globalProgressNode = $this.find('.fileupload-progress'),
@@ -288,13 +310,16 @@
288
310
  globalProgressNode
289
311
  .find('.progress')
290
312
  .attr('aria-valuenow', progress)
291
- .find('.bar').css(
313
+ .children().first().css(
292
314
  'width',
293
315
  progress + '%'
294
316
  );
295
317
  },
296
318
  // Callback for uploads start, equivalent to the global ajaxStart event:
297
319
  start: function (e) {
320
+ if (e.isDefaultPrevented()) {
321
+ return false;
322
+ }
298
323
  var that = $(this).data('blueimp-fileupload') ||
299
324
  $(this).data('fileupload');
300
325
  that._resetFinishedDeferreds();
@@ -306,6 +331,9 @@
306
331
  },
307
332
  // Callback for uploads stop, equivalent to the global ajaxStop event:
308
333
  stop: function (e) {
334
+ if (e.isDefaultPrevented()) {
335
+ return false;
336
+ }
309
337
  var that = $(this).data('blueimp-fileupload') ||
310
338
  $(this).data('fileupload'),
311
339
  deferred = that._addFinishedDeferreds();
@@ -317,26 +345,46 @@
317
345
  function () {
318
346
  $(this).find('.progress')
319
347
  .attr('aria-valuenow', '0')
320
- .find('.bar').css('width', '0%');
348
+ .children().first().css('width', '0%');
321
349
  $(this).find('.progress-extended').html(' ');
322
350
  deferred.resolve();
323
351
  }
324
352
  );
325
353
  },
354
+ processstart: function (e) {
355
+ if (e.isDefaultPrevented()) {
356
+ return false;
357
+ }
358
+ $(this).addClass('fileupload-processing');
359
+ },
360
+ processstop: function (e) {
361
+ if (e.isDefaultPrevented()) {
362
+ return false;
363
+ }
364
+ $(this).removeClass('fileupload-processing');
365
+ },
326
366
  // Callback for file deletion:
327
367
  destroy: function (e, data) {
368
+ if (e.isDefaultPrevented()) {
369
+ return false;
370
+ }
328
371
  var that = $(this).data('blueimp-fileupload') ||
329
- $(this).data('fileupload');
330
- if (data.url) {
331
- $.ajax(data).done(function () {
372
+ $(this).data('fileupload'),
373
+ removeNode = function () {
332
374
  that._transition(data.context).done(
333
375
  function () {
334
376
  $(this).remove();
335
- that._adjustMaxNumberOfFiles(1);
336
377
  that._trigger('destroyed', e, data);
337
378
  }
338
379
  );
380
+ };
381
+ if (data.url) {
382
+ data.dataType = data.dataType || that.options.dataType;
383
+ $.ajax(data).done(removeNode).fail(function () {
384
+ that._trigger('destroyfailed', e, data);
339
385
  });
386
+ } else {
387
+ removeNode();
340
388
  }
341
389
  }
342
390
  },
@@ -357,13 +405,6 @@
357
405
  return this._finishedUploads;
358
406
  },
359
407
 
360
- _getFilesFromResponse: function (data) {
361
- if (data.result && $.isArray(data.result.files)) {
362
- return data.result.files;
363
- }
364
- return [];
365
- },
366
-
367
408
  // Link handler, that allows to download files
368
409
  // by drag & drop of the links to the desktop:
369
410
  _enableDragToDesktop: function () {
@@ -377,21 +418,10 @@
377
418
  'DownloadURL',
378
419
  [type, name, url].join(':')
379
420
  );
380
- } catch (err) {}
421
+ } catch (ignore) {}
381
422
  });
382
423
  },
383
424
 
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
-
395
425
  _formatFileSize: function (bytes) {
396
426
  if (typeof bytes !== 'number') {
397
427
  return '';
@@ -447,46 +477,6 @@
447
477
  this._formatFileSize(data.total);
448
478
  },
449
479
 
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
-
490
480
  _renderTemplate: function (func, files) {
491
481
  if (!func) {
492
482
  return $();
@@ -502,63 +492,10 @@
502
492
  return $(this.options.templatesContainer).html(result).children();
503
493
  },
504
494
 
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
-
538
495
  _renderPreviews: function (data) {
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
- }
496
+ data.context.find('.preview').each(function (index, elm) {
497
+ $(elm).append(data.files[index].preview);
560
498
  });
561
- return this._processingQueue;
562
499
  },
563
500
 
564
501
  _renderUpload: function (files) {
@@ -580,20 +517,23 @@
580
517
  var button = $(e.currentTarget),
581
518
  template = button.closest('.template-upload'),
582
519
  data = template.data('data');
583
- if (data && data.submit && !data.jqXHR && data.submit()) {
584
- button.prop('disabled', true);
520
+ button.prop('disabled', true);
521
+ if (data && data.submit) {
522
+ data.submit();
585
523
  }
586
524
  },
587
525
 
588
526
  _cancelHandler: function (e) {
589
527
  e.preventDefault();
590
- var template = $(e.currentTarget).closest('.template-upload'),
528
+ var template = $(e.currentTarget)
529
+ .closest('.template-upload,.template-download'),
591
530
  data = template.data('data') || {};
592
- if (!data.jqXHR) {
531
+ data.context = data.context || template;
532
+ if (data.abort) {
533
+ data.abort();
534
+ } else {
593
535
  data.errorThrown = 'abort';
594
536
  this._trigger('fail', e, data);
595
- } else {
596
- data.jqXHR.abort();
597
537
  }
598
538
  },
599
539
 
@@ -731,55 +671,18 @@
731
671
  }
732
672
  },
733
673
 
734
- _stringToRegExp: function (str) {
735
- var parts = str.split('/'),
736
- modifiers = parts.pop();
737
- parts.shift();
738
- return new RegExp(parts.join('/'), modifiers);
739
- },
740
-
741
- _initRegExpOptions: function () {
742
- var options = this.options;
743
- if ($.type(options.acceptFileTypes) === 'string') {
744
- options.acceptFileTypes = this._stringToRegExp(
745
- options.acceptFileTypes
746
- );
747
- }
748
- if ($.type(options.previewSourceFileTypes) === 'string') {
749
- options.previewSourceFileTypes = this._stringToRegExp(
750
- options.previewSourceFileTypes
751
- );
752
- }
753
- },
754
-
755
674
  _initSpecialOptions: function () {
756
675
  this._super();
757
676
  this._initFilesContainer();
758
677
  this._initTemplates();
759
- this._initRegExpOptions();
760
- },
761
-
762
- _setOption: function (key, value) {
763
- this._super(key, value);
764
- if (key === 'maxNumberOfFiles') {
765
- this._adjustMaxNumberOfFiles(0);
766
- }
767
678
  },
768
679
 
769
680
  _create: function () {
770
681
  this._super();
771
- this._refreshOptionsList.push(
772
- 'filesContainer',
773
- 'uploadTemplateId',
774
- 'downloadTemplateId'
775
- );
776
- if (!this._processingQueue) {
777
- this._processingQueue = $.Deferred().resolveWith(this).promise();
778
- this.process = function () {
779
- return this._processingQueue;
780
- };
781
- }
782
682
  this._resetFinishedDeferreds();
683
+ if (!$.support.fileInput) {
684
+ this._disableFileInputButton();
685
+ }
783
686
  },
784
687
 
785
688
  enable: function () {