Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added folder drag&drop support.

  • Loading branch information...
commit cd0c9eda9661a7f772a85c357332b7a7af21bbe6 1 parent 788a49d
@blueimp authored
Showing with 129 additions and 27 deletions.
  1. +129 −27 js/jquery.fileupload.js
View
156 js/jquery.fileupload.js
@@ -1,5 +1,5 @@
/*
- * jQuery File Upload Plugin 5.15
+ * jQuery File Upload Plugin 5.16
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
@@ -696,7 +696,7 @@
var args = [undefined, 'abort', 'abort'];
if (!jqXHR) {
if (slot) {
- slot.rejectWith(args);
+ slot.rejectWith(pipe, args);
}
return send(false, args);
}
@@ -775,21 +775,90 @@
}
},
+ _handleFileTreeEntry: function (entry, path) {
+ var that = this,
+ dfd = $.Deferred(),
+ errorHandler = function () {
+ dfd.reject();
+ },
+ dirReader;
+ path = path || '';
+ if (entry.isFile) {
+ entry.file(function (file) {
+ file.relativePath = path;
+ dfd.resolve(file);
+ }, errorHandler);
+ } else if (entry.isDirectory) {
+ dirReader = entry.createReader();
+ dirReader.readEntries(function (entries) {
+ that._handleFileTreeEntries(
+ entries,
+ path + entry.name + '/'
+ ).done(function (files) {
+ dfd.resolve(files);
+ }).fail(errorHandler);
+ }, errorHandler);
+ } else {
+ errorHandler();
+ }
+ return dfd.promise();
+ },
+
+ _handleFileTreeEntries: function (entries, path) {
+ var that = this;
+ return $.when.apply(
+ $,
+ $.map(entries, function (entry) {
+ return that._handleFileTreeEntry(entry, path);
+ })
+ ).pipe(function () {
+ return Array.prototype.concat.apply(
+ [],
+ arguments
+ );
+ });
+ },
+
+ _getDroppedFiles: function (dataTransfer) {
+ dataTransfer = dataTransfer || {};
+ var items = dataTransfer.items;
+ if (items && items.length && (items[0].webkitGetAsEntry ||
+ items[0].getAsEntry)) {
+ return this._handleFileTreeEntries(
+ $.map(items, function (item) {
+ if (item.webkitGetAsEntry) {
+ return item.webkitGetAsEntry();
+ }
+ return item.getAsEntry();
+ })
+ );
+ }
+ return $.Deferred().resolve(
+ $.makeArray(dataTransfer.files)
+ ).promise();
+ },
+
_getFileInputFiles: function (fileInput) {
fileInput = $(fileInput);
- var files = $.makeArray(fileInput.prop('files')),
+ var entries = fileInput.prop('webkitEntries') ||
+ fileInput.prop('entries'),
+ files,
value;
+ if (entries) {
+ return this._handleFileTreeEntries(entries);
+ }
+ files = $.makeArray(fileInput.prop('files'));
if (!files.length) {
value = fileInput.prop('value');
if (!value) {
- return [];
+ return $.Deferred().reject([]).promise();
}
// If the files property is not available, the browser does not
// support the File API and we add a pseudo File object with
// the input value as name with path information removed:
files = [{name: value.replace(/^.*\\/, '')}];
}
- return files;
+ return $.Deferred().resolve(files).promise();
},
_onChange: function (e) {
@@ -798,14 +867,15 @@
fileInput: $(e.target),
form: $(e.target.form)
};
- data.files = that._getFileInputFiles(data.fileInput);
- if (that.options.replaceFileInput) {
- that._replaceFileInput(data.fileInput);
- }
- if (that._trigger('change', e, data) === false ||
- that._onAdd(e, data) === false) {
- return false;
- }
+ that._getFileInputFiles(data.fileInput).always(function (files) {
+ data.files = files;
+ if (that.options.replaceFileInput) {
+ that._replaceFileInput(data.fileInput);
+ }
+ if (that._trigger('change', e, data) !== false) {
+ that._onAdd(e, data);
+ }
+ });
},
_onPaste: function (e) {
@@ -826,16 +896,16 @@
},
_onDrop: function (e) {
+ e.preventDefault();
var that = e.data.fileupload,
dataTransfer = e.dataTransfer = e.originalEvent.dataTransfer,
- data = {
- files: $.makeArray(dataTransfer && dataTransfer.files)
- };
- if (that._trigger('drop', e, data) === false ||
- that._onAdd(e, data) === false) {
- return false;
- }
- e.preventDefault();
+ data = {};
+ that._getDroppedFiles(dataTransfer).always(function (files) {
+ data.files = files;
+ if (that._trigger('drop', e, data) !== false) {
+ that._onAdd(e, data);
+ }
+ });
},
_onDragOver: function (e) {
@@ -929,29 +999,61 @@
// must have a files property and can contain additional options:
// .fileupload('add', {files: filesList});
add: function (data) {
+ var that = this;
if (!data || this.options.disabled) {
return;
}
if (data.fileInput && !data.files) {
- data.files = this._getFileInputFiles(data.fileInput);
+ this._getFileInputFiles(data.fileInput).always(function (files) {
+ data.files = files;
+ that._onAdd(null, data);
+ });
} else {
data.files = $.makeArray(data.files);
+ this._onAdd(null, data);
}
- this._onAdd(null, data);
},
// This method is exposed to the widget API and allows sending files
// using the fileupload API. The data parameter accepts an object which
- // must have a files property and can contain additional options:
+ // must have a files or fileInput property and can contain additional options:
// .fileupload('send', {files: filesList});
// The method returns a Promise object for the file upload call.
send: function (data) {
if (data && !this.options.disabled) {
if (data.fileInput && !data.files) {
- data.files = this._getFileInputFiles(data.fileInput);
- } else {
- data.files = $.makeArray(data.files);
+ var that = this,
+ dfd = $.Deferred(),
+ promise = dfd.promise(),
+ jqXHR,
+ aborted;
+ promise.abort = function () {
+ aborted = true;
+ if (jqXHR) {
+ return jqXHR.abort();
+ }
+ dfd.reject(null, 'abort', 'abort');
+ return promise;
+ };
+ this._getFileInputFiles(data.fileInput).always(
+ function (files) {
+ if (aborted) {
+ return;
+ }
+ data.files = files;
+ jqXHR = that._onSend(null, data).then(
+ function (result, textStatus, jqXHR) {
+ dfd.resolve(result, textStatus, jqXHR);
+ },
+ function (jqXHR, textStatus, errorThrown) {
+ dfd.reject(jqXHR, textStatus, errorThrown);
+ }
+ );
+ }
+ );
+ return this._enhancePromise(promise);
}
+ data.files = $.makeArray(data.files);
if (data.files.length) {
return this._onSend(null, data);
}
Please sign in to comment.
Something went wrong with that request. Please try again.