update jquery.form.min

This commit is contained in:
Mitchell Livingston 2011-09-18 23:12:31 +00:00
parent bdda467d35
commit 234e9715ea
2 changed files with 158 additions and 72 deletions

View File

@ -1,6 +1,6 @@
/*! /*!
* jQuery Form Plugin * jQuery Form Plugin
* version: 2.75 (20-MAY-2011) * version: 2.84 (12-AUG-2011)
* @requires jQuery v1.3.2 or later * @requires jQuery v1.3.2 or later
* *
* Examples and documentation at: http://malsup.com/jquery/form/ * Examples and documentation at: http://malsup.com/jquery/form/
@ -49,13 +49,16 @@ $.fn.ajaxSubmit = function(options) {
log('ajaxSubmit: skipping submit process - no element selected'); log('ajaxSubmit: skipping submit process - no element selected');
return this; return this;
} }
var method, action, url, $form = this;
if (typeof options == 'function') { if (typeof options == 'function') {
options = { success: options }; options = { success: options };
} }
var action = this.attr('action'); method = this.attr('method');
var url = (typeof action === 'string') ? $.trim(action) : ''; action = this.attr('action');
url = (typeof action === 'string') ? $.trim(action) : '';
url = url || window.location.href || ''; url = url || window.location.href || '';
if (url) { if (url) {
// clean url (don't include hash vaue) // clean url (don't include hash vaue)
@ -65,7 +68,7 @@ $.fn.ajaxSubmit = function(options) {
options = $.extend(true, { options = $.extend(true, {
url: url, url: url,
success: $.ajaxSettings.success, success: $.ajaxSettings.success,
type: this[0].getAttribute('method') || 'GET', // IE7 massage (see issue 57) type: method || 'GET',
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
}, options); }, options);
@ -88,7 +91,7 @@ $.fn.ajaxSubmit = function(options) {
if (options.data) { if (options.data) {
options.extraData = options.data; options.extraData = options.data;
for (n in options.data) { for (n in options.data) {
if(options.data[n] instanceof Array) { if( $.isArray(options.data[n]) ) {
for (var k in options.data[n]) { for (var k in options.data[n]) {
a.push( { name: n, value: options.data[n][k] } ); a.push( { name: n, value: options.data[n][k] } );
} }
@ -124,7 +127,7 @@ $.fn.ajaxSubmit = function(options) {
options.data = q; // data is the query string for 'post' options.data = q; // data is the query string for 'post'
} }
var $form = this, callbacks = []; var callbacks = [];
if (options.resetForm) { if (options.resetForm) {
callbacks.push(function() { $form.resetForm(); }); callbacks.push(function() { $form.resetForm(); });
} }
@ -162,13 +165,19 @@ $.fn.ajaxSubmit = function(options) {
// hack to fix Safari hang (thanks to Tim Molendijk for this) // hack to fix Safari hang (thanks to Tim Molendijk for this)
// see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
if (options.closeKeepAlive) { if (options.closeKeepAlive) {
$.get(options.closeKeepAlive, fileUpload); $.get(options.closeKeepAlive, function() { fileUpload(a); });
} }
else { else {
fileUpload(); fileUpload(a);
} }
} }
else { else {
// IE7 massage (see issue 57)
if ($.browser.msie && method == 'get') {
var ieMeth = $form[0].getAttribute('method');
if (typeof ieMeth === 'string')
options.type = ieMeth;
}
$.ajax(options); $.ajax(options);
} }
@ -178,8 +187,17 @@ $.fn.ajaxSubmit = function(options) {
// private function for handling file uploads (hat tip to YAHOO!) // private function for handling file uploads (hat tip to YAHOO!)
function fileUpload() { function fileUpload(a) {
var form = $form[0]; var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
var useProp = !!$.fn.prop;
if (a) {
// ensure that every serialized input is still enabled
for (i=0; i < a.length; i++) {
el = $(form[a[i].name]);
el[ useProp ? 'prop' : 'attr' ]('disabled', false);
}
}
if ($(':input[name=submit],:input[id=submit]', form).length) { if ($(':input[name=submit],:input[id=submit]', form).length) {
// if there is an input with a name or id of 'submit' then we won't be // if there is an input with a name or id of 'submit' then we won't be
@ -188,15 +206,25 @@ $.fn.ajaxSubmit = function(options) {
return; return;
} }
var s = $.extend(true, {}, $.ajaxSettings, options); s = $.extend(true, {}, $.ajaxSettings, options);
s.context = s.context || s; s.context = s.context || s;
var id = 'jqFormIO' + (new Date().getTime()), fn = '_'+id; id = 'jqFormIO' + (new Date().getTime());
var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ s.iframeSrc +'" />'); if (s.iframeTarget) {
var io = $io[0]; $io = $(s.iframeTarget);
n = $io.attr('name');
if (n == null)
$io.attr('name', id);
else
id = n;
}
else {
$io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
}
io = $io[0];
$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
var xhr = { // mock object xhr = { // mock object
aborted: 0, aborted: 0,
responseText: null, responseText: null,
responseXML: null, responseXML: null,
@ -211,13 +239,13 @@ $.fn.ajaxSubmit = function(options) {
this.aborted = 1; this.aborted = 1;
$io.attr('src', s.iframeSrc); // abort op in progress $io.attr('src', s.iframeSrc); // abort op in progress
xhr.error = e; xhr.error = e;
s.error && s.error.call(s.context, xhr, e, e); s.error && s.error.call(s.context, xhr, e, status);
g && $.event.trigger("ajaxError", [xhr, s, e]); g && $.event.trigger("ajaxError", [xhr, s, e]);
s.complete && s.complete.call(s.context, xhr, e); s.complete && s.complete.call(s.context, xhr, e);
} }
}; };
var g = s.global; g = s.global;
// trigger ajax global events so that activity/block indicators work like normal // trigger ajax global events so that activity/block indicators work like normal
if (g && ! $.active++) { if (g && ! $.active++) {
$.event.trigger("ajaxStart"); $.event.trigger("ajaxStart");
@ -227,7 +255,7 @@ $.fn.ajaxSubmit = function(options) {
} }
if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) { if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
if (s.global) { if (s.global) {
$.active--; $.active--;
} }
return; return;
@ -236,12 +264,10 @@ $.fn.ajaxSubmit = function(options) {
return; return;
} }
var timedOut = 0, timeoutHandle;
// add submitting element to data if we know it // add submitting element to data if we know it
var sub = form.clk; sub = form.clk;
if (sub) { if (sub) {
var n = sub.name; n = sub.name;
if (n && !sub.disabled) { if (n && !sub.disabled) {
s.extraData = s.extraData || {}; s.extraData = s.extraData || {};
s.extraData[n] = sub.value; s.extraData[n] = sub.value;
@ -251,7 +277,15 @@ $.fn.ajaxSubmit = function(options) {
} }
} }
} }
var CLIENT_TIMEOUT_ABORT = 1;
var SERVER_ABORT = 2;
function getDoc(frame) {
var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document;
return doc;
}
// take a breath so that pending repaints get some cpu time before the upload starts // take a breath so that pending repaints get some cpu time before the upload starts
function doSubmit() { function doSubmit() {
// make sure form attrs are set // make sure form attrs are set
@ -259,15 +293,15 @@ $.fn.ajaxSubmit = function(options) {
// update form attrs in IE friendly way // update form attrs in IE friendly way
form.setAttribute('target',id); form.setAttribute('target',id);
if (form.getAttribute('method') != 'POST') { if (!method) {
form.setAttribute('method', 'POST'); form.setAttribute('method', 'POST');
} }
if (form.getAttribute('action') != s.url) { if (a != s.url) {
form.setAttribute('action', s.url); form.setAttribute('action', s.url);
} }
// ie borks in some cases when setting encoding // ie borks in some cases when setting encoding
if (! s.skipEncodingOverride) { if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
$form.attr({ $form.attr({
encoding: 'multipart/form-data', encoding: 'multipart/form-data',
enctype: 'multipart/form-data' enctype: 'multipart/form-data'
@ -276,7 +310,23 @@ $.fn.ajaxSubmit = function(options) {
// support timout // support timout
if (s.timeout) { if (s.timeout) {
timeoutHandle = setTimeout(function() { timedOut = true; cb(true); }, s.timeout); timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
}
// look for server aborts
function checkState() {
try {
var state = getDoc(io).readyState;
log('state = ' + state);
if (state.toLowerCase() == 'uninitialized')
setTimeout(checkState,50);
}
catch(e) {
log('Server abort: ' , e, ' (', e.name, ')');
cb(SERVER_ABORT);
timeoutHandle && clearTimeout(timeoutHandle);
timeoutHandle = undefined;
}
} }
// add "extra" data to form if provided in options // add "extra" data to form if provided in options
@ -285,14 +335,17 @@ $.fn.ajaxSubmit = function(options) {
if (s.extraData) { if (s.extraData) {
for (var n in s.extraData) { for (var n in s.extraData) {
extraInputs.push( extraInputs.push(
$('<input type="hidden" name="'+n+'" value="'+s.extraData[n]+'" />') $('<input type="hidden" name="'+n+'" />').attr('value',s.extraData[n])
.appendTo(form)[0]); .appendTo(form)[0]);
} }
} }
// add iframe to doc and submit the form if (!s.iframeTarget) {
$io.appendTo('body'); // add iframe to doc and submit the form
io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false); $io.appendTo('body');
io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
}
setTimeout(checkState,15);
form.submit(); form.submit();
} }
finally { finally {
@ -313,19 +366,29 @@ $.fn.ajaxSubmit = function(options) {
else { else {
setTimeout(doSubmit, 10); // this lets dom updates render setTimeout(doSubmit, 10); // this lets dom updates render
} }
var data, doc, domCheckCount = 50, callbackProcessed; var data, doc, domCheckCount = 50, callbackProcessed;
function cb(e) { function cb(e) {
if (xhr.aborted || callbackProcessed) { if (xhr.aborted || callbackProcessed) {
return; return;
} }
if (e === true && xhr) { try {
doc = getDoc(io);
}
catch(ex) {
log('cannot access response document: ', ex);
e = SERVER_ABORT;
}
if (e === CLIENT_TIMEOUT_ABORT && xhr) {
xhr.abort('timeout'); xhr.abort('timeout');
return; return;
} }
else if (e == SERVER_ABORT && xhr) {
var doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document; xhr.abort('server abort');
return;
}
if (!doc || doc.location.href == s.iframeSrc) { if (!doc || doc.location.href == s.iframeSrc) {
// response not received yet // response not received yet
if (!timedOut) if (!timedOut)
@ -333,7 +396,7 @@ $.fn.ajaxSubmit = function(options) {
} }
io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false); io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
var ok = true; var status = 'success', errMsg;
try { try {
if (timedOut) { if (timedOut) {
throw 'timeout'; throw 'timeout';
@ -355,7 +418,8 @@ $.fn.ajaxSubmit = function(options) {
} }
//log('response detected'); //log('response detected');
xhr.responseText = doc.body ? doc.body.innerHTML : doc.documentElement ? doc.documentElement.innerHTML : null; var docRoot = doc.body ? doc.body : doc.documentElement;
xhr.responseText = docRoot ? docRoot.innerHTML : null;
xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc; xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
if (isXml) if (isXml)
s.dataType = 'xml'; s.dataType = 'xml';
@ -363,13 +427,22 @@ $.fn.ajaxSubmit = function(options) {
var headers = {'content-type': s.dataType}; var headers = {'content-type': s.dataType};
return headers[header]; return headers[header];
}; };
// support for XHR 'status' & 'statusText' emulation :
if (docRoot) {
xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
}
var scr = /(json|script|text)/.test(s.dataType); var dt = s.dataType || '';
var scr = /(json|script|text)/.test(dt.toLowerCase());
if (scr || s.textarea) { if (scr || s.textarea) {
// see if user embedded response in textarea // see if user embedded response in textarea
var ta = doc.getElementsByTagName('textarea')[0]; var ta = doc.getElementsByTagName('textarea')[0];
if (ta) { if (ta) {
xhr.responseText = ta.value; xhr.responseText = ta.value;
// support for XHR 'status' & 'statusText' emulation :
xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
} }
else if (scr) { else if (scr) {
// account for browsers injecting pre around json response // account for browsers injecting pre around json response
@ -381,40 +454,54 @@ $.fn.ajaxSubmit = function(options) {
else if (b) { else if (b) {
xhr.responseText = b.innerHTML; xhr.responseText = b.innerHTML;
} }
} }
} }
else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) { else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
xhr.responseXML = toXml(xhr.responseText); xhr.responseXML = toXml(xhr.responseText);
} }
data = httpData(xhr, s.dataType, s); try {
data = httpData(xhr, s.dataType, s);
}
catch (e) {
status = 'parsererror';
xhr.error = errMsg = (e || status);
}
} }
catch(e){ catch (e) {
log('error caught:',e); log('error caught: ',e);
ok = false; status = 'error';
xhr.error = e; xhr.error = errMsg = (e || status);
s.error && s.error.call(s.context, xhr, 'error', e);
g && $.event.trigger("ajaxError", [xhr, s, e]);
}
if (xhr.aborted) {
log('upload aborted');
ok = false;
} }
if (xhr.aborted) {
log('upload aborted');
status = null;
}
if (xhr.status) { // we've set xhr.status
status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
}
// ordering of these callbacks/triggers is odd, but that's how $.ajax does it // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
if (ok) { if (status === 'success') {
s.success && s.success.call(s.context, data, 'success', xhr); s.success && s.success.call(s.context, data, 'success', xhr);
g && $.event.trigger("ajaxSuccess", [xhr, s]); g && $.event.trigger("ajaxSuccess", [xhr, s]);
} }
else if (status) {
if (errMsg == undefined)
errMsg = xhr.statusText;
s.error && s.error.call(s.context, xhr, status, errMsg);
g && $.event.trigger("ajaxError", [xhr, s, errMsg]);
}
g && $.event.trigger("ajaxComplete", [xhr, s]); g && $.event.trigger("ajaxComplete", [xhr, s]);
if (g && ! --$.active) { if (g && ! --$.active) {
$.event.trigger("ajaxStop"); $.event.trigger("ajaxStop");
} }
s.complete && s.complete.call(s.context, xhr, ok ? 'success' : 'error'); s.complete && s.complete.call(s.context, xhr, status);
callbackProcessed = true; callbackProcessed = true;
if (s.timeout) if (s.timeout)
@ -422,8 +509,8 @@ $.fn.ajaxSubmit = function(options) {
// clean up // clean up
setTimeout(function() { setTimeout(function() {
$io.removeData('form-plugin-onload'); if (!s.iframeTarget)
$io.remove(); $io.remove();
xhr.responseXML = null; xhr.responseXML = null;
}, 100); }, 100);
} }
@ -442,8 +529,9 @@ $.fn.ajaxSubmit = function(options) {
var parseJSON = $.parseJSON || function(s) { var parseJSON = $.parseJSON || function(s) {
return window['eval']('(' + s + ')'); return window['eval']('(' + s + ')');
}; };
var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4 var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
var ct = xhr.getResponseHeader('content-type') || '', var ct = xhr.getResponseHeader('content-type') || '',
xml = type === 'xml' || !type && ct.indexOf('xml') >= 0, xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
data = xml ? xhr.responseXML : xhr.responseText; data = xml ? xhr.responseXML : xhr.responseText;
@ -496,7 +584,7 @@ $.fn.ajaxForm = function(options) {
log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)')); log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
return this; return this;
} }
return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) { return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
e.preventDefault(); e.preventDefault();
@ -560,7 +648,7 @@ $.fn.formToArray = function(semantic) {
if (!els) { if (!els) {
return a; return a;
} }
var i,j,n,v,el,max,jmax; var i,j,n,v,el,max,jmax;
for(i=0, max=els.length; i < max; i++) { for(i=0, max=els.length; i < max; i++) {
el = els[i]; el = els[i];
@ -745,9 +833,10 @@ $.fn.clearForm = function() {
* Clears the selected form elements. * Clears the selected form elements.
*/ */
$.fn.clearFields = $.fn.clearInputs = function() { $.fn.clearFields = $.fn.clearInputs = function() {
var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
return this.each(function() { return this.each(function() {
var t = this.type, tag = this.tagName.toLowerCase(); var t = this.type, tag = this.tagName.toLowerCase();
if (t == 'text' || t == 'password' || tag == 'textarea') { if (re.test(t) || tag == 'textarea') {
this.value = ''; this.value = '';
} }
else if (t == 'checkbox' || t == 'radio') { else if (t == 'checkbox' || t == 'radio') {
@ -809,16 +898,13 @@ $.fn.selected = function(select) {
}; };
// helper fn for console logging // helper fn for console logging
// set $.fn.ajaxSubmit.debug to true to enable debug logging
function log() { function log() {
if ($.fn.ajaxSubmit.debug) { var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); if (window.console && window.console.log) {
if (window.console && window.console.log) { window.console.log(msg);
window.console.log(msg); }
} else if (window.opera && window.opera.postError) {
else if (window.opera && window.opera.postError) { window.opera.postError(msg);
window.opera.postError(msg);
}
} }
}; };

File diff suppressed because one or more lines are too long