Skip to content

Commit df5d490

Browse files
committed
Provide XHR file upload capability tests via $.support.xhrFileUpload and $.support.xhrFormDataFileUpload.
Only listen to drag&drop events if the browser supports XHR file uploads. Fixes blueimp#815.
1 parent 9a6fd66 commit df5d490

File tree

2 files changed

+131
-107
lines changed

2 files changed

+131
-107
lines changed

js/jquery.fileupload.js

+29-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* jQuery File Upload Plugin 5.8.1
2+
* jQuery File Upload Plugin 5.9
33
* https://github.com/blueimp/jQuery-File-Upload
44
*
55
* Copyright 2010, Sebastian Tschan
@@ -10,7 +10,7 @@
1010
*/
1111

1212
/*jslint nomen: true, unparam: true, regexp: true */
13-
/*global define, window, document, XMLHttpRequestUpload, Blob, File, FormData, location */
13+
/*global define, window, document, Blob, FormData, location */
1414

1515
(function (factory) {
1616
'use strict';
@@ -27,6 +27,12 @@
2727
}(function ($) {
2828
'use strict';
2929

30+
// The FileReader API is not actually used, but works as feature detection,
31+
// as e.g. Safari supports XHR file uploads via the FormData API,
32+
// but not non-multipart XHR file uploads:
33+
$.support.xhrFileUpload = !!(window.XMLHttpRequestUpload && window.FileReader);
34+
$.support.xhrFormDataFileUpload = !!window.FormData;
35+
3036
// The fileupload widget listens for change events on file input fields defined
3137
// via fileInput setting and paste or drop events of the given dropZone.
3238
// In addition to the default jQuery Widget methods, the fileupload widget
@@ -165,13 +171,18 @@
165171
},
166172

167173
// A list of options that require a refresh after assigning a new value:
168-
_refreshOptionsList: ['namespace', 'dropZone', 'fileInput'],
174+
_refreshOptionsList: [
175+
'namespace',
176+
'dropZone',
177+
'fileInput',
178+
'multipart',
179+
'forceIframeTransport'
180+
],
169181

170182
_isXHRUpload: function (options) {
171-
var undef = 'undefined';
172183
return !options.forceIframeTransport &&
173-
typeof XMLHttpRequestUpload !== undef && typeof File !== undef &&
174-
(!options.multipart || typeof FormData !== undef);
184+
((!options.multipart && $.support.xhrFileUpload) ||
185+
$.support.xhrFormDataFileUpload);
175186
},
176187

177188
_getFormData: function (options) {
@@ -245,8 +256,10 @@
245256

246257
_initXHRData: function (options) {
247258
var formData,
248-
file = options.files[0];
249-
if (!options.multipart || options.blob) {
259+
file = options.files[0],
260+
// Ignore non-multipart setting if not supported:
261+
multipart = options.multipart || !$.support.xhrFileUpload;
262+
if (!multipart || options.blob) {
250263
// For non-multipart uploads and chunked uploads,
251264
// file meta data is not part of the request body,
252265
// so we transmit this data as part of the HTTP headers.
@@ -262,13 +275,13 @@
262275
// Non-chunked non-multipart upload:
263276
options.contentType = file.type;
264277
options.data = file;
265-
} else if (!options.multipart) {
278+
} else if (!multipart) {
266279
// Chunked non-multipart upload:
267280
options.contentType = 'application/octet-stream';
268281
options.data = options.blob;
269282
}
270283
}
271-
if (options.multipart && typeof FormData !== 'undefined') {
284+
if (multipart && $.support.xhrFormDataFileUpload) {
272285
if (options.postMessage) {
273286
// window.postMessage does not allow sending FormData
274287
// objects, so we just add the File/Blob objects to
@@ -748,10 +761,12 @@
748761

749762
_initEventHandlers: function () {
750763
var ns = this.options.namespace;
751-
this.options.dropZone
752-
.bind('dragover.' + ns, {fileupload: this}, this._onDragOver)
753-
.bind('drop.' + ns, {fileupload: this}, this._onDrop)
754-
.bind('paste.' + ns, {fileupload: this}, this._onPaste);
764+
if (this._isXHRUpload(this.options)) {
765+
this.options.dropZone
766+
.bind('dragover.' + ns, {fileupload: this}, this._onDragOver)
767+
.bind('drop.' + ns, {fileupload: this}, this._onDrop)
768+
.bind('paste.' + ns, {fileupload: this}, this._onPaste);
769+
}
755770
this.options.fileInput
756771
.bind('change.' + ns, {fileupload: this}, this._onChange);
757772
},

test/test.js

+102-93
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* jQuery File Upload Plugin Test 6.4
2+
* jQuery File Upload Plugin Test 6.5
33
* https://github.com/blueimp/jQuery-File-Upload
44
*
55
* Copyright 2010, Sebastian Tschan
@@ -94,16 +94,18 @@ $(function () {
9494
.data('events').change.length,
9595
'Listens to file input change events'
9696
);
97-
ok(
98-
fu.fileupload('option', 'dropZone')
99-
.data('events').drop.length,
100-
'Listens to drop zone drop events'
101-
);
102-
ok(
103-
fu.fileupload('option', 'dropZone')
104-
.data('events').dragover.length,
105-
'Listens to drop zone dragover events'
106-
);
97+
if ($.support.xhrFormDataFileUpload) {
98+
ok(
99+
fu.fileupload('option', 'dropZone')
100+
.data('events').drop.length,
101+
'Listens to drop zone drop events'
102+
);
103+
ok(
104+
fu.fileupload('option', 'dropZone')
105+
.data('events').dragover.length,
106+
'Listens to drop zone dragover events'
107+
);
108+
}
107109
});
108110

109111
module('API', lifecycle);
@@ -121,16 +123,18 @@ $(function () {
121123
1,
122124
'Removes own file input change event listener'
123125
);
124-
strictEqual(
125-
dropZone.data('events').drop.length,
126-
1,
127-
'Removes own drop zone drop event listener'
128-
);
129-
strictEqual(
130-
dropZone.data('events').dragover.length,
131-
1,
132-
'Removes own drop zone dragover event listener'
133-
);
126+
if ($.support.xhrFormDataFileUpload) {
127+
strictEqual(
128+
dropZone.data('events').drop.length,
129+
1,
130+
'Removes own drop zone drop event listener'
131+
);
132+
strictEqual(
133+
dropZone.data('events').dragover.length,
134+
1,
135+
'Removes own drop zone dragover event listener'
136+
);
137+
}
134138
});
135139

136140
test('disable', function () {
@@ -142,22 +146,23 @@ $(function () {
142146
dropZone.bind('drop', $.noop);
143147
dropZone.bind('dragover', $.noop);
144148
fu.fileupload('disable');
145-
expect(3);
146149
strictEqual(
147150
fileInput.data('events').change.length,
148151
1,
149152
'Removes own file input change event listener'
150153
);
151-
strictEqual(
152-
dropZone.data('events').drop.length,
153-
1,
154-
'Removes own drop zone drop event listener'
155-
);
156-
strictEqual(
157-
dropZone.data('events').dragover.length,
158-
1,
159-
'Removes own drop zone dragover event listener'
160-
);
154+
if ($.support.xhrFormDataFileUpload) {
155+
strictEqual(
156+
dropZone.data('events').drop.length,
157+
1,
158+
'Removes own drop zone drop event listener'
159+
);
160+
strictEqual(
161+
dropZone.data('events').dragover.length,
162+
1,
163+
'Removes own drop zone dragover event listener'
164+
);
165+
}
161166
fu.fileupload({
162167
add: function (e, data) {
163168
ok(false);
@@ -170,22 +175,23 @@ $(function () {
170175
param = {files: [{name: 'test'}]};
171176
fu.fileupload('disable');
172177
fu.fileupload('enable');
173-
expect(4);
174178
ok(
175179
fu.fileupload('option', 'fileInput')
176180
.data('events').change.length,
177181
'Listens to file input change events'
178182
);
179-
ok(
180-
fu.fileupload('option', 'dropZone')
181-
.data('events').drop.length,
182-
'Listens to drop zone drop events'
183-
);
184-
ok(
185-
fu.fileupload('option', 'dropZone')
186-
.data('events').dragover.length,
187-
'Listens to drop zone dragover events'
188-
);
183+
if ($.support.xhrFormDataFileUpload) {
184+
ok(
185+
fu.fileupload('option', 'dropZone')
186+
.data('events').drop.length,
187+
'Listens to drop zone drop events'
188+
);
189+
ok(
190+
fu.fileupload('option', 'dropZone')
191+
.data('events').dragover.length,
192+
'Listens to drop zone dragover events'
193+
);
194+
}
189195
$('#fileupload').fileupload({
190196
send: function (e, data) {
191197
strictEqual(
@@ -208,24 +214,28 @@ $(function () {
208214
!fileInput.data('events'),
209215
'Removes event listener after changing fileInput option'
210216
);
211-
ok(
212-
!dropZone.data('events'),
213-
'Removes event listeners after changing dropZone option'
214-
);
217+
if ($.support.xhrFormDataFileUpload) {
218+
ok(
219+
!dropZone.data('events'),
220+
'Removes event listeners after changing dropZone option'
221+
);
222+
}
215223
fu.fileupload('option', 'fileInput', fileInput);
216224
fu.fileupload('option', 'dropZone', dropZone);
217225
ok(
218226
fileInput.data('events').change.length,
219227
'Adds change event listener after setting fileInput option'
220228
);
221-
ok(
222-
dropZone.data('events').drop.length,
223-
'Adds drop event listener after setting dropZone option'
224-
);
225-
ok(
226-
dropZone.data('events').dragover.length,
227-
'Adds dragover event listener after setting dropZone option'
228-
);
229+
if ($.support.xhrFormDataFileUpload) {
230+
ok(
231+
dropZone.data('events').drop.length,
232+
'Adds drop event listener after setting dropZone option'
233+
);
234+
ok(
235+
dropZone.data('events').dragover.length,
236+
'Adds dragover event listener after setting dropZone option'
237+
);
238+
}
229239
fu.fileupload('option', 'dropZone', 'body');
230240
strictEqual(
231241
fu.fileupload('option', 'dropZone')[0],
@@ -785,44 +795,43 @@ $(function () {
785795
fu.fileupload('add', param);
786796
});
787797

788-
asyncTest('multipart', function () {
789-
expect(4);
790-
var param = {files: [{
791-
name: 'test.png',
792-
size: 123,
793-
type: 'image/png'
794-
}]},
795-
fu = $('#fileupload').fileupload({
796-
multipart: false,
797-
always: function (e, data) {
798-
strictEqual(
799-
data.contentType,
800-
param.files[0].type,
801-
'non-multipart upload sets file type as contentType'
802-
);
803-
strictEqual(
804-
data.headers['X-File-Name'],
805-
param.files[0].name,
806-
'non-multipart upload sets X-File-Name header'
807-
);
808-
strictEqual(
809-
data.headers['X-File-Type'],
810-
param.files[0].type,
811-
'non-multipart upload sets X-File-Type header'
812-
);
813-
strictEqual(
814-
data.headers['X-File-Size'],
815-
param.files[0].size,
816-
'non-multipart upload sets X-File-Size header'
817-
);
818-
start();
819-
}
820-
});
821-
fu.data('fileupload')._isXHRUpload = function () {
822-
return true;
823-
};
824-
fu.fileupload('send', param);
825-
});
798+
if ($.support.xhrFileUpload) {
799+
asyncTest('multipart', function () {
800+
expect(4);
801+
var param = {files: [{
802+
name: 'test.png',
803+
size: 123,
804+
type: 'image/png'
805+
}]},
806+
fu = $('#fileupload').fileupload({
807+
multipart: false,
808+
always: function (e, data) {
809+
strictEqual(
810+
data.contentType,
811+
param.files[0].type,
812+
'non-multipart upload sets file type as contentType'
813+
);
814+
strictEqual(
815+
data.headers['X-File-Name'],
816+
param.files[0].name,
817+
'non-multipart upload sets X-File-Name header'
818+
);
819+
strictEqual(
820+
data.headers['X-File-Type'],
821+
param.files[0].type,
822+
'non-multipart upload sets X-File-Type header'
823+
);
824+
strictEqual(
825+
data.headers['X-File-Size'],
826+
param.files[0].size,
827+
'non-multipart upload sets X-File-Size header'
828+
);
829+
start();
830+
}
831+
});
832+
fu.fileupload('send', param);
833+
});
834+
}
826835

827836
module('UI Initialization', lifecycleUI);
828837

0 commit comments

Comments
 (0)