jquery-fileupload-rails 0.4.1 → 0.4.2
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 +7 -0
- data/README.md +38 -16
- data/{vendor → app}/assets/images/loading.gif +0 -0
- data/{vendor → app}/assets/images/progressbar.gif +0 -0
- data/app/assets/javascripts/jquery-fileupload/angularjs.js +12 -0
- data/app/assets/javascripts/jquery-fileupload/basic-plus.js +11 -0
- data/app/assets/javascripts/jquery-fileupload/basic.js +3 -0
- data/{vendor → app}/assets/javascripts/jquery-fileupload/cors/jquery.postmessage-transport.js +4 -4
- data/{vendor → app}/assets/javascripts/jquery-fileupload/cors/jquery.xdr-transport.js +1 -2
- data/app/assets/javascripts/jquery-fileupload/index.js +13 -0
- data/app/assets/javascripts/jquery-fileupload/jquery-ui.js +13 -0
- data/app/assets/javascripts/jquery-fileupload/jquery.fileupload-angular.js +429 -0
- data/app/assets/javascripts/jquery-fileupload/jquery.fileupload-audio.js +106 -0
- data/app/assets/javascripts/jquery-fileupload/jquery.fileupload-image.js +315 -0
- data/app/assets/javascripts/jquery-fileupload/jquery.fileupload-jquery-ui.js +152 -0
- data/app/assets/javascripts/jquery-fileupload/jquery.fileupload-process.js +172 -0
- data/{vendor → app}/assets/javascripts/jquery-fileupload/jquery.fileupload-ui.js +178 -273
- data/app/assets/javascripts/jquery-fileupload/jquery.fileupload-validate.js +119 -0
- data/app/assets/javascripts/jquery-fileupload/jquery.fileupload-video.js +106 -0
- data/{vendor → app}/assets/javascripts/jquery-fileupload/jquery.fileupload.js +481 -188
- data/{vendor → app}/assets/javascripts/jquery-fileupload/jquery.iframe-transport.js +43 -14
- data/{vendor → app}/assets/javascripts/jquery-fileupload/locale.js +0 -0
- data/{vendor → app}/assets/javascripts/jquery-fileupload/vendor/canvas-to-blob.js +9 -5
- data/{vendor → app}/assets/javascripts/jquery-fileupload/vendor/jquery.ui.widget.js +72 -44
- data/app/assets/javascripts/jquery-fileupload/vendor/load-image.all.min.js +1 -0
- data/{vendor → app}/assets/javascripts/jquery-fileupload/vendor/tmpl.js +9 -8
- data/app/assets/stylesheets/jquery.fileupload-noscript.scss +22 -0
- data/app/assets/stylesheets/jquery.fileupload-ui-noscript.scss +17 -0
- data/app/assets/stylesheets/jquery.fileupload-ui.scss +57 -0
- data/app/assets/stylesheets/jquery.fileupload.scss +36 -0
- data/lib/jquery/fileupload/rails/version.rb +1 -1
- metadata +43 -39
- data/vendor/assets/javascripts/jquery-fileupload/basic.js +0 -4
- data/vendor/assets/javascripts/jquery-fileupload/index.js +0 -9
- data/vendor/assets/javascripts/jquery-fileupload/jquery.fileupload-fp.js +0 -223
- data/vendor/assets/javascripts/jquery-fileupload/vendor/load-image.js +0 -121
- data/vendor/assets/stylesheets/jquery.fileupload-ui.scss +0 -84
@@ -0,0 +1,119 @@
|
|
1
|
+
/*
|
2
|
+
* jQuery File Upload Validation Plugin 1.1.2
|
3
|
+
* https://github.com/blueimp/jQuery-File-Upload
|
4
|
+
*
|
5
|
+
* Copyright 2013, Sebastian Tschan
|
6
|
+
* https://blueimp.net
|
7
|
+
*
|
8
|
+
* Licensed under the MIT license:
|
9
|
+
* http://www.opensource.org/licenses/MIT
|
10
|
+
*/
|
11
|
+
|
12
|
+
/* global define, window */
|
13
|
+
|
14
|
+
(function (factory) {
|
15
|
+
'use strict';
|
16
|
+
if (typeof define === 'function' && define.amd) {
|
17
|
+
// Register as an anonymous AMD module:
|
18
|
+
define([
|
19
|
+
'jquery',
|
20
|
+
'./jquery.fileupload-process'
|
21
|
+
], factory);
|
22
|
+
} else {
|
23
|
+
// Browser globals:
|
24
|
+
factory(
|
25
|
+
window.jQuery
|
26
|
+
);
|
27
|
+
}
|
28
|
+
}(function ($) {
|
29
|
+
'use strict';
|
30
|
+
|
31
|
+
// Append to the default processQueue:
|
32
|
+
$.blueimp.fileupload.prototype.options.processQueue.push(
|
33
|
+
{
|
34
|
+
action: 'validate',
|
35
|
+
// Always trigger this action,
|
36
|
+
// even if the previous action was rejected:
|
37
|
+
always: true,
|
38
|
+
// Options taken from the global options map:
|
39
|
+
acceptFileTypes: '@',
|
40
|
+
maxFileSize: '@',
|
41
|
+
minFileSize: '@',
|
42
|
+
maxNumberOfFiles: '@',
|
43
|
+
disabled: '@disableValidation'
|
44
|
+
}
|
45
|
+
);
|
46
|
+
|
47
|
+
// The File Upload Validation plugin extends the fileupload widget
|
48
|
+
// with file validation functionality:
|
49
|
+
$.widget('blueimp.fileupload', $.blueimp.fileupload, {
|
50
|
+
|
51
|
+
options: {
|
52
|
+
/*
|
53
|
+
// The regular expression for allowed file types, matches
|
54
|
+
// against either file type or file name:
|
55
|
+
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
|
56
|
+
// The maximum allowed file size in bytes:
|
57
|
+
maxFileSize: 10000000, // 10 MB
|
58
|
+
// The minimum allowed file size in bytes:
|
59
|
+
minFileSize: undefined, // No minimal file size
|
60
|
+
// The limit of files to be uploaded:
|
61
|
+
maxNumberOfFiles: 10,
|
62
|
+
*/
|
63
|
+
|
64
|
+
// Function returning the current number of files,
|
65
|
+
// has to be overriden for maxNumberOfFiles validation:
|
66
|
+
getNumberOfFiles: $.noop,
|
67
|
+
|
68
|
+
// Error and info messages:
|
69
|
+
messages: {
|
70
|
+
maxNumberOfFiles: 'Maximum number of files exceeded',
|
71
|
+
acceptFileTypes: 'File type not allowed',
|
72
|
+
maxFileSize: 'File is too large',
|
73
|
+
minFileSize: 'File is too small'
|
74
|
+
}
|
75
|
+
},
|
76
|
+
|
77
|
+
processActions: {
|
78
|
+
|
79
|
+
validate: function (data, options) {
|
80
|
+
if (options.disabled) {
|
81
|
+
return data;
|
82
|
+
}
|
83
|
+
var dfd = $.Deferred(),
|
84
|
+
settings = this.options,
|
85
|
+
file = data.files[data.index],
|
86
|
+
fileSize;
|
87
|
+
if (options.minFileSize || options.maxFileSize) {
|
88
|
+
fileSize = file.size;
|
89
|
+
}
|
90
|
+
if ($.type(options.maxNumberOfFiles) === 'number' &&
|
91
|
+
(settings.getNumberOfFiles() || 0) + data.files.length >
|
92
|
+
options.maxNumberOfFiles) {
|
93
|
+
file.error = settings.i18n('maxNumberOfFiles');
|
94
|
+
} else if (options.acceptFileTypes &&
|
95
|
+
!(options.acceptFileTypes.test(file.type) ||
|
96
|
+
options.acceptFileTypes.test(file.name))) {
|
97
|
+
file.error = settings.i18n('acceptFileTypes');
|
98
|
+
} else if (fileSize > options.maxFileSize) {
|
99
|
+
file.error = settings.i18n('maxFileSize');
|
100
|
+
} else if ($.type(fileSize) === 'number' &&
|
101
|
+
fileSize < options.minFileSize) {
|
102
|
+
file.error = settings.i18n('minFileSize');
|
103
|
+
} else {
|
104
|
+
delete file.error;
|
105
|
+
}
|
106
|
+
if (file.error || data.files.error) {
|
107
|
+
data.files.error = true;
|
108
|
+
dfd.rejectWith(this, [data]);
|
109
|
+
} else {
|
110
|
+
dfd.resolveWith(this, [data]);
|
111
|
+
}
|
112
|
+
return dfd.promise();
|
113
|
+
}
|
114
|
+
|
115
|
+
}
|
116
|
+
|
117
|
+
});
|
118
|
+
|
119
|
+
}));
|
@@ -0,0 +1,106 @@
|
|
1
|
+
/*
|
2
|
+
* jQuery File Upload Video Preview Plugin 1.0.3
|
3
|
+
* https://github.com/blueimp/jQuery-File-Upload
|
4
|
+
*
|
5
|
+
* Copyright 2013, 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, window, document */
|
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
|
+
'load-image',
|
22
|
+
'./jquery.fileupload-process'
|
23
|
+
], factory);
|
24
|
+
} else {
|
25
|
+
// Browser globals:
|
26
|
+
factory(
|
27
|
+
window.jQuery,
|
28
|
+
window.loadImage
|
29
|
+
);
|
30
|
+
}
|
31
|
+
}(function ($, loadImage) {
|
32
|
+
'use strict';
|
33
|
+
|
34
|
+
// Prepend to the default processQueue:
|
35
|
+
$.blueimp.fileupload.prototype.options.processQueue.unshift(
|
36
|
+
{
|
37
|
+
action: 'loadVideo',
|
38
|
+
// Use the action as prefix for the "@" options:
|
39
|
+
prefix: true,
|
40
|
+
fileTypes: '@',
|
41
|
+
maxFileSize: '@',
|
42
|
+
disabled: '@disableVideoPreview'
|
43
|
+
},
|
44
|
+
{
|
45
|
+
action: 'setVideo',
|
46
|
+
name: '@videoPreviewName',
|
47
|
+
disabled: '@disableVideoPreview'
|
48
|
+
}
|
49
|
+
);
|
50
|
+
|
51
|
+
// The File Upload Video Preview plugin extends the fileupload widget
|
52
|
+
// with video preview functionality:
|
53
|
+
$.widget('blueimp.fileupload', $.blueimp.fileupload, {
|
54
|
+
|
55
|
+
options: {
|
56
|
+
// The regular expression for the types of video files to load,
|
57
|
+
// matched against the file type:
|
58
|
+
loadVideoFileTypes: /^video\/.*$/
|
59
|
+
},
|
60
|
+
|
61
|
+
_videoElement: document.createElement('video'),
|
62
|
+
|
63
|
+
processActions: {
|
64
|
+
|
65
|
+
// Loads the video file given via data.files and data.index
|
66
|
+
// as video element if the browser supports playing it.
|
67
|
+
// Accepts the options fileTypes (regular expression)
|
68
|
+
// and maxFileSize (integer) to limit the files to load:
|
69
|
+
loadVideo: function (data, options) {
|
70
|
+
if (options.disabled) {
|
71
|
+
return data;
|
72
|
+
}
|
73
|
+
var file = data.files[data.index],
|
74
|
+
url,
|
75
|
+
video;
|
76
|
+
if (this._videoElement.canPlayType &&
|
77
|
+
this._videoElement.canPlayType(file.type) &&
|
78
|
+
($.type(options.maxFileSize) !== 'number' ||
|
79
|
+
file.size <= options.maxFileSize) &&
|
80
|
+
(!options.fileTypes ||
|
81
|
+
options.fileTypes.test(file.type))) {
|
82
|
+
url = loadImage.createObjectURL(file);
|
83
|
+
if (url) {
|
84
|
+
video = this._videoElement.cloneNode(false);
|
85
|
+
video.src = url;
|
86
|
+
video.controls = true;
|
87
|
+
data.video = video;
|
88
|
+
return data;
|
89
|
+
}
|
90
|
+
}
|
91
|
+
return data;
|
92
|
+
},
|
93
|
+
|
94
|
+
// Sets the video element as a property of the file object:
|
95
|
+
setVideo: function (data, options) {
|
96
|
+
if (data.video && !options.disabled) {
|
97
|
+
data.files[data.index][options.name || 'preview'] = data.video;
|
98
|
+
}
|
99
|
+
return data;
|
100
|
+
}
|
101
|
+
|
102
|
+
}
|
103
|
+
|
104
|
+
});
|
105
|
+
|
106
|
+
}));
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
* jQuery File Upload Plugin 5.
|
2
|
+
* jQuery File Upload Plugin 5.42.0
|
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
|
-
/*
|
13
|
-
/*global define, window, document,
|
12
|
+
/* jshint nomen:false */
|
13
|
+
/* global define, window, document, location, Blob, FormData */
|
14
14
|
|
15
15
|
(function (factory) {
|
16
16
|
'use strict';
|
@@ -27,26 +27,48 @@
|
|
27
27
|
}(function ($) {
|
28
28
|
'use strict';
|
29
29
|
|
30
|
+
// Detect file input support, based on
|
31
|
+
// http://viljamis.com/blog/2012/file-upload-support-on-mobile/
|
32
|
+
$.support.fileInput = !(new RegExp(
|
33
|
+
// Handle devices which give false positives for the feature detection:
|
34
|
+
'(Android (1\\.[0156]|2\\.[01]))' +
|
35
|
+
'|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' +
|
36
|
+
'|(w(eb)?OSBrowser)|(webOS)' +
|
37
|
+
'|(Kindle/(1\\.0|2\\.[05]|3\\.0))'
|
38
|
+
).test(window.navigator.userAgent) ||
|
39
|
+
// Feature detection for all other devices:
|
40
|
+
$('<input type="file">').prop('disabled'));
|
41
|
+
|
30
42
|
// The FileReader API is not actually used, but works as feature detection,
|
31
|
-
// as
|
32
|
-
// but not non-multipart XHR file uploads
|
33
|
-
|
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);
|
34
48
|
$.support.xhrFormDataFileUpload = !!window.FormData;
|
35
49
|
|
36
|
-
//
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
50
|
+
// Detect support for Blob slicing (required for chunked uploads):
|
51
|
+
$.support.blobSlice = window.Blob && (Blob.prototype.slice ||
|
52
|
+
Blob.prototype.webkitSlice || Blob.prototype.mozSlice);
|
53
|
+
|
54
|
+
// Helper function to create drag handlers for dragover/dragenter/dragleave:
|
55
|
+
function getDragHandler(type) {
|
56
|
+
var isDragOver = type === 'dragover';
|
57
|
+
return function (e) {
|
58
|
+
e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
|
59
|
+
var dataTransfer = e.dataTransfer;
|
60
|
+
if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1 &&
|
61
|
+
this._trigger(
|
62
|
+
type,
|
63
|
+
$.Event(type, {delegatedEvent: e})
|
64
|
+
) !== false) {
|
65
|
+
e.preventDefault();
|
66
|
+
if (isDragOver) {
|
67
|
+
dataTransfer.dropEffect = 'copy';
|
68
|
+
}
|
46
69
|
}
|
47
|
-
|
48
|
-
|
49
|
-
};
|
70
|
+
};
|
71
|
+
}
|
50
72
|
|
51
73
|
// The fileupload widget listens for change events on file input fields defined
|
52
74
|
// via fileInput setting and paste or drop events of the given dropZone.
|
@@ -62,9 +84,9 @@
|
|
62
84
|
// The drop target element(s), by the default the complete document.
|
63
85
|
// Set to null to disable drag & drop support:
|
64
86
|
dropZone: $(document),
|
65
|
-
// The paste target element(s), by the default
|
66
|
-
// Set to
|
67
|
-
pasteZone:
|
87
|
+
// The paste target element(s), by the default undefined.
|
88
|
+
// Set to a DOM node or jQuery object to enable file pasting:
|
89
|
+
pasteZone: undefined,
|
68
90
|
// The file input field(s), that are listened to for change events.
|
69
91
|
// If undefined, it is set to the file input fields inside
|
70
92
|
// of the widget element on plugin initialization.
|
@@ -87,6 +109,14 @@
|
|
87
109
|
// To limit the number of files uploaded with one XHR request,
|
88
110
|
// set the following option to an integer greater than 0:
|
89
111
|
limitMultiFileUploads: undefined,
|
112
|
+
// The following option limits the number of files uploaded with one
|
113
|
+
// XHR request to keep the request size under or equal to the defined
|
114
|
+
// limit in bytes:
|
115
|
+
limitMultiFileUploadSize: undefined,
|
116
|
+
// Multipart file uploads add a number of bytes to each uploaded file,
|
117
|
+
// therefore the following option adds an overhead for each file used
|
118
|
+
// in the limitMultiFileUploadSize configuration:
|
119
|
+
limitMultiFileUploadSizeOverhead: 512,
|
90
120
|
// Set the following option to true to issue all file upload requests
|
91
121
|
// in a sequential order:
|
92
122
|
sequentialUploads: false,
|
@@ -127,6 +157,25 @@
|
|
127
157
|
progressInterval: 100,
|
128
158
|
// Interval in milliseconds to calculate progress bitrate:
|
129
159
|
bitrateInterval: 500,
|
160
|
+
// By default, uploads are started automatically when adding files:
|
161
|
+
autoUpload: true,
|
162
|
+
|
163
|
+
// Error and info messages:
|
164
|
+
messages: {
|
165
|
+
uploadedBytes: 'Uploaded bytes exceed file size'
|
166
|
+
},
|
167
|
+
|
168
|
+
// Translation function, gets the message key to be translated
|
169
|
+
// and an object with context specific data as arguments:
|
170
|
+
i18n: function (message, context) {
|
171
|
+
message = this.messages[message] || message.toString();
|
172
|
+
if (context) {
|
173
|
+
$.each(context, function (key, value) {
|
174
|
+
message = message.replace('{' + key + '}', value);
|
175
|
+
});
|
176
|
+
}
|
177
|
+
return message;
|
178
|
+
},
|
130
179
|
|
131
180
|
// Additional form data to be sent along with the file uploads can be set
|
132
181
|
// using this option, which accepts an array of objects with name and
|
@@ -140,18 +189,29 @@
|
|
140
189
|
// The add callback is invoked as soon as files are added to the fileupload
|
141
190
|
// widget (via file input selection, drag & drop, paste or add API call).
|
142
191
|
// If the singleFileUploads option is enabled, this callback will be
|
143
|
-
// called once for each file in the selection for XHR file
|
192
|
+
// called once for each file in the selection for XHR file uploads, else
|
144
193
|
// once for each file selection.
|
194
|
+
//
|
145
195
|
// The upload starts when the submit method is invoked on the data parameter.
|
146
196
|
// The data object contains a files property holding the added files
|
147
|
-
// and allows to override plugin options as well as define ajax settings.
|
197
|
+
// and allows you to override plugin options as well as define ajax settings.
|
198
|
+
//
|
148
199
|
// Listeners for this callback can also be bound the following way:
|
149
200
|
// .bind('fileuploadadd', func);
|
201
|
+
//
|
150
202
|
// data.submit() returns a Promise object and allows to attach additional
|
151
203
|
// handlers using jQuery's Deferred callbacks:
|
152
204
|
// data.submit().done(func).fail(func).always(func);
|
153
205
|
add: function (e, data) {
|
154
|
-
|
206
|
+
if (e.isDefaultPrevented()) {
|
207
|
+
return false;
|
208
|
+
}
|
209
|
+
if (data.autoUpload || (data.autoUpload !== false &&
|
210
|
+
$(this).fileupload('option', 'autoUpload'))) {
|
211
|
+
data.process().done(function () {
|
212
|
+
data.submit();
|
213
|
+
});
|
214
|
+
}
|
155
215
|
},
|
156
216
|
|
157
217
|
// Other callbacks:
|
@@ -214,8 +274,9 @@
|
|
214
274
|
cache: false
|
215
275
|
},
|
216
276
|
|
217
|
-
// A list of options that require
|
218
|
-
|
277
|
+
// A list of options that require reinitializing event listeners and/or
|
278
|
+
// special initialization code:
|
279
|
+
_specialOptions: [
|
219
280
|
'fileInput',
|
220
281
|
'dropZone',
|
221
282
|
'pasteZone',
|
@@ -223,8 +284,13 @@
|
|
223
284
|
'forceIframeTransport'
|
224
285
|
],
|
225
286
|
|
287
|
+
_blobSlice: $.support.blobSlice && function () {
|
288
|
+
var slice = this.slice || this.webkitSlice || this.mozSlice;
|
289
|
+
return slice.apply(this, arguments);
|
290
|
+
},
|
291
|
+
|
226
292
|
_BitrateTimer: function () {
|
227
|
-
this.timestamp =
|
293
|
+
this.timestamp = ((Date.now) ? Date.now() : (new Date()).getTime());
|
228
294
|
this.loaded = 0;
|
229
295
|
this.bitrate = 0;
|
230
296
|
this.getBitrate = function (now, loaded, interval) {
|
@@ -246,13 +312,13 @@
|
|
246
312
|
|
247
313
|
_getFormData: function (options) {
|
248
314
|
var formData;
|
249
|
-
if (
|
315
|
+
if ($.type(options.formData) === 'function') {
|
250
316
|
return options.formData(options.form);
|
251
317
|
}
|
252
318
|
if ($.isArray(options.formData)) {
|
253
319
|
return options.formData;
|
254
320
|
}
|
255
|
-
if (options.formData) {
|
321
|
+
if ($.type(options.formData) === 'object') {
|
256
322
|
formData = [];
|
257
323
|
$.each(options.formData, function (name, value) {
|
258
324
|
formData.push({name: name, value: value});
|
@@ -270,10 +336,35 @@
|
|
270
336
|
return total;
|
271
337
|
},
|
272
338
|
|
339
|
+
_initProgressObject: function (obj) {
|
340
|
+
var progress = {
|
341
|
+
loaded: 0,
|
342
|
+
total: 0,
|
343
|
+
bitrate: 0
|
344
|
+
};
|
345
|
+
if (obj._progress) {
|
346
|
+
$.extend(obj._progress, progress);
|
347
|
+
} else {
|
348
|
+
obj._progress = progress;
|
349
|
+
}
|
350
|
+
},
|
351
|
+
|
352
|
+
_initResponseObject: function (obj) {
|
353
|
+
var prop;
|
354
|
+
if (obj._response) {
|
355
|
+
for (prop in obj._response) {
|
356
|
+
if (obj._response.hasOwnProperty(prop)) {
|
357
|
+
delete obj._response[prop];
|
358
|
+
}
|
359
|
+
}
|
360
|
+
} else {
|
361
|
+
obj._response = {};
|
362
|
+
}
|
363
|
+
},
|
364
|
+
|
273
365
|
_onProgress: function (e, data) {
|
274
366
|
if (e.lengthComputable) {
|
275
|
-
var now =
|
276
|
-
total,
|
367
|
+
var now = ((Date.now) ? Date.now() : (new Date()).getTime()),
|
277
368
|
loaded;
|
278
369
|
if (data._time && data.progressInterval &&
|
279
370
|
(now - data._time < data.progressInterval) &&
|
@@ -281,16 +372,19 @@
|
|
281
372
|
return;
|
282
373
|
}
|
283
374
|
data._time = now;
|
284
|
-
|
285
|
-
|
286
|
-
e.loaded / e.total * (data.chunkSize || total),
|
287
|
-
10
|
375
|
+
loaded = Math.floor(
|
376
|
+
e.loaded / e.total * (data.chunkSize || data._progress.total)
|
288
377
|
) + (data.uploadedBytes || 0);
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
378
|
+
// Add the difference from the previously loaded state
|
379
|
+
// to the global loaded counter:
|
380
|
+
this._progress.loaded += (loaded - data._progress.loaded);
|
381
|
+
this._progress.bitrate = this._bitrateTimer.getBitrate(
|
382
|
+
now,
|
383
|
+
this._progress.loaded,
|
384
|
+
data.bitrateInterval
|
385
|
+
);
|
386
|
+
data._progress.loaded = data.loaded = loaded;
|
387
|
+
data._progress.bitrate = data.bitrate = data._bitrateTimer.getBitrate(
|
294
388
|
now,
|
295
389
|
loaded,
|
296
390
|
data.bitrateInterval
|
@@ -298,19 +392,18 @@
|
|
298
392
|
// Trigger a custom progress event with a total data property set
|
299
393
|
// to the file size(s) of the current upload and a loaded data
|
300
394
|
// property calculated accordingly:
|
301
|
-
this._trigger(
|
395
|
+
this._trigger(
|
396
|
+
'progress',
|
397
|
+
$.Event('progress', {delegatedEvent: e}),
|
398
|
+
data
|
399
|
+
);
|
302
400
|
// Trigger a global progress event for all current file uploads,
|
303
401
|
// including ajax calls queued for sequential file uploads:
|
304
|
-
this._trigger(
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
now,
|
310
|
-
this._loaded,
|
311
|
-
data.bitrateInterval
|
312
|
-
)
|
313
|
-
});
|
402
|
+
this._trigger(
|
403
|
+
'progressall',
|
404
|
+
$.Event('progressall', {delegatedEvent: e}),
|
405
|
+
this._progress
|
406
|
+
);
|
314
407
|
}
|
315
408
|
},
|
316
409
|
|
@@ -334,20 +427,29 @@
|
|
334
427
|
}
|
335
428
|
},
|
336
429
|
|
430
|
+
_isInstanceOf: function (type, obj) {
|
431
|
+
// Cross-frame instanceof check
|
432
|
+
return Object.prototype.toString.call(obj) === '[object ' + type + ']';
|
433
|
+
},
|
434
|
+
|
337
435
|
_initXHRData: function (options) {
|
338
|
-
var
|
436
|
+
var that = this,
|
437
|
+
formData,
|
339
438
|
file = options.files[0],
|
340
439
|
// Ignore non-multipart setting if not supported:
|
341
440
|
multipart = options.multipart || !$.support.xhrFileUpload,
|
342
|
-
paramName = options.paramName
|
343
|
-
|
441
|
+
paramName = $.type(options.paramName) === 'array' ?
|
442
|
+
options.paramName[0] : options.paramName;
|
443
|
+
options.headers = $.extend({}, options.headers);
|
344
444
|
if (options.contentRange) {
|
345
445
|
options.headers['Content-Range'] = options.contentRange;
|
346
446
|
}
|
347
|
-
if (!multipart) {
|
447
|
+
if (!multipart || options.blob || !this._isInstanceOf('File', file)) {
|
348
448
|
options.headers['Content-Disposition'] = 'attachment; filename="' +
|
349
449
|
encodeURI(file.name) + '"';
|
350
|
-
|
450
|
+
}
|
451
|
+
if (!multipart) {
|
452
|
+
options.contentType = file.type || 'application/octet-stream';
|
351
453
|
options.data = options.blob || file;
|
352
454
|
} else if ($.support.xhrFormDataFileUpload) {
|
353
455
|
if (options.postMessage) {
|
@@ -364,13 +466,14 @@
|
|
364
466
|
} else {
|
365
467
|
$.each(options.files, function (index, file) {
|
366
468
|
formData.push({
|
367
|
-
name: options.paramName
|
469
|
+
name: ($.type(options.paramName) === 'array' &&
|
470
|
+
options.paramName[index]) || paramName,
|
368
471
|
value: file
|
369
472
|
});
|
370
473
|
});
|
371
474
|
}
|
372
475
|
} else {
|
373
|
-
if (options.formData
|
476
|
+
if (that._isInstanceOf('FormData', options.formData)) {
|
374
477
|
formData = options.formData;
|
375
478
|
} else {
|
376
479
|
formData = new FormData();
|
@@ -379,21 +482,18 @@
|
|
379
482
|
});
|
380
483
|
}
|
381
484
|
if (options.blob) {
|
382
|
-
options.headers['Content-Disposition'] = 'attachment; filename="' +
|
383
|
-
encodeURI(file.name) + '"';
|
384
485
|
formData.append(paramName, options.blob, file.name);
|
385
486
|
} else {
|
386
487
|
$.each(options.files, function (index, file) {
|
387
|
-
// Files are also Blob instances, but some browsers
|
388
|
-
// (Firefox 3.6) support the File API but not Blobs.
|
389
488
|
// This check allows the tests to run with
|
390
489
|
// dummy objects:
|
391
|
-
if ((
|
392
|
-
(
|
490
|
+
if (that._isInstanceOf('File', file) ||
|
491
|
+
that._isInstanceOf('Blob', file)) {
|
393
492
|
formData.append(
|
394
|
-
options.paramName
|
493
|
+
($.type(options.paramName) === 'array' &&
|
494
|
+
options.paramName[index]) || paramName,
|
395
495
|
file,
|
396
|
-
file.name
|
496
|
+
file.uploadName || file.name
|
397
497
|
);
|
398
498
|
}
|
399
499
|
});
|
@@ -406,13 +506,13 @@
|
|
406
506
|
},
|
407
507
|
|
408
508
|
_initIframeSettings: function (options) {
|
509
|
+
var targetHost = $('<a></a>').prop('href', options.url).prop('host');
|
409
510
|
// Setting the dataType to iframe enables the iframe transport:
|
410
511
|
options.dataType = 'iframe ' + (options.dataType || '');
|
411
512
|
// The iframe transport accepts a serialized array as form data:
|
412
513
|
options.formData = this._getFormData(options);
|
413
514
|
// Add redirect url to form data on cross-domain uploads:
|
414
|
-
if (options.redirect &&
|
415
|
-
.prop('host') !== location.host) {
|
515
|
+
if (options.redirect && targetHost && targetHost !== location.host) {
|
416
516
|
options.formData.push({
|
417
517
|
name: options.redirectParamName || 'redirect',
|
418
518
|
value: options.redirect
|
@@ -434,7 +534,7 @@
|
|
434
534
|
options.dataType = 'postmessage ' + (options.dataType || '');
|
435
535
|
}
|
436
536
|
} else {
|
437
|
-
this._initIframeSettings(options
|
537
|
+
this._initIframeSettings(options);
|
438
538
|
}
|
439
539
|
},
|
440
540
|
|
@@ -477,8 +577,10 @@
|
|
477
577
|
options.url = options.form.prop('action') || location.href;
|
478
578
|
}
|
479
579
|
// The HTTP request method must be "POST" or "PUT":
|
480
|
-
options.type = (options.type ||
|
481
|
-
.
|
580
|
+
options.type = (options.type ||
|
581
|
+
($.type(options.form.prop('method')) === 'string' &&
|
582
|
+
options.form.prop('method')) || ''
|
583
|
+
).toUpperCase();
|
482
584
|
if (options.type !== 'POST' && options.type !== 'PUT' &&
|
483
585
|
options.type !== 'PATCH') {
|
484
586
|
options.type = 'POST';
|
@@ -495,6 +597,21 @@
|
|
495
597
|
return options;
|
496
598
|
},
|
497
599
|
|
600
|
+
// jQuery 1.6 doesn't provide .state(),
|
601
|
+
// while jQuery 1.8+ removed .isRejected() and .isResolved():
|
602
|
+
_getDeferredState: function (deferred) {
|
603
|
+
if (deferred.state) {
|
604
|
+
return deferred.state();
|
605
|
+
}
|
606
|
+
if (deferred.isResolved()) {
|
607
|
+
return 'resolved';
|
608
|
+
}
|
609
|
+
if (deferred.isRejected()) {
|
610
|
+
return 'rejected';
|
611
|
+
}
|
612
|
+
return 'pending';
|
613
|
+
},
|
614
|
+
|
498
615
|
// Maps jqXHR callbacks to the equivalent
|
499
616
|
// methods of the given Promise object:
|
500
617
|
_enhancePromise: function (promise) {
|
@@ -519,6 +636,66 @@
|
|
519
636
|
return this._enhancePromise(promise);
|
520
637
|
},
|
521
638
|
|
639
|
+
// Adds convenience methods to the data callback argument:
|
640
|
+
_addConvenienceMethods: function (e, data) {
|
641
|
+
var that = this,
|
642
|
+
getPromise = function (args) {
|
643
|
+
return $.Deferred().resolveWith(that, args).promise();
|
644
|
+
};
|
645
|
+
data.process = function (resolveFunc, rejectFunc) {
|
646
|
+
if (resolveFunc || rejectFunc) {
|
647
|
+
data._processQueue = this._processQueue =
|
648
|
+
(this._processQueue || getPromise([this])).pipe(
|
649
|
+
function () {
|
650
|
+
if (data.errorThrown) {
|
651
|
+
return $.Deferred()
|
652
|
+
.rejectWith(that, [data]).promise();
|
653
|
+
}
|
654
|
+
return getPromise(arguments);
|
655
|
+
}
|
656
|
+
).pipe(resolveFunc, rejectFunc);
|
657
|
+
}
|
658
|
+
return this._processQueue || getPromise([this]);
|
659
|
+
};
|
660
|
+
data.submit = function () {
|
661
|
+
if (this.state() !== 'pending') {
|
662
|
+
data.jqXHR = this.jqXHR =
|
663
|
+
(that._trigger(
|
664
|
+
'submit',
|
665
|
+
$.Event('submit', {delegatedEvent: e}),
|
666
|
+
this
|
667
|
+
) !== false) && that._onSend(e, this);
|
668
|
+
}
|
669
|
+
return this.jqXHR || that._getXHRPromise();
|
670
|
+
};
|
671
|
+
data.abort = function () {
|
672
|
+
if (this.jqXHR) {
|
673
|
+
return this.jqXHR.abort();
|
674
|
+
}
|
675
|
+
this.errorThrown = 'abort';
|
676
|
+
that._trigger('fail', null, this);
|
677
|
+
return that._getXHRPromise(false);
|
678
|
+
};
|
679
|
+
data.state = function () {
|
680
|
+
if (this.jqXHR) {
|
681
|
+
return that._getDeferredState(this.jqXHR);
|
682
|
+
}
|
683
|
+
if (this._processQueue) {
|
684
|
+
return that._getDeferredState(this._processQueue);
|
685
|
+
}
|
686
|
+
};
|
687
|
+
data.processing = function () {
|
688
|
+
return !this.jqXHR && this._processQueue && that
|
689
|
+
._getDeferredState(this._processQueue) === 'pending';
|
690
|
+
};
|
691
|
+
data.progress = function () {
|
692
|
+
return this._progress;
|
693
|
+
};
|
694
|
+
data.response = function () {
|
695
|
+
return this._response;
|
696
|
+
};
|
697
|
+
},
|
698
|
+
|
522
699
|
// Parses the Range header from the server response
|
523
700
|
// and returns the uploaded bytes:
|
524
701
|
_getUploadedBytes: function (jqXHR) {
|
@@ -535,12 +712,13 @@
|
|
535
712
|
// should be uploaded in chunks, but does not invoke any
|
536
713
|
// upload requests:
|
537
714
|
_chunkedUpload: function (options, testOnly) {
|
715
|
+
options.uploadedBytes = options.uploadedBytes || 0;
|
538
716
|
var that = this,
|
539
717
|
file = options.files[0],
|
540
718
|
fs = file.size,
|
541
|
-
ub = options.uploadedBytes
|
719
|
+
ub = options.uploadedBytes,
|
542
720
|
mcs = options.maxChunkSize || fs,
|
543
|
-
slice =
|
721
|
+
slice = this._blobSlice,
|
544
722
|
dfd = $.Deferred(),
|
545
723
|
promise = dfd.promise(),
|
546
724
|
jqXHR,
|
@@ -553,7 +731,7 @@
|
|
553
731
|
return true;
|
554
732
|
}
|
555
733
|
if (ub >= fs) {
|
556
|
-
file.error = '
|
734
|
+
file.error = options.i18n('uploadedBytes');
|
557
735
|
return this._getXHRPromise(
|
558
736
|
false,
|
559
737
|
options.context,
|
@@ -561,9 +739,10 @@
|
|
561
739
|
);
|
562
740
|
}
|
563
741
|
// The chunk upload method:
|
564
|
-
upload = function (
|
742
|
+
upload = function () {
|
565
743
|
// Clone the options object for each chunk upload:
|
566
|
-
var o = $.extend({}, options)
|
744
|
+
var o = $.extend({}, options),
|
745
|
+
currentLoaded = o._progress.loaded;
|
567
746
|
o.blob = slice.call(
|
568
747
|
file,
|
569
748
|
ub,
|
@@ -585,10 +764,10 @@
|
|
585
764
|
.done(function (result, textStatus, jqXHR) {
|
586
765
|
ub = that._getUploadedBytes(jqXHR) ||
|
587
766
|
(ub + o.chunkSize);
|
588
|
-
// Create a progress event if
|
589
|
-
//
|
590
|
-
//
|
591
|
-
if (
|
767
|
+
// Create a progress event if no final progress event
|
768
|
+
// with loaded equaling total has been triggered
|
769
|
+
// for this chunk:
|
770
|
+
if (currentLoaded + o.chunkSize - o._progress.loaded) {
|
592
771
|
that._onProgress($.Event('progress', {
|
593
772
|
lengthComputable: true,
|
594
773
|
loaded: ub - o.uploadedBytes,
|
@@ -640,61 +819,66 @@
|
|
640
819
|
this._trigger('start');
|
641
820
|
// Set timer for global bitrate progress calculation:
|
642
821
|
this._bitrateTimer = new this._BitrateTimer();
|
822
|
+
// Reset the global progress values:
|
823
|
+
this._progress.loaded = this._progress.total = 0;
|
824
|
+
this._progress.bitrate = 0;
|
643
825
|
}
|
826
|
+
// Make sure the container objects for the .response() and
|
827
|
+
// .progress() methods on the data object are available
|
828
|
+
// and reset to their initial state:
|
829
|
+
this._initResponseObject(data);
|
830
|
+
this._initProgressObject(data);
|
831
|
+
data._progress.loaded = data.loaded = data.uploadedBytes || 0;
|
832
|
+
data._progress.total = data.total = this._getTotal(data.files) || 1;
|
833
|
+
data._progress.bitrate = data.bitrate = 0;
|
644
834
|
this._active += 1;
|
645
835
|
// Initialize the global progress values:
|
646
|
-
this.
|
647
|
-
this.
|
836
|
+
this._progress.loaded += data.loaded;
|
837
|
+
this._progress.total += data.total;
|
648
838
|
},
|
649
839
|
|
650
840
|
_onDone: function (result, textStatus, jqXHR, options) {
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
// Create a progress event
|
655
|
-
//
|
656
|
-
// loaded equaling total for XHR uploads:
|
841
|
+
var total = options._progress.total,
|
842
|
+
response = options._response;
|
843
|
+
if (options._progress.loaded < total) {
|
844
|
+
// Create a progress event if no final progress event
|
845
|
+
// with loaded equaling total has been triggered:
|
657
846
|
this._onProgress($.Event('progress', {
|
658
847
|
lengthComputable: true,
|
659
848
|
loaded: total,
|
660
849
|
total: total
|
661
850
|
}), options);
|
662
851
|
}
|
663
|
-
options.result = result;
|
664
|
-
options.textStatus = textStatus;
|
665
|
-
options.jqXHR = jqXHR;
|
852
|
+
response.result = options.result = result;
|
853
|
+
response.textStatus = options.textStatus = textStatus;
|
854
|
+
response.jqXHR = options.jqXHR = jqXHR;
|
666
855
|
this._trigger('done', null, options);
|
667
856
|
},
|
668
857
|
|
669
858
|
_onFail: function (jqXHR, textStatus, errorThrown, options) {
|
670
|
-
|
671
|
-
options.textStatus = textStatus;
|
672
|
-
options.errorThrown = errorThrown;
|
673
|
-
this._trigger('fail', null, options);
|
859
|
+
var response = options._response;
|
674
860
|
if (options.recalculateProgress) {
|
675
861
|
// Remove the failed (error or abort) file upload from
|
676
862
|
// the global progress calculation:
|
677
|
-
this.
|
678
|
-
this.
|
863
|
+
this._progress.loaded -= options._progress.loaded;
|
864
|
+
this._progress.total -= options._progress.total;
|
679
865
|
}
|
866
|
+
response.jqXHR = options.jqXHR = jqXHR;
|
867
|
+
response.textStatus = options.textStatus = textStatus;
|
868
|
+
response.errorThrown = options.errorThrown = errorThrown;
|
869
|
+
this._trigger('fail', null, options);
|
680
870
|
},
|
681
871
|
|
682
872
|
_onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) {
|
683
873
|
// jqXHRorResult, textStatus and jqXHRorError are added to the
|
684
874
|
// options object via done and fail callbacks
|
685
|
-
this._active -= 1;
|
686
875
|
this._trigger('always', null, options);
|
687
|
-
if (this._active === 0) {
|
688
|
-
// The stop callback is triggered when all uploads have
|
689
|
-
// been completed, equivalent to the global ajaxStop event:
|
690
|
-
this._trigger('stop');
|
691
|
-
// Reset the global progress values:
|
692
|
-
this._loaded = this._total = 0;
|
693
|
-
this._bitrateTimer = null;
|
694
|
-
}
|
695
876
|
},
|
696
877
|
|
697
878
|
_onSend: function (e, data) {
|
879
|
+
if (!data.submit) {
|
880
|
+
this._addConvenienceMethods(e, data);
|
881
|
+
}
|
698
882
|
var that = this,
|
699
883
|
jqXHR,
|
700
884
|
aborted,
|
@@ -706,7 +890,11 @@
|
|
706
890
|
// Set timer for bitrate progress calculation:
|
707
891
|
options._bitrateTimer = new that._BitrateTimer();
|
708
892
|
jqXHR = jqXHR || (
|
709
|
-
((aborted || that._trigger(
|
893
|
+
((aborted || that._trigger(
|
894
|
+
'send',
|
895
|
+
$.Event('send', {delegatedEvent: e}),
|
896
|
+
options
|
897
|
+
) === false) &&
|
710
898
|
that._getXHRPromise(false, options.context, aborted)) ||
|
711
899
|
that._chunkedUpload(options) || $.ajax(options)
|
712
900
|
).done(function (result, textStatus, jqXHR) {
|
@@ -714,32 +902,32 @@
|
|
714
902
|
}).fail(function (jqXHR, textStatus, errorThrown) {
|
715
903
|
that._onFail(jqXHR, textStatus, errorThrown, options);
|
716
904
|
}).always(function (jqXHRorResult, textStatus, jqXHRorError) {
|
717
|
-
that._sending -= 1;
|
718
905
|
that._onAlways(
|
719
906
|
jqXHRorResult,
|
720
907
|
textStatus,
|
721
908
|
jqXHRorError,
|
722
909
|
options
|
723
910
|
);
|
911
|
+
that._sending -= 1;
|
912
|
+
that._active -= 1;
|
724
913
|
if (options.limitConcurrentUploads &&
|
725
914
|
options.limitConcurrentUploads > that._sending) {
|
726
915
|
// Start the next queued upload,
|
727
916
|
// that has not been aborted:
|
728
|
-
var nextSlot = that._slots.shift()
|
729
|
-
isPending;
|
917
|
+
var nextSlot = that._slots.shift();
|
730
918
|
while (nextSlot) {
|
731
|
-
|
732
|
-
// while jQuery 1.8+ removed .isRejected():
|
733
|
-
isPending = nextSlot.state ?
|
734
|
-
nextSlot.state() === 'pending' :
|
735
|
-
!nextSlot.isRejected();
|
736
|
-
if (isPending) {
|
919
|
+
if (that._getDeferredState(nextSlot) === 'pending') {
|
737
920
|
nextSlot.resolve();
|
738
921
|
break;
|
739
922
|
}
|
740
923
|
nextSlot = that._slots.shift();
|
741
924
|
}
|
742
925
|
}
|
926
|
+
if (that._active === 0) {
|
927
|
+
// The stop callback is triggered when all uploads have
|
928
|
+
// been completed, equivalent to the global ajaxStop event:
|
929
|
+
that._trigger('stop');
|
930
|
+
}
|
743
931
|
});
|
744
932
|
return jqXHR;
|
745
933
|
};
|
@@ -752,7 +940,8 @@
|
|
752
940
|
this._slots.push(slot);
|
753
941
|
pipe = slot.pipe(send);
|
754
942
|
} else {
|
755
|
-
|
943
|
+
this._sequence = this._sequence.pipe(send, send);
|
944
|
+
pipe = this._sequence;
|
756
945
|
}
|
757
946
|
// Return the piped Promise object, enhanced with an abort method,
|
758
947
|
// which is delegated to the jqXHR object of the current upload,
|
@@ -776,49 +965,80 @@
|
|
776
965
|
var that = this,
|
777
966
|
result = true,
|
778
967
|
options = $.extend({}, this.options, data),
|
968
|
+
files = data.files,
|
969
|
+
filesLength = files.length,
|
779
970
|
limit = options.limitMultiFileUploads,
|
971
|
+
limitSize = options.limitMultiFileUploadSize,
|
972
|
+
overhead = options.limitMultiFileUploadSizeOverhead,
|
973
|
+
batchSize = 0,
|
780
974
|
paramName = this._getParamName(options),
|
781
975
|
paramNameSet,
|
782
976
|
paramNameSlice,
|
783
977
|
fileSet,
|
784
|
-
i
|
785
|
-
|
978
|
+
i,
|
979
|
+
j = 0;
|
980
|
+
if (limitSize && (!filesLength || files[0].size === undefined)) {
|
981
|
+
limitSize = undefined;
|
982
|
+
}
|
983
|
+
if (!(options.singleFileUploads || limit || limitSize) ||
|
786
984
|
!this._isXHRUpload(options)) {
|
787
|
-
fileSet = [
|
985
|
+
fileSet = [files];
|
788
986
|
paramNameSet = [paramName];
|
789
|
-
} else if (!options.singleFileUploads && limit) {
|
987
|
+
} else if (!(options.singleFileUploads || limitSize) && limit) {
|
790
988
|
fileSet = [];
|
791
989
|
paramNameSet = [];
|
792
|
-
for (i = 0; i <
|
793
|
-
fileSet.push(
|
990
|
+
for (i = 0; i < filesLength; i += limit) {
|
991
|
+
fileSet.push(files.slice(i, i + limit));
|
794
992
|
paramNameSlice = paramName.slice(i, i + limit);
|
795
993
|
if (!paramNameSlice.length) {
|
796
994
|
paramNameSlice = paramName;
|
797
995
|
}
|
798
996
|
paramNameSet.push(paramNameSlice);
|
799
997
|
}
|
998
|
+
} else if (!options.singleFileUploads && limitSize) {
|
999
|
+
fileSet = [];
|
1000
|
+
paramNameSet = [];
|
1001
|
+
for (i = 0; i < filesLength; i = i + 1) {
|
1002
|
+
batchSize += files[i].size + overhead;
|
1003
|
+
if (i + 1 === filesLength ||
|
1004
|
+
((batchSize + files[i + 1].size + overhead) > limitSize) ||
|
1005
|
+
(limit && i + 1 - j >= limit)) {
|
1006
|
+
fileSet.push(files.slice(j, i + 1));
|
1007
|
+
paramNameSlice = paramName.slice(j, i + 1);
|
1008
|
+
if (!paramNameSlice.length) {
|
1009
|
+
paramNameSlice = paramName;
|
1010
|
+
}
|
1011
|
+
paramNameSet.push(paramNameSlice);
|
1012
|
+
j = i + 1;
|
1013
|
+
batchSize = 0;
|
1014
|
+
}
|
1015
|
+
}
|
800
1016
|
} else {
|
801
1017
|
paramNameSet = paramName;
|
802
1018
|
}
|
803
|
-
data.originalFiles =
|
804
|
-
$.each(fileSet ||
|
1019
|
+
data.originalFiles = files;
|
1020
|
+
$.each(fileSet || files, function (index, element) {
|
805
1021
|
var newData = $.extend({}, data);
|
806
1022
|
newData.files = fileSet ? element : [element];
|
807
1023
|
newData.paramName = paramNameSet[index];
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
1024
|
+
that._initResponseObject(newData);
|
1025
|
+
that._initProgressObject(newData);
|
1026
|
+
that._addConvenienceMethods(e, newData);
|
1027
|
+
result = that._trigger(
|
1028
|
+
'add',
|
1029
|
+
$.Event('add', {delegatedEvent: e}),
|
1030
|
+
newData
|
1031
|
+
);
|
815
1032
|
return result;
|
816
1033
|
});
|
817
1034
|
return result;
|
818
1035
|
},
|
819
1036
|
|
820
|
-
_replaceFileInput: function (
|
821
|
-
var
|
1037
|
+
_replaceFileInput: function (data) {
|
1038
|
+
var input = data.fileInput,
|
1039
|
+
inputClone = input.clone(true);
|
1040
|
+
// Add a reference for the new cloned file input to the data argument:
|
1041
|
+
data.fileInputClone = inputClone;
|
822
1042
|
$('<form></form>').append(inputClone)[0].reset();
|
823
1043
|
// Detaching allows to insert the fileInput on another form
|
824
1044
|
// without loosing the file input value:
|
@@ -854,7 +1074,25 @@
|
|
854
1074
|
// to be returned together in one set:
|
855
1075
|
dfd.resolve([e]);
|
856
1076
|
},
|
857
|
-
|
1077
|
+
successHandler = function (entries) {
|
1078
|
+
that._handleFileTreeEntries(
|
1079
|
+
entries,
|
1080
|
+
path + entry.name + '/'
|
1081
|
+
).done(function (files) {
|
1082
|
+
dfd.resolve(files);
|
1083
|
+
}).fail(errorHandler);
|
1084
|
+
},
|
1085
|
+
readEntries = function () {
|
1086
|
+
dirReader.readEntries(function (results) {
|
1087
|
+
if (!results.length) {
|
1088
|
+
successHandler(entries);
|
1089
|
+
} else {
|
1090
|
+
entries = entries.concat(results);
|
1091
|
+
readEntries();
|
1092
|
+
}
|
1093
|
+
}, errorHandler);
|
1094
|
+
},
|
1095
|
+
dirReader, entries = [];
|
858
1096
|
path = path || '';
|
859
1097
|
if (entry.isFile) {
|
860
1098
|
if (entry._file) {
|
@@ -869,14 +1107,7 @@
|
|
869
1107
|
}
|
870
1108
|
} else if (entry.isDirectory) {
|
871
1109
|
dirReader = entry.createReader();
|
872
|
-
|
873
|
-
that._handleFileTreeEntries(
|
874
|
-
entries,
|
875
|
-
path + entry.name + '/'
|
876
|
-
).done(function (files) {
|
877
|
-
dfd.resolve(files);
|
878
|
-
}).fail(errorHandler);
|
879
|
-
}, errorHandler);
|
1110
|
+
readEntries();
|
880
1111
|
} else {
|
881
1112
|
// Return an empy list for file system items
|
882
1113
|
// other than files or directories:
|
@@ -978,84 +1209,99 @@
|
|
978
1209
|
this._getFileInputFiles(data.fileInput).always(function (files) {
|
979
1210
|
data.files = files;
|
980
1211
|
if (that.options.replaceFileInput) {
|
981
|
-
that._replaceFileInput(data
|
1212
|
+
that._replaceFileInput(data);
|
982
1213
|
}
|
983
|
-
if (that._trigger(
|
1214
|
+
if (that._trigger(
|
1215
|
+
'change',
|
1216
|
+
$.Event('change', {delegatedEvent: e}),
|
1217
|
+
data
|
1218
|
+
) !== false) {
|
984
1219
|
that._onAdd(e, data);
|
985
1220
|
}
|
986
1221
|
});
|
987
1222
|
},
|
988
1223
|
|
989
1224
|
_onPaste: function (e) {
|
990
|
-
var
|
991
|
-
|
1225
|
+
var items = e.originalEvent && e.originalEvent.clipboardData &&
|
1226
|
+
e.originalEvent.clipboardData.items,
|
992
1227
|
data = {files: []};
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
1228
|
+
if (items && items.length) {
|
1229
|
+
$.each(items, function (index, item) {
|
1230
|
+
var file = item.getAsFile && item.getAsFile();
|
1231
|
+
if (file) {
|
1232
|
+
data.files.push(file);
|
1233
|
+
}
|
1234
|
+
});
|
1235
|
+
if (this._trigger(
|
1236
|
+
'paste',
|
1237
|
+
$.Event('paste', {delegatedEvent: e}),
|
1238
|
+
data
|
1239
|
+
) !== false) {
|
1240
|
+
this._onAdd(e, data);
|
997
1241
|
}
|
998
|
-
});
|
999
|
-
if (this._trigger('paste', e, data) === false ||
|
1000
|
-
this._onAdd(e, data) === false) {
|
1001
|
-
return false;
|
1002
1242
|
}
|
1003
1243
|
},
|
1004
1244
|
|
1005
1245
|
_onDrop: function (e) {
|
1246
|
+
e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
|
1006
1247
|
var that = this,
|
1007
|
-
dataTransfer = e.dataTransfer
|
1248
|
+
dataTransfer = e.dataTransfer,
|
1008
1249
|
data = {};
|
1009
1250
|
if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {
|
1010
1251
|
e.preventDefault();
|
1252
|
+
this._getDroppedFiles(dataTransfer).always(function (files) {
|
1253
|
+
data.files = files;
|
1254
|
+
if (that._trigger(
|
1255
|
+
'drop',
|
1256
|
+
$.Event('drop', {delegatedEvent: e}),
|
1257
|
+
data
|
1258
|
+
) !== false) {
|
1259
|
+
that._onAdd(e, data);
|
1260
|
+
}
|
1261
|
+
});
|
1011
1262
|
}
|
1012
|
-
this._getDroppedFiles(dataTransfer).always(function (files) {
|
1013
|
-
data.files = files;
|
1014
|
-
if (that._trigger('drop', e, data) !== false) {
|
1015
|
-
that._onAdd(e, data);
|
1016
|
-
}
|
1017
|
-
});
|
1018
1263
|
},
|
1019
1264
|
|
1020
|
-
_onDragOver:
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1) {
|
1026
|
-
dataTransfer.dropEffect = 'copy';
|
1027
|
-
e.preventDefault();
|
1028
|
-
}
|
1029
|
-
},
|
1265
|
+
_onDragOver: getDragHandler('dragover'),
|
1266
|
+
|
1267
|
+
_onDragEnter: getDragHandler('dragenter'),
|
1268
|
+
|
1269
|
+
_onDragLeave: getDragHandler('dragleave'),
|
1030
1270
|
|
1031
1271
|
_initEventHandlers: function () {
|
1032
1272
|
if (this._isXHRUpload(this.options)) {
|
1033
1273
|
this._on(this.options.dropZone, {
|
1034
1274
|
dragover: this._onDragOver,
|
1035
|
-
drop: this._onDrop
|
1275
|
+
drop: this._onDrop,
|
1276
|
+
// event.preventDefault() on dragenter is required for IE10+:
|
1277
|
+
dragenter: this._onDragEnter,
|
1278
|
+
// dragleave is not required, but added for completeness:
|
1279
|
+
dragleave: this._onDragLeave
|
1036
1280
|
});
|
1037
1281
|
this._on(this.options.pasteZone, {
|
1038
1282
|
paste: this._onPaste
|
1039
1283
|
});
|
1040
1284
|
}
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1285
|
+
if ($.support.fileInput) {
|
1286
|
+
this._on(this.options.fileInput, {
|
1287
|
+
change: this._onChange
|
1288
|
+
});
|
1289
|
+
}
|
1044
1290
|
},
|
1045
1291
|
|
1046
1292
|
_destroyEventHandlers: function () {
|
1047
|
-
this._off(this.options.dropZone, 'dragover drop');
|
1293
|
+
this._off(this.options.dropZone, 'dragenter dragleave dragover drop');
|
1048
1294
|
this._off(this.options.pasteZone, 'paste');
|
1049
1295
|
this._off(this.options.fileInput, 'change');
|
1050
1296
|
},
|
1051
1297
|
|
1052
1298
|
_setOption: function (key, value) {
|
1053
|
-
var
|
1054
|
-
if (
|
1299
|
+
var reinit = $.inArray(key, this._specialOptions) !== -1;
|
1300
|
+
if (reinit) {
|
1055
1301
|
this._destroyEventHandlers();
|
1056
1302
|
}
|
1057
1303
|
this._super(key, value);
|
1058
|
-
if (
|
1304
|
+
if (reinit) {
|
1059
1305
|
this._initSpecialOptions();
|
1060
1306
|
this._initEventHandlers();
|
1061
1307
|
}
|
@@ -1077,19 +1323,61 @@
|
|
1077
1323
|
}
|
1078
1324
|
},
|
1079
1325
|
|
1080
|
-
|
1081
|
-
var
|
1326
|
+
_getRegExp: function (str) {
|
1327
|
+
var parts = str.split('/'),
|
1328
|
+
modifiers = parts.pop();
|
1329
|
+
parts.shift();
|
1330
|
+
return new RegExp(parts.join('/'), modifiers);
|
1331
|
+
},
|
1332
|
+
|
1333
|
+
_isRegExpOption: function (key, value) {
|
1334
|
+
return key !== 'url' && $.type(value) === 'string' &&
|
1335
|
+
/^\/.*\/[igm]{0,3}$/.test(value);
|
1336
|
+
},
|
1337
|
+
|
1338
|
+
_initDataAttributes: function () {
|
1339
|
+
var that = this,
|
1340
|
+
options = this.options,
|
1341
|
+
clone = $(this.element[0].cloneNode(false));
|
1082
1342
|
// Initialize options set via HTML5 data-attributes:
|
1083
|
-
$.
|
1343
|
+
$.each(
|
1344
|
+
clone.data(),
|
1345
|
+
function (key, value) {
|
1346
|
+
var dataAttributeName = 'data-' +
|
1347
|
+
// Convert camelCase to hyphen-ated key:
|
1348
|
+
key.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
1349
|
+
if (clone.attr(dataAttributeName)) {
|
1350
|
+
if (that._isRegExpOption(key, value)) {
|
1351
|
+
value = that._getRegExp(value);
|
1352
|
+
}
|
1353
|
+
options[key] = value;
|
1354
|
+
}
|
1355
|
+
}
|
1356
|
+
);
|
1357
|
+
},
|
1358
|
+
|
1359
|
+
_create: function () {
|
1360
|
+
this._initDataAttributes();
|
1084
1361
|
this._initSpecialOptions();
|
1085
1362
|
this._slots = [];
|
1086
1363
|
this._sequence = this._getXHRPromise(true);
|
1087
|
-
this._sending = this._active =
|
1364
|
+
this._sending = this._active = 0;
|
1365
|
+
this._initProgressObject(this);
|
1088
1366
|
this._initEventHandlers();
|
1089
1367
|
},
|
1090
1368
|
|
1091
|
-
|
1092
|
-
|
1369
|
+
// This method is exposed to the widget API and allows to query
|
1370
|
+
// the number of active uploads:
|
1371
|
+
active: function () {
|
1372
|
+
return this._active;
|
1373
|
+
},
|
1374
|
+
|
1375
|
+
// This method is exposed to the widget API and allows to query
|
1376
|
+
// the widget upload progress.
|
1377
|
+
// It returns an object with loaded, total and bitrate properties
|
1378
|
+
// for the running uploads:
|
1379
|
+
progress: function () {
|
1380
|
+
return this._progress;
|
1093
1381
|
},
|
1094
1382
|
|
1095
1383
|
// This method is exposed to the widget API and allows adding files
|
@@ -1138,8 +1426,13 @@
|
|
1138
1426
|
if (aborted) {
|
1139
1427
|
return;
|
1140
1428
|
}
|
1429
|
+
if (!files.length) {
|
1430
|
+
dfd.reject();
|
1431
|
+
return;
|
1432
|
+
}
|
1141
1433
|
data.files = files;
|
1142
|
-
jqXHR = that._onSend(null, data)
|
1434
|
+
jqXHR = that._onSend(null, data);
|
1435
|
+
jqXHR.then(
|
1143
1436
|
function (result, textStatus, jqXHR) {
|
1144
1437
|
dfd.resolve(result, textStatus, jqXHR);
|
1145
1438
|
},
|