Skip to content

Instantly share code, notes, and snippets.

@maca
Last active December 15, 2015 21:09
Show Gist options
  • Save maca/5323739 to your computer and use it in GitHub Desktop.
Save maca/5323739 to your computer and use it in GitHub Desktop.
jQuery xhr uploads plugin.
/*
* jQuery XHR upload plugin
* http://github.com/maca
*
* Copyright 2011, Macario Ortega
* Dual licensed under the MIT or GPL Version 2 licenses.
*
*/
(function($){
$.fn.ajaxyUpload = function(opts) {
var settings = {
error : $.noop,
success : $.noop,
start : $.noop,
complete : $.noop,
cancelText : 'cancel',
spinner : {color : '#555', lines : 6, length : 2, width : 9, radius : 6}
};
return $(this).each(function(){
var fileInput = $(this);
if (opts) { $.extend(settings, opts); }
fileInput.attr("multiple", "multiple");
// xhrUpload callback, this is triggered below only if the browser has hxr upload
// capabilities
fileInput.bind('xhrUpload', function(){
var self = this;
$.each(this.files, function(index, file){
var advance = $('<div>').addClass('inline-upload-advance');
var pBar = $('<div>').addClass('inline-upload-progress-bar').append(advance);
var cancelLink = $('<a href="#">').addClass('inline-upload-cancel-link').text(settings.cancelText);
var uploadStatus = $('<div>').addClass('inline-upload-upload-status').append(pBar).append(cancelLink).click(function(){
$(self).trigger('cancelUpload');
return false;
});
advance.css('height','10px');
advance.css('background-color', '#33a');
advance.css('width', '0px');
pBar.css('width','200px');
pBar.css('background-color','#fff');
pBar.css('border','1px solid #BBB');
fileInput.after(uploadStatus);
var xhrUpload = $.ajax({
type : "POST",
url : settings.url,
xhr : function(){
var xhr = $.ajaxSettings.xhr();
xhr.upload.onprogress = function(rpe) {
var progress = (rpe.loaded / rpe.total * 100 >> 0) + '%';
advance.css('width', progress);
};
xhr.onloadstart = function(){
fileInput.val('');
settings.start.apply(self);
};
return xhr;
},
beforeSend : function(xhr){
// here we set custom headers for the rack middleware, first one tells the Rack app we are doing
// an xhr upload, the two others are self explanatory
xhr.setRequestHeader("X-XHR-Upload", "1");
xhr.setRequestHeader("X-File-Name", file.name || file.fileName);
xhr.setRequestHeader("X-File-Size", file.fileSize);
},
success : function(data, status, xhr) {
settings.success.apply(self, [data, status, xhr]);
},
error : function(xhr, text, error) {
if (xhr.status == 422) {
settings.error.apply(self, [$.parseJSON(xhr.responseText)]);
} else if (text != 'abort') {
settings.error.apply(self);
};
},
complete : function(xhr, status) {
settings.complete.apply(self);
uploadStatus.remove();
},
contentType : file.type || "application/octet-stream",
dataType : "json",
processData : false,
data : file
});
$(self).bind('cancelUpload', function(){
xhrUpload.abort();
uploadStatus.remove();
if($.browser.msie){
correctInput($('#main_uploader')).show();
correctInput($('#project_uploader')).show();
}else{
$('#main_uploader').find('a.upload_image').show();
$('#project_uploader').find('a.upload_image').show();
}
return true;
})
});
});
// set an iframeUpload callback as fallback for older browsers
fileInput.bind('iframeUpload', function(){
var input = $("<input type='file' class='inline-upload-input'>").attr('name', 'file');
var iframe = $("<iframe class='inline-upload-catcher' name='inline-upload-catcher-" + new Date().getTime() + "'></iframe>").hide();
var spinner = $('<div>').addClass('spinner').hide();
var auth = $("<input type='hidden' name='authenticity_token'>").val( $('input[name=authenticity_token]').val() ); // Rails authenticity token
var form = $("<form enctype='multipart/form-data' method='post' action=" + settings.url + "></form>").addClass('inline-upload-form').append(input).append(auth);
form.attr('target', iframe.attr('name'));
new Spinner(settings.spinner).spin(spinner[0]);
spinner.css('height', spinner.css('height') || '10px');
spinner.css('height', spinner.css('height') || '10px');
spinner.css('z-index', spinner.css('z-index') || '3000');
$(this).after(form).after(iframe).hide();
input.after(spinner);
input.bind('complete', function(event, data){
if (data.errors != undefined && data.errors != null) {
settings.error.apply(this, [data]);
} else {
settings.success.apply(this, [data]);
};
spinner.hide();
settings.complete.apply(this);
});
input.change(function(){
settings.start.apply(this);
spinner.show();
form.submit();
$(this).val('');
});
iframe.load(function(){
var script = $(this).contents().find('script');
if (script.size() > 0) {
var data = script.html()
input.trigger('complete', [$.parseJSON(data)]);
}
});
});
// Not used just to check browser capabilities
var xhr = $.ajaxSettings.xhr();
// If the browser has xhr upload capabilities trigger xhrUpload otherwise fallback to iframe upload
if (this.files && xhr && xhr.upload && (xhr.upload.onprogress !== undefined) && window.FileReader) {
fileInput.change(function(){ $(this).trigger('xhrUpload') });
} else {
fileInput.trigger('iframeUpload');
};
})
};
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment