(function($) {
jQuery.fn.html5_upload = function(options) {
var available_events = ['onStart', 'onStartOne', 'onProgress', 'onFinishOne', 'onFinish', 'onError'];
var options = jQuery.extend({
onStart: function(event, total) {
return true;
},
onStartOne: function(event, name, number, total) {
return true;
},
onProgress: function(event, progress, name, number, total) {
},
onFinishOne: function(event, response, name, number, total) {
},
onFinish: function(event, total) {
},
onError: function(event, name, error) {
},
onBrowserIncompatible: function() {
alert("Sorry, but your browser is incompatible with uploading files using HTML5 (at least, with current preferences.\n Please install the latest version of Firefox, Safari or Chrome");
},
autostart: true,
autoclear: true,
stopOnFirstError: false,
sendBoundary: false,
fieldName: 'user_file[]',//ignore if sendBoundary is false
method: 'post',
STATUSES: {
'STARTED': 'Запуск',
'PROGRESS': 'Загрузка',
'LOADED': 'Обработка',
'FINISHED': 'Завершено'
},
headers: {
"Cache-Control":"no-cache",
"X-Requested-With":"XMLHttpRequest",
"X-File-Name": function(file){return file.fileName},
"X-File-Size": function(file){return file.fileSize},
"Content-Type": function(file){
if (!options.sendBoundary) return 'multipart/form-data';
return false;
}
},
setName: function(text) {},
setStatus: function(text) {},
setProgress: function(value) {},
genName: function(file, number, total) {
return file + "(" + (number+1) + " из " + total + ")";
},
genStatus: function(progress, finished) {
if (finished) {
return options.STATUSES['FINISHED'];
}
if (progress == 0) {
return options.STATUSES['STARTED'];
}
else if (progress == 1) {
return options.STATUSES['LOADED'];
}
else {
return options.STATUSES['PROGRESS'];
}
},
genProgress: function(loaded, total) {
return loaded / total;
}
}, options);
function upload() {
var files = this.files;
var total = files.length;
var $this = $(this);
if (!$this.triggerHandler('html5_upload.onStart', [total])) {
return false;
}
this.disabled = true;
var uploaded = 0;
var xhr = this.html5_upload['xhr'];
this.html5_upload['continue_after_abort'] = true;
function upload_file(number) {
if (number == total) {
$this.trigger('html5_upload.onFinish', [total]);
options.setStatus(options.genStatus(1, true));
$this.attr("disabled", false);
if (options.autoclear) {
$this.val("");
}
return;
}
var file = files[number];
if (!$this.triggerHandler('html5_upload.onStartOne', [file.fileName, number, total])) {
return upload_file(number+1);
}
options.setStatus(options.genStatus(0));
options.setName(options.genName(file.fileName, number, total));
options.setProgress(options.genProgress(0, file.fileSize));
xhr.upload['onprogress'] = function(rpe) {
$this.trigger('html5_upload.onProgress', [rpe.loaded / rpe.total, file.fileName, number, total]);
options.setStatus(options.genStatus(rpe.loaded / rpe.total));
options.setProgress(options.genProgress(rpe.loaded, rpe.total));
};
xhr.onload = function(load) {
$this.trigger('html5_upload.onFinishOne', [xhr.responseText, file.fileName, number, total]);
options.setStatus(options.genStatus(1, true));
options.setProgress(options.genProgress(file.fileSize, file.fileSize));
upload_file(number+1);
};
xhr.onabort = function() {
if ($this[0].html5_upload['continue_after_abort']) {
upload_file(number+1);
}
else {
$this.attr("disabled", false);
if (options.autoclear) {
$this.val("");
}
}
};
xhr.onerror = function(e) {
$this.trigger('html5_upload.onError', [file.fileName, e]);
if (!options.stopOnFirstError) {
upload_file(number+1);
}
};
xhr.open(options.method, typeof(options.url) == "function" ? options.url(number) : options.url, true);
$.each(options.headers,function(key,val){
val = typeof(val) == "function" ? val(file) : val; // resolve value
if (val === false) return true; // if resolved value is boolean false, do not send this header
xhr.setRequestHeader(key, val);
});
if (!options.sendBoundary) {
xhr.send(file);
}
else {
if (window.FormData) {//Many thanks to scottt.tw
var f = new FormData();
f.append(typeof(options.fieldName) == "function" ? options.fieldName() : options.fieldName, file);
xhr.send(f);
}
else if (file.getAsBinary) {//Thanks to jm.schelcher
var boundary = '------multipartformboundary' + (new Date).getTime();
var dashdash = '--';
var crlf = '\r\n';
/* Build RFC2388 string. */
var builder = '';
builder += dashdash;
builder += boundary;
builder += crlf;
builder += 'Content-Disposition: form-data; name="'+(typeof(options.fieldName) == "function" ? options.fieldName() : options.fieldName)+'"';
//thanks to oyejo...@gmail.com for this fix
fileName = unescape(encodeURIComponent(file.fileName)); //encode_utf8
builder += '; filename="' + fileName + '"';
builder += crlf;
builder += 'Content-Type: application/octet-stream';
builder += crlf;
builder += crlf;
/* Append binary data. */
builder += file.getAsBinary();
builder += crlf;
/* Write boundary. */
builder += dashdash;
builder += boundary;
builder += dashdash;
builder += crlf;
xhr.setRequestHeader('content-type', 'multipart/form-data; boundary=' + boundary);
xhr.sendAsBinary(builder);
}
else {
options.onBrowserIncompatible();
}
}
}
upload_file(0);
return true;
}
return this.each(function() {
this.html5_upload = {
xhr: new XMLHttpRequest(),
continue_after_abort: true
};
if (options.autostart) {
$(this).bind('change', upload);
}
for (event in available_events) {
if (options[available_events[event]]) {
$(this).bind("html5_upload."+available_events[event], options[available_events[event]]);
}
}
$(this)
.bind('html5_upload.start', upload)
.bind('html5_upload.cancelOne', function() {
this.html5_upload['xhr'].abort();
})
.bind('html5_upload.cancelAll', function() {
this.html5_upload['continue_after_abort'] = false;
this.html5_upload['xhr'].abort();
})
.bind('html5_upload.destroy', function() {
this.html5_upload['continue_after_abort'] = false;
this.xhr.abort();
delete this.html5_upload;
$(this).unbind('html5_upload.*').unbind('change', upload);
});
});
};
})(jQuery);