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.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +162 -86
- data/app/assets/javascripts/uploader/application.js +6 -4
- data/app/assets/javascripts/uploader/jquery.uploader.js.coffee +58 -0
- data/app/controllers/uploader/attachments_controller.rb +63 -39
- data/app/views/uploader/default/_container.html.erb +19 -45
- data/app/views/uploader/default/_download.html.erb +4 -5
- data/app/views/uploader/default/_upload.html.erb +0 -1
- data/config/locales/en.yml +2 -0
- data/config/locales/ru.yml +3 -0
- data/config/locales/uk.yml +3 -0
- data/config/routes.rb +1 -1
- data/lib/uploader/asset.rb +63 -84
- data/lib/uploader/authorization.rb +52 -0
- data/lib/uploader/authorization_adapter.rb +24 -0
- data/lib/uploader/chunked_uploads.rb +15 -0
- data/lib/uploader/engine.rb +6 -0
- data/lib/uploader/file_part.rb +18 -0
- data/lib/uploader/fileuploads.rb +42 -65
- data/lib/uploader/helpers/field_tag.rb +10 -5
- data/lib/uploader/hooks/formtastic.rb +0 -13
- data/lib/uploader/upload_request.rb +72 -0
- data/lib/uploader/version.rb +1 -1
- data/lib/uploader.rb +41 -8
- data/spec/dummy/app/models/asset.rb +12 -0
- data/spec/dummy/app/models/picture.rb +6 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +325 -0
- data/spec/dummy/public/uploads/picture/data/1/thumb_rails.png +0 -0
- data/spec/dummy/public/uploads/picture/data/3/thumb_rails.png +0 -0
- data/spec/fileuploads_spec.rb +4 -4
- data/spec/requests/attachments_controller_spec.rb +11 -12
- data/vendor/assets/javascripts/uploader/jquery.fileupload-process.js +175 -0
- data/vendor/assets/javascripts/uploader/jquery.fileupload-ui.js +164 -261
- data/vendor/assets/javascripts/uploader/jquery.fileupload-validate.js +122 -0
- data/vendor/assets/javascripts/uploader/jquery.fileupload.js +335 -101
- data/vendor/assets/javascripts/uploader/jquery.iframe-transport.js +47 -15
- data/vendor/assets/javascripts/uploader/vendor/jquery.ui.widget.js +572 -0
- data/vendor/assets/javascripts/uploader/vendor/tmpl.min.js +1 -0
- data/vendor/assets/stylesheets/uploader/default.css +26 -19
- metadata +12 -9
- data/vendor/assets/javascripts/uploader/jquery.fileupload-fp.js +0 -227
- data/vendor/assets/javascripts/uploader/jquery.ui.widget.js +0 -530
- data/vendor/assets/javascripts/uploader/load-image.min.js +0 -1
- data/vendor/assets/javascripts/uploader/locales/en.js +0 -27
- data/vendor/assets/javascripts/uploader/locales/ru.js +0 -27
- data/vendor/assets/javascripts/uploader/locales/uk.js +0 -27
- data/vendor/assets/javascripts/uploader/tmpl.min.js +0 -1
Binary file
|
Binary file
|
data/spec/fileuploads_spec.rb
CHANGED
@@ -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.
|
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(
|
21
|
-
last_response.body.should include(
|
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.
|
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
|
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
|
-
/*
|
13
|
-
/*global define,
|
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
|
-
'
|
23
|
-
'./jquery.fileupload-
|
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
|
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
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
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
|
-
.
|
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
|
-
|
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
|
-
|
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
|
-
|
175
|
-
|
176
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
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
|
-
.
|
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
|
-
.
|
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
|
-
|
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 (
|
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
|
-
|
540
|
-
|
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
|
-
|
584
|
-
|
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)
|
528
|
+
var template = $(e.currentTarget)
|
529
|
+
.closest('.template-upload,.template-download'),
|
591
530
|
data = template.data('data') || {};
|
592
|
-
|
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 () {
|