web/wp-includes/js/jquery/jquery.form.js
changeset 204 09a1c134465b
parent 194 32102edaa81b
equal deleted inserted replaced
203:f507feede89a 204:09a1c134465b
     6  * Examples and documentation at: http://malsup.com/jquery/form/
     6  * Examples and documentation at: http://malsup.com/jquery/form/
     7  * Dual licensed under the MIT and GPL licenses:
     7  * Dual licensed under the MIT and GPL licenses:
     8  *   http://www.opensource.org/licenses/mit-license.php
     8  *   http://www.opensource.org/licenses/mit-license.php
     9  *   http://www.gnu.org/licenses/gpl.html
     9  *   http://www.gnu.org/licenses/gpl.html
    10  */
    10  */
    11 (function(b){b.fn.ajaxSubmit=function(t){if(!this.length){a("ajaxSubmit: skipping submit process - no element selected");return this}if(typeof t=="function"){t={success:t}}var h=this.attr("action");var d=(typeof h==="string")?b.trim(h):"";if(d){d=(d.match(/^([^#]+)/)||[])[1]}d=d||window.location.href||"";t=b.extend(true,{url:d,success:b.ajaxSettings.success,type:this[0].getAttribute("method")||"GET",iframeSrc:/^https/i.test(window.location.href||"")?"javascript:false":"about:blank"},t);var u={};this.trigger("form-pre-serialize",[this,t,u]);if(u.veto){a("ajaxSubmit: submit vetoed via form-pre-serialize trigger");return this}if(t.beforeSerialize&&t.beforeSerialize(this,t)===false){a("ajaxSubmit: submit aborted via beforeSerialize callback");return this}var f,p,m=this.formToArray(t.semantic);if(t.data){t.extraData=t.data;for(f in t.data){if(t.data[f] instanceof Array){for(var i in t.data[f]){m.push({name:f,value:t.data[f][i]})}}else{p=t.data[f];p=b.isFunction(p)?p():p;m.push({name:f,value:p})}}}if(t.beforeSubmit&&t.beforeSubmit(m,this,t)===false){a("ajaxSubmit: submit aborted via beforeSubmit callback");return this}this.trigger("form-submit-validate",[m,this,t,u]);if(u.veto){a("ajaxSubmit: submit vetoed via form-submit-validate trigger");return this}var c=b.param(m);if(t.type.toUpperCase()=="GET"){t.url+=(t.url.indexOf("?")>=0?"&":"?")+c;t.data=null}else{t.data=c}var s=this,l=[];if(t.resetForm){l.push(function(){s.resetForm()})}if(t.clearForm){l.push(function(){s.clearForm()})}if(!t.dataType&&t.target){var r=t.success||function(){};l.push(function(n){var k=t.replaceTarget?"replaceWith":"html";b(t.target)[k](n).each(r,arguments)})}else{if(t.success){l.push(t.success)}}t.success=function(w,n,x){var v=t.context||t;for(var q=0,k=l.length;q<k;q++){l[q].apply(v,[w,n,x||s,s])}};var g=b("input:file",this).length>0;var e="multipart/form-data";var j=(s.attr("enctype")==e||s.attr("encoding")==e);if(t.iframe!==false&&(g||t.iframe||j)){if(t.closeKeepAlive){b.get(t.closeKeepAlive,o)}else{o()}}else{b.ajax(t)}this.trigger("form-submit-notify",[this,t]);return this;function o(){var v=s[0];if(b(":input[name=submit],:input[id=submit]",v).length){alert('Error: Form elements must not have name or id of "submit".');return}var D=b.extend(true,{},b.ajaxSettings,t);D.context=D.context||D;var G="jqFormIO"+(new Date().getTime()),A="_"+G;var x=b('<iframe id="'+G+'" name="'+G+'" src="'+D.iframeSrc+'" />');var B=x[0];x.css({position:"absolute",top:"-1000px",left:"-1000px"});var y={aborted:0,responseText:null,responseXML:null,status:0,statusText:"n/a",getAllResponseHeaders:function(){},getResponseHeader:function(){},setRequestHeader:function(){},abort:function(n){var O=(n==="timeout"?"timeout":"aborted");a("aborting upload... "+O);this.aborted=1;x.attr("src",D.iframeSrc);y.error=O;D.error&&D.error.call(D.context,y,O,O);K&&b.event.trigger("ajaxError",[y,D,O]);D.complete&&D.complete.call(D.context,y,O)}};var K=D.global;if(K&&!b.active++){b.event.trigger("ajaxStart")}if(K){b.event.trigger("ajaxSend",[y,D])}if(D.beforeSend&&D.beforeSend.call(D.context,y,D)===false){if(D.global){b.active--}return}if(y.aborted){return}var J=0,C;var z=v.clk;if(z){var H=z.name;if(H&&!z.disabled){D.extraData=D.extraData||{};D.extraData[H]=z.value;if(z.type=="image"){D.extraData[H+".x"]=v.clk_x;D.extraData[H+".y"]=v.clk_y}}}function I(){var Q=s.attr("target"),O=s.attr("action");v.setAttribute("target",G);if(v.getAttribute("method")!="POST"){v.setAttribute("method","POST")}if(v.getAttribute("action")!=D.url){v.setAttribute("action",D.url)}if(!D.skipEncodingOverride){s.attr({encoding:"multipart/form-data",enctype:"multipart/form-data"})}if(D.timeout){C=setTimeout(function(){J=true;F(true)},D.timeout)}var P=[];try{if(D.extraData){for(var R in D.extraData){P.push(b('<input type="hidden" name="'+R+'" value="'+D.extraData[R]+'" />').appendTo(v)[0])}}x.appendTo("body");B.attachEvent?B.attachEvent("onload",F):B.addEventListener("load",F,false);v.submit()}finally{v.setAttribute("action",O);if(Q){v.setAttribute("target",Q)}else{s.removeAttr("target")}b(P).remove()}}if(D.forceSync){I()}else{setTimeout(I,10)}var M,N,L=50,w;function F(T){if(y.aborted||w){return}if(T===true&&y){y.abort("timeout");return}var S=B.contentWindow?B.contentWindow.document:B.contentDocument?B.contentDocument:B.document;if(!S||S.location.href==D.iframeSrc){if(!J){return}}B.detachEvent?B.detachEvent("onload",F):B.removeEventListener("load",F,false);var P=true;try{if(J){throw"timeout"}var U=D.dataType=="xml"||S.XMLDocument||b.isXMLDoc(S);a("isXml="+U);if(!U&&window.opera&&(S.body==null||S.body.innerHTML=="")){if(--L){a("requeing onLoad callback, DOM not available");setTimeout(F,250);return}}y.responseText=S.body?S.body.innerHTML:S.documentElement?S.documentElement.innerHTML:null;y.responseXML=S.XMLDocument?S.XMLDocument:S;if(U){D.dataType="xml"}y.getResponseHeader=function(W){var V={"content-type":D.dataType};return V[W]};var R=/(json|script|text)/.test(D.dataType);if(R||D.textarea){var O=S.getElementsByTagName("textarea")[0];if(O){y.responseText=O.value}else{if(R){var Q=S.getElementsByTagName("pre")[0];var n=S.getElementsByTagName("body")[0];if(Q){y.responseText=Q.textContent}else{if(n){y.responseText=n.innerHTML}}}}}else{if(D.dataType=="xml"&&!y.responseXML&&y.responseText!=null){y.responseXML=E(y.responseText)}}M=k(y,D.dataType,D)}catch(T){a("error caught:",T);P=false;y.error=T;D.error&&D.error.call(D.context,y,"error",T);K&&b.event.trigger("ajaxError",[y,D,T])}if(y.aborted){a("upload aborted");P=false}if(P){D.success&&D.success.call(D.context,M,"success",y);K&&b.event.trigger("ajaxSuccess",[y,D])}K&&b.event.trigger("ajaxComplete",[y,D]);if(K&&!--b.active){b.event.trigger("ajaxStop")}D.complete&&D.complete.call(D.context,y,P?"success":"error");w=true;if(D.timeout){clearTimeout(C)}setTimeout(function(){x.removeData("form-plugin-onload");x.remove();y.responseXML=null},100)}var E=b.parseXML||function(n,O){if(window.ActiveXObject){O=new ActiveXObject("Microsoft.XMLDOM");O.async="false";O.loadXML(n)}else{O=(new DOMParser()).parseFromString(n,"text/xml")}return(O&&O.documentElement&&O.documentElement.nodeName!="parsererror")?O:null};var q=b.parseJSON||function(n){return window["eval"]("("+n+")")};var k=function(S,Q,P){var O=S.getResponseHeader("content-type")||"",n=Q==="xml"||!Q&&O.indexOf("xml")>=0,R=n?S.responseXML:S.responseText;if(n&&R.documentElement.nodeName==="parsererror"){b.error&&b.error("parsererror")}if(P&&P.dataFilter){R=P.dataFilter(R,Q)}if(typeof R==="string"){if(Q==="json"||!Q&&O.indexOf("json")>=0){R=q(R)}else{if(Q==="script"||!Q&&O.indexOf("javascript")>=0){b.globalEval(R)}}}return R}}};b.fn.ajaxForm=function(c){if(this.length===0){var d={s:this.selector,c:this.context};if(!b.isReady&&d.s){a("DOM not ready, queuing ajaxForm");b(function(){b(d.s,d.c).ajaxForm(c)});return this}a("terminating; zero elements found by selector"+(b.isReady?"":" (DOM not ready)"));return this}return this.ajaxFormUnbind().bind("submit.form-plugin",function(f){if(!f.isDefaultPrevented()){f.preventDefault();b(this).ajaxSubmit(c)}}).bind("click.form-plugin",function(j){var i=j.target;var g=b(i);if(!(g.is(":submit,input:image"))){var f=g.closest(":submit");if(f.length==0){return}i=f[0]}var h=this;h.clk=i;if(i.type=="image"){if(j.offsetX!=undefined){h.clk_x=j.offsetX;h.clk_y=j.offsetY}else{if(typeof b.fn.offset=="function"){var k=g.offset();h.clk_x=j.pageX-k.left;h.clk_y=j.pageY-k.top}else{h.clk_x=j.pageX-i.offsetLeft;h.clk_y=j.pageY-i.offsetTop}}}setTimeout(function(){h.clk=h.clk_x=h.clk_y=null},100)})};b.fn.ajaxFormUnbind=function(){return this.unbind("submit.form-plugin click.form-plugin")};b.fn.formToArray=function(q){var p=[];if(this.length===0){return p}var d=this[0];var g=q?d.getElementsByTagName("*"):d.elements;if(!g){return p}var k,h,f,r,e,m,c;for(k=0,m=g.length;k<m;k++){e=g[k];f=e.name;if(!f){continue}if(q&&d.clk&&e.type=="image"){if(!e.disabled&&d.clk==e){p.push({name:f,value:b(e).val()});p.push({name:f+".x",value:d.clk_x},{name:f+".y",value:d.clk_y})}continue}r=b.fieldValue(e,true);if(r&&r.constructor==Array){for(h=0,c=r.length;h<c;h++){p.push({name:f,value:r[h]})}}else{if(r!==null&&typeof r!="undefined"){p.push({name:f,value:r})}}}if(!q&&d.clk){var l=b(d.clk),o=l[0];f=o.name;if(f&&!o.disabled&&o.type=="image"){p.push({name:f,value:l.val()});p.push({name:f+".x",value:d.clk_x},{name:f+".y",value:d.clk_y})}}return p};b.fn.formSerialize=function(c){return b.param(this.formToArray(c))};b.fn.fieldSerialize=function(d){var c=[];this.each(function(){var h=this.name;if(!h){return}var f=b.fieldValue(this,d);if(f&&f.constructor==Array){for(var g=0,e=f.length;g<e;g++){c.push({name:h,value:f[g]})}}else{if(f!==null&&typeof f!="undefined"){c.push({name:this.name,value:f})}}});return b.param(c)};b.fn.fieldValue=function(h){for(var g=[],e=0,c=this.length;e<c;e++){var f=this[e];var d=b.fieldValue(f,h);if(d===null||typeof d=="undefined"||(d.constructor==Array&&!d.length)){continue}d.constructor==Array?b.merge(g,d):g.push(d)}return g};b.fieldValue=function(c,j){var e=c.name,p=c.type,q=c.tagName.toLowerCase();if(j===undefined){j=true}if(j&&(!e||c.disabled||p=="reset"||p=="button"||(p=="checkbox"||p=="radio")&&!c.checked||(p=="submit"||p=="image")&&c.form&&c.form.clk!=c||q=="select"&&c.selectedIndex==-1)){return null}if(q=="select"){var k=c.selectedIndex;if(k<0){return null}var m=[],d=c.options;var g=(p=="select-one");var l=(g?k+1:d.length);for(var f=(g?k:0);f<l;f++){var h=d[f];if(h.selected){var o=h.value;if(!o){o=(h.attributes&&h.attributes.value&&!(h.attributes.value.specified))?h.text:h.value}if(g){return o}m.push(o)}}return m}return b(c).val()};b.fn.clearForm=function(){return this.each(function(){b("input,select,textarea",this).clearFields()})};b.fn.clearFields=b.fn.clearInputs=function(){return this.each(function(){var d=this.type,c=this.tagName.toLowerCase();if(d=="text"||d=="password"||c=="textarea"){this.value=""}else{if(d=="checkbox"||d=="radio"){this.checked=false}else{if(c=="select"){this.selectedIndex=-1}}}})};b.fn.resetForm=function(){return this.each(function(){if(typeof this.reset=="function"||(typeof this.reset=="object"&&!this.reset.nodeType)){this.reset()}})};b.fn.enable=function(c){if(c===undefined){c=true}return this.each(function(){this.disabled=!c})};b.fn.selected=function(c){if(c===undefined){c=true}return this.each(function(){var d=this.type;if(d=="checkbox"||d=="radio"){this.checked=c}else{if(this.tagName.toLowerCase()=="option"){var e=b(this).parent("select");if(c&&e[0]&&e[0].type=="select-one"){e.find("option").selected(false)}this.selected=c}}})};function a(){if(b.fn.ajaxSubmit.debug){var c="[jquery.form] "+Array.prototype.join.call(arguments,"");if(window.console&&window.console.log){window.console.log(c)}else{if(window.opera&&window.opera.postError){window.opera.postError(c)}}}}})(jQuery);
    11 ;(function($) {
       
    12 
       
    13 /*
       
    14 	Usage Note:
       
    15 	-----------
       
    16 	Do not use both ajaxSubmit and ajaxForm on the same form.  These
       
    17 	functions are intended to be exclusive.  Use ajaxSubmit if you want
       
    18 	to bind your own submit handler to the form.  For example,
       
    19 
       
    20 	$(document).ready(function() {
       
    21 		$('#myForm').bind('submit', function(e) {
       
    22 			e.preventDefault(); // <-- important
       
    23 			$(this).ajaxSubmit({
       
    24 				target: '#output'
       
    25 			});
       
    26 		});
       
    27 	});
       
    28 
       
    29 	Use ajaxForm when you want the plugin to manage all the event binding
       
    30 	for you.  For example,
       
    31 
       
    32 	$(document).ready(function() {
       
    33 		$('#myForm').ajaxForm({
       
    34 			target: '#output'
       
    35 		});
       
    36 	});
       
    37 
       
    38 	When using ajaxForm, the ajaxSubmit function will be invoked for you
       
    39 	at the appropriate time.
       
    40 */
       
    41 
       
    42 /**
       
    43  * ajaxSubmit() provides a mechanism for immediately submitting
       
    44  * an HTML form using AJAX.
       
    45  */
       
    46 $.fn.ajaxSubmit = function(options) {
       
    47 	// fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
       
    48 	if (!this.length) {
       
    49 		log('ajaxSubmit: skipping submit process - no element selected');
       
    50 		return this;
       
    51 	}
       
    52 
       
    53 	if (typeof options == 'function') {
       
    54 		options = { success: options };
       
    55 	}
       
    56 
       
    57 	var action = this.attr('action');
       
    58 	var url = (typeof action === 'string') ? $.trim(action) : '';
       
    59 	if (url) {
       
    60 		// clean url (don't include hash vaue)
       
    61 		url = (url.match(/^([^#]+)/)||[])[1];
       
    62 	}
       
    63 	url = url || window.location.href || '';
       
    64 
       
    65 	options = $.extend(true, {
       
    66 		url:  url,
       
    67 		success: $.ajaxSettings.success,
       
    68 		type: this[0].getAttribute('method') || 'GET', // IE7 massage (see issue 57)
       
    69 		iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
       
    70 	}, options);
       
    71 
       
    72 	// hook for manipulating the form data before it is extracted;
       
    73 	// convenient for use with rich editors like tinyMCE or FCKEditor
       
    74 	var veto = {};
       
    75 	this.trigger('form-pre-serialize', [this, options, veto]);
       
    76 	if (veto.veto) {
       
    77 		log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
       
    78 		return this;
       
    79 	}
       
    80 
       
    81 	// provide opportunity to alter form data before it is serialized
       
    82 	if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
       
    83 		log('ajaxSubmit: submit aborted via beforeSerialize callback');
       
    84 		return this;
       
    85 	}
       
    86 
       
    87 	var n,v,a = this.formToArray(options.semantic);
       
    88 	if (options.data) {
       
    89 		options.extraData = options.data;
       
    90 		for (n in options.data) {
       
    91 			if(options.data[n] instanceof Array) {
       
    92 				for (var k in options.data[n]) {
       
    93 					a.push( { name: n, value: options.data[n][k] } );
       
    94 				}
       
    95 			}
       
    96 			else {
       
    97 				v = options.data[n];
       
    98 				v = $.isFunction(v) ? v() : v; // if value is fn, invoke it
       
    99 				a.push( { name: n, value: v } );
       
   100 			}
       
   101 		}
       
   102 	}
       
   103 
       
   104 	// give pre-submit callback an opportunity to abort the submit
       
   105 	if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
       
   106 		log('ajaxSubmit: submit aborted via beforeSubmit callback');
       
   107 		return this;
       
   108 	}
       
   109 
       
   110 	// fire vetoable 'validate' event
       
   111 	this.trigger('form-submit-validate', [a, this, options, veto]);
       
   112 	if (veto.veto) {
       
   113 		log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
       
   114 		return this;
       
   115 	}
       
   116 
       
   117 	var q = $.param(a);
       
   118 
       
   119 	if (options.type.toUpperCase() == 'GET') {
       
   120 		options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
       
   121 		options.data = null;  // data is null for 'get'
       
   122 	}
       
   123 	else {
       
   124 		options.data = q; // data is the query string for 'post'
       
   125 	}
       
   126 
       
   127 	var $form = this, callbacks = [];
       
   128 	if (options.resetForm) {
       
   129 		callbacks.push(function() { $form.resetForm(); });
       
   130 	}
       
   131 	if (options.clearForm) {
       
   132 		callbacks.push(function() { $form.clearForm(); });
       
   133 	}
       
   134 
       
   135 	// perform a load on the target only if dataType is not provided
       
   136 	if (!options.dataType && options.target) {
       
   137 		var oldSuccess = options.success || function(){};
       
   138 		callbacks.push(function(data) {
       
   139 			var fn = options.replaceTarget ? 'replaceWith' : 'html';
       
   140 			$(options.target)[fn](data).each(oldSuccess, arguments);
       
   141 		});
       
   142 	}
       
   143 	else if (options.success) {
       
   144 		callbacks.push(options.success);
       
   145 	}
       
   146 
       
   147 	options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
       
   148 		var context = options.context || options;   // jQuery 1.4+ supports scope context
       
   149 		for (var i=0, max=callbacks.length; i < max; i++) {
       
   150 			callbacks[i].apply(context, [data, status, xhr || $form, $form]);
       
   151 		}
       
   152 	};
       
   153 
       
   154 	// are there files to upload?
       
   155 	var fileInputs = $('input:file', this).length > 0;
       
   156 	var mp = 'multipart/form-data';
       
   157 	var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
       
   158 
       
   159 	// options.iframe allows user to force iframe mode
       
   160 	// 06-NOV-09: now defaulting to iframe mode if file input is detected
       
   161    if (options.iframe !== false && (fileInputs || options.iframe || multipart)) {
       
   162 	   // hack to fix Safari hang (thanks to Tim Molendijk for this)
       
   163 	   // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
       
   164 	   if (options.closeKeepAlive) {
       
   165 		   $.get(options.closeKeepAlive, fileUpload);
       
   166 		}
       
   167 	   else {
       
   168 		   fileUpload();
       
   169 		}
       
   170    }
       
   171    else {
       
   172 		$.ajax(options);
       
   173    }
       
   174 
       
   175 	// fire 'notify' event
       
   176 	this.trigger('form-submit-notify', [this, options]);
       
   177 	return this;
       
   178 
       
   179 
       
   180 	// private function for handling file uploads (hat tip to YAHOO!)
       
   181 	function fileUpload() {
       
   182 		var form = $form[0];
       
   183 
       
   184 		if ($(':input[name=submit],:input[id=submit]', form).length) {
       
   185 			// if there is an input with a name or id of 'submit' then we won't be
       
   186 			// able to invoke the submit fn on the form (at least not x-browser)
       
   187 			alert('Error: Form elements must not have name or id of "submit".');
       
   188 			return;
       
   189 		}
       
   190 
       
   191 		var s = $.extend(true, {}, $.ajaxSettings, options);
       
   192 		s.context = s.context || s;
       
   193 		var id = 'jqFormIO' + (new Date().getTime()), fn = '_'+id;
       
   194 		var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ s.iframeSrc +'" />');
       
   195 		var io = $io[0];
       
   196 
       
   197 		$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
       
   198 
       
   199 		var xhr = { // mock object
       
   200 			aborted: 0,
       
   201 			responseText: null,
       
   202 			responseXML: null,
       
   203 			status: 0,
       
   204 			statusText: 'n/a',
       
   205 			getAllResponseHeaders: function() {},
       
   206 			getResponseHeader: function() {},
       
   207 			setRequestHeader: function() {},
       
   208 			abort: function(status) {
       
   209 				var e = (status === 'timeout' ? 'timeout' : 'aborted');
       
   210 				log('aborting upload... ' + e);
       
   211 				this.aborted = 1;
       
   212 				$io.attr('src', s.iframeSrc); // abort op in progress
       
   213 				xhr.error = e;
       
   214 				s.error && s.error.call(s.context, xhr, e, e);
       
   215 				g && $.event.trigger("ajaxError", [xhr, s, e]);
       
   216 				s.complete && s.complete.call(s.context, xhr, e);
       
   217 			}
       
   218 		};
       
   219 
       
   220 		var g = s.global;
       
   221 		// trigger ajax global events so that activity/block indicators work like normal
       
   222 		if (g && ! $.active++) {
       
   223 			$.event.trigger("ajaxStart");
       
   224 		}
       
   225 		if (g) {
       
   226 			$.event.trigger("ajaxSend", [xhr, s]);
       
   227 		}
       
   228 
       
   229 		if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
       
   230 			if (s.global) {
       
   231 				$.active--;
       
   232 			}
       
   233 			return;
       
   234 		}
       
   235 		if (xhr.aborted) {
       
   236 			return;
       
   237 		}
       
   238 
       
   239 		var timedOut = 0, timeoutHandle;
       
   240 
       
   241 		// add submitting element to data if we know it
       
   242 		var sub = form.clk;
       
   243 		if (sub) {
       
   244 			var n = sub.name;
       
   245 			if (n && !sub.disabled) {
       
   246 				s.extraData = s.extraData || {};
       
   247 				s.extraData[n] = sub.value;
       
   248 				if (sub.type == "image") {
       
   249 					s.extraData[n+'.x'] = form.clk_x;
       
   250 					s.extraData[n+'.y'] = form.clk_y;
       
   251 				}
       
   252 			}
       
   253 		}
       
   254 
       
   255 		// take a breath so that pending repaints get some cpu time before the upload starts
       
   256 		function doSubmit() {
       
   257 			// make sure form attrs are set
       
   258 			var t = $form.attr('target'), a = $form.attr('action');
       
   259 
       
   260 			// update form attrs in IE friendly way
       
   261 			form.setAttribute('target',id);
       
   262 			if (form.getAttribute('method') != 'POST') {
       
   263 				form.setAttribute('method', 'POST');
       
   264 			}
       
   265 			if (form.getAttribute('action') != s.url) {
       
   266 				form.setAttribute('action', s.url);
       
   267 			}
       
   268 
       
   269 			// ie borks in some cases when setting encoding
       
   270 			if (! s.skipEncodingOverride) {
       
   271 				$form.attr({
       
   272 					encoding: 'multipart/form-data',
       
   273 					enctype:  'multipart/form-data'
       
   274 				});
       
   275 			}
       
   276 
       
   277 			// support timout
       
   278 			if (s.timeout) {
       
   279 				timeoutHandle = setTimeout(function() { timedOut = true; cb(true); }, s.timeout);
       
   280 			}
       
   281 
       
   282 			// add "extra" data to form if provided in options
       
   283 			var extraInputs = [];
       
   284 			try {
       
   285 				if (s.extraData) {
       
   286 					for (var n in s.extraData) {
       
   287 						extraInputs.push(
       
   288 							$('<input type="hidden" name="'+n+'" value="'+s.extraData[n]+'" />')
       
   289 								.appendTo(form)[0]);
       
   290 					}
       
   291 				}
       
   292 
       
   293 				// add iframe to doc and submit the form
       
   294 				$io.appendTo('body');
       
   295                 io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
       
   296 				form.submit();
       
   297 			}
       
   298 			finally {
       
   299 				// reset attrs and remove "extra" input elements
       
   300 				form.setAttribute('action',a);
       
   301 				if(t) {
       
   302 					form.setAttribute('target', t);
       
   303 				} else {
       
   304 					$form.removeAttr('target');
       
   305 				}
       
   306 				$(extraInputs).remove();
       
   307 			}
       
   308 		}
       
   309 
       
   310 		if (s.forceSync) {
       
   311 			doSubmit();
       
   312 		}
       
   313 		else {
       
   314 			setTimeout(doSubmit, 10); // this lets dom updates render
       
   315 		}
       
   316 
       
   317 		var data, doc, domCheckCount = 50, callbackProcessed;
       
   318 
       
   319 		function cb(e) {
       
   320 			if (xhr.aborted || callbackProcessed) {
       
   321 				return;
       
   322 			}
       
   323 			if (e === true && xhr) {
       
   324 				xhr.abort('timeout');
       
   325 				return;
       
   326 			}
       
   327 
       
   328 			var doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
       
   329 			if (!doc || doc.location.href == s.iframeSrc) {
       
   330 				// response not received yet
       
   331 				if (!timedOut)
       
   332 					return;
       
   333 			}
       
   334             io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
       
   335 
       
   336 			var ok = true;
       
   337 			try {
       
   338 				if (timedOut) {
       
   339 					throw 'timeout';
       
   340 				}
       
   341 
       
   342 				var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
       
   343 				log('isXml='+isXml);
       
   344 				if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) {
       
   345 					if (--domCheckCount) {
       
   346 						// in some browsers (Opera) the iframe DOM is not always traversable when
       
   347 						// the onload callback fires, so we loop a bit to accommodate
       
   348 						log('requeing onLoad callback, DOM not available');
       
   349 						setTimeout(cb, 250);
       
   350 						return;
       
   351 					}
       
   352 					// let this fall through because server response could be an empty document
       
   353 					//log('Could not access iframe DOM after mutiple tries.');
       
   354 					//throw 'DOMException: not available';
       
   355 				}
       
   356 
       
   357 				//log('response detected');
       
   358 				xhr.responseText = doc.body ? doc.body.innerHTML : doc.documentElement ? doc.documentElement.innerHTML : null;
       
   359 				xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
       
   360 				if (isXml)
       
   361 					s.dataType = 'xml';
       
   362 				xhr.getResponseHeader = function(header){
       
   363 					var headers = {'content-type': s.dataType};
       
   364 					return headers[header];
       
   365 				};
       
   366 
       
   367 				var scr = /(json|script|text)/.test(s.dataType);
       
   368 				if (scr || s.textarea) {
       
   369 					// see if user embedded response in textarea
       
   370 					var ta = doc.getElementsByTagName('textarea')[0];
       
   371 					if (ta) {
       
   372 						xhr.responseText = ta.value;
       
   373 					}
       
   374 					else if (scr) {
       
   375 						// account for browsers injecting pre around json response
       
   376 						var pre = doc.getElementsByTagName('pre')[0];
       
   377 						var b = doc.getElementsByTagName('body')[0];
       
   378 						if (pre) {
       
   379 							xhr.responseText = pre.textContent;
       
   380 						}
       
   381 						else if (b) {
       
   382 							xhr.responseText = b.innerHTML;
       
   383 						}
       
   384 					}
       
   385 				}
       
   386 				else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
       
   387 					xhr.responseXML = toXml(xhr.responseText);
       
   388 				}
       
   389 
       
   390 				data = httpData(xhr, s.dataType, s);
       
   391 			}
       
   392 			catch(e){
       
   393 				log('error caught:',e);
       
   394 				ok = false;
       
   395 				xhr.error = e;
       
   396 				s.error && s.error.call(s.context, xhr, 'error', e);
       
   397 				g && $.event.trigger("ajaxError", [xhr, s, e]);
       
   398 			}
       
   399 
       
   400 			if (xhr.aborted) {
       
   401 				log('upload aborted');
       
   402 				ok = false;
       
   403 			}
       
   404 
       
   405 			// ordering of these callbacks/triggers is odd, but that's how $.ajax does it
       
   406 			if (ok) {
       
   407 				s.success && s.success.call(s.context, data, 'success', xhr);
       
   408 				g && $.event.trigger("ajaxSuccess", [xhr, s]);
       
   409 			}
       
   410 
       
   411 			g && $.event.trigger("ajaxComplete", [xhr, s]);
       
   412 
       
   413 			if (g && ! --$.active) {
       
   414 				$.event.trigger("ajaxStop");
       
   415 			}
       
   416 
       
   417 			s.complete && s.complete.call(s.context, xhr, ok ? 'success' : 'error');
       
   418 
       
   419 			callbackProcessed = true;
       
   420 			if (s.timeout)
       
   421 				clearTimeout(timeoutHandle);
       
   422 
       
   423 			// clean up
       
   424 			setTimeout(function() {
       
   425 				$io.removeData('form-plugin-onload');
       
   426 				$io.remove();
       
   427 				xhr.responseXML = null;
       
   428 			}, 100);
       
   429 		}
       
   430 
       
   431 		var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
       
   432 			if (window.ActiveXObject) {
       
   433 				doc = new ActiveXObject('Microsoft.XMLDOM');
       
   434 				doc.async = 'false';
       
   435 				doc.loadXML(s);
       
   436 			}
       
   437 			else {
       
   438 				doc = (new DOMParser()).parseFromString(s, 'text/xml');
       
   439 			}
       
   440 			return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
       
   441 		};
       
   442 		var parseJSON = $.parseJSON || function(s) {
       
   443 			return window['eval']('(' + s + ')');
       
   444 		};
       
   445 
       
   446 		var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
       
   447 			var ct = xhr.getResponseHeader('content-type') || '',
       
   448 				xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
       
   449 				data = xml ? xhr.responseXML : xhr.responseText;
       
   450 
       
   451 			if (xml && data.documentElement.nodeName === 'parsererror') {
       
   452 				$.error && $.error('parsererror');
       
   453 			}
       
   454 			if (s && s.dataFilter) {
       
   455 				data = s.dataFilter(data, type);
       
   456 			}
       
   457 			if (typeof data === 'string') {
       
   458 				if (type === 'json' || !type && ct.indexOf('json') >= 0) {
       
   459 					data = parseJSON(data);
       
   460 				} else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
       
   461 					$.globalEval(data);
       
   462 				}
       
   463 			}
       
   464 			return data;
       
   465 		};
       
   466 	}
       
   467 };
       
   468 
       
   469 /**
       
   470  * ajaxForm() provides a mechanism for fully automating form submission.
       
   471  *
       
   472  * The advantages of using this method instead of ajaxSubmit() are:
       
   473  *
       
   474  * 1: This method will include coordinates for <input type="image" /> elements (if the element
       
   475  *	is used to submit the form).
       
   476  * 2. This method will include the submit element's name/value data (for the element that was
       
   477  *	used to submit the form).
       
   478  * 3. This method binds the submit() method to the form for you.
       
   479  *
       
   480  * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
       
   481  * passes the options argument along after properly binding events for submit elements and
       
   482  * the form itself.
       
   483  */
       
   484 $.fn.ajaxForm = function(options) {
       
   485 	// in jQuery 1.3+ we can fix mistakes with the ready state
       
   486 	if (this.length === 0) {
       
   487 		var o = { s: this.selector, c: this.context };
       
   488 		if (!$.isReady && o.s) {
       
   489 			log('DOM not ready, queuing ajaxForm');
       
   490 			$(function() {
       
   491 				$(o.s,o.c).ajaxForm(options);
       
   492 			});
       
   493 			return this;
       
   494 		}
       
   495 		// is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
       
   496 		log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
       
   497 		return this;
       
   498 	}
       
   499 
       
   500 	return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
       
   501 		if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
       
   502 			e.preventDefault();
       
   503 			$(this).ajaxSubmit(options);
       
   504 		}
       
   505 	}).bind('click.form-plugin', function(e) {
       
   506 		var target = e.target;
       
   507 		var $el = $(target);
       
   508 		if (!($el.is(":submit,input:image"))) {
       
   509 			// is this a child element of the submit el?  (ex: a span within a button)
       
   510 			var t = $el.closest(':submit');
       
   511 			if (t.length == 0) {
       
   512 				return;
       
   513 			}
       
   514 			target = t[0];
       
   515 		}
       
   516 		var form = this;
       
   517 		form.clk = target;
       
   518 		if (target.type == 'image') {
       
   519 			if (e.offsetX != undefined) {
       
   520 				form.clk_x = e.offsetX;
       
   521 				form.clk_y = e.offsetY;
       
   522 			} else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
       
   523 				var offset = $el.offset();
       
   524 				form.clk_x = e.pageX - offset.left;
       
   525 				form.clk_y = e.pageY - offset.top;
       
   526 			} else {
       
   527 				form.clk_x = e.pageX - target.offsetLeft;
       
   528 				form.clk_y = e.pageY - target.offsetTop;
       
   529 			}
       
   530 		}
       
   531 		// clear form vars
       
   532 		setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
       
   533 	});
       
   534 };
       
   535 
       
   536 // ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
       
   537 $.fn.ajaxFormUnbind = function() {
       
   538 	return this.unbind('submit.form-plugin click.form-plugin');
       
   539 };
       
   540 
       
   541 /**
       
   542  * formToArray() gathers form element data into an array of objects that can
       
   543  * be passed to any of the following ajax functions: $.get, $.post, or load.
       
   544  * Each object in the array has both a 'name' and 'value' property.  An example of
       
   545  * an array for a simple login form might be:
       
   546  *
       
   547  * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
       
   548  *
       
   549  * It is this array that is passed to pre-submit callback functions provided to the
       
   550  * ajaxSubmit() and ajaxForm() methods.
       
   551  */
       
   552 $.fn.formToArray = function(semantic) {
       
   553 	var a = [];
       
   554 	if (this.length === 0) {
       
   555 		return a;
       
   556 	}
       
   557 
       
   558 	var form = this[0];
       
   559 	var els = semantic ? form.getElementsByTagName('*') : form.elements;
       
   560 	if (!els) {
       
   561 		return a;
       
   562 	}
       
   563 
       
   564 	var i,j,n,v,el,max,jmax;
       
   565 	for(i=0, max=els.length; i < max; i++) {
       
   566 		el = els[i];
       
   567 		n = el.name;
       
   568 		if (!n) {
       
   569 			continue;
       
   570 		}
       
   571 
       
   572 		if (semantic && form.clk && el.type == "image") {
       
   573 			// handle image inputs on the fly when semantic == true
       
   574 			if(!el.disabled && form.clk == el) {
       
   575 				a.push({name: n, value: $(el).val()});
       
   576 				a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
       
   577 			}
       
   578 			continue;
       
   579 		}
       
   580 
       
   581 		v = $.fieldValue(el, true);
       
   582 		if (v && v.constructor == Array) {
       
   583 			for(j=0, jmax=v.length; j < jmax; j++) {
       
   584 				a.push({name: n, value: v[j]});
       
   585 			}
       
   586 		}
       
   587 		else if (v !== null && typeof v != 'undefined') {
       
   588 			a.push({name: n, value: v});
       
   589 		}
       
   590 	}
       
   591 
       
   592 	if (!semantic && form.clk) {
       
   593 		// input type=='image' are not found in elements array! handle it here
       
   594 		var $input = $(form.clk), input = $input[0];
       
   595 		n = input.name;
       
   596 		if (n && !input.disabled && input.type == 'image') {
       
   597 			a.push({name: n, value: $input.val()});
       
   598 			a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
       
   599 		}
       
   600 	}
       
   601 	return a;
       
   602 };
       
   603 
       
   604 /**
       
   605  * Serializes form data into a 'submittable' string. This method will return a string
       
   606  * in the format: name1=value1&amp;name2=value2
       
   607  */
       
   608 $.fn.formSerialize = function(semantic) {
       
   609 	//hand off to jQuery.param for proper encoding
       
   610 	return $.param(this.formToArray(semantic));
       
   611 };
       
   612 
       
   613 /**
       
   614  * Serializes all field elements in the jQuery object into a query string.
       
   615  * This method will return a string in the format: name1=value1&amp;name2=value2
       
   616  */
       
   617 $.fn.fieldSerialize = function(successful) {
       
   618 	var a = [];
       
   619 	this.each(function() {
       
   620 		var n = this.name;
       
   621 		if (!n) {
       
   622 			return;
       
   623 		}
       
   624 		var v = $.fieldValue(this, successful);
       
   625 		if (v && v.constructor == Array) {
       
   626 			for (var i=0,max=v.length; i < max; i++) {
       
   627 				a.push({name: n, value: v[i]});
       
   628 			}
       
   629 		}
       
   630 		else if (v !== null && typeof v != 'undefined') {
       
   631 			a.push({name: this.name, value: v});
       
   632 		}
       
   633 	});
       
   634 	//hand off to jQuery.param for proper encoding
       
   635 	return $.param(a);
       
   636 };
       
   637 
       
   638 /**
       
   639  * Returns the value(s) of the element in the matched set.  For example, consider the following form:
       
   640  *
       
   641  *  <form><fieldset>
       
   642  *	  <input name="A" type="text" />
       
   643  *	  <input name="A" type="text" />
       
   644  *	  <input name="B" type="checkbox" value="B1" />
       
   645  *	  <input name="B" type="checkbox" value="B2"/>
       
   646  *	  <input name="C" type="radio" value="C1" />
       
   647  *	  <input name="C" type="radio" value="C2" />
       
   648  *  </fieldset></form>
       
   649  *
       
   650  *  var v = $(':text').fieldValue();
       
   651  *  // if no values are entered into the text inputs
       
   652  *  v == ['','']
       
   653  *  // if values entered into the text inputs are 'foo' and 'bar'
       
   654  *  v == ['foo','bar']
       
   655  *
       
   656  *  var v = $(':checkbox').fieldValue();
       
   657  *  // if neither checkbox is checked
       
   658  *  v === undefined
       
   659  *  // if both checkboxes are checked
       
   660  *  v == ['B1', 'B2']
       
   661  *
       
   662  *  var v = $(':radio').fieldValue();
       
   663  *  // if neither radio is checked
       
   664  *  v === undefined
       
   665  *  // if first radio is checked
       
   666  *  v == ['C1']
       
   667  *
       
   668  * The successful argument controls whether or not the field element must be 'successful'
       
   669  * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
       
   670  * The default value of the successful argument is true.  If this value is false the value(s)
       
   671  * for each element is returned.
       
   672  *
       
   673  * Note: This method *always* returns an array.  If no valid value can be determined the
       
   674  *	   array will be empty, otherwise it will contain one or more values.
       
   675  */
       
   676 $.fn.fieldValue = function(successful) {
       
   677 	for (var val=[], i=0, max=this.length; i < max; i++) {
       
   678 		var el = this[i];
       
   679 		var v = $.fieldValue(el, successful);
       
   680 		if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
       
   681 			continue;
       
   682 		}
       
   683 		v.constructor == Array ? $.merge(val, v) : val.push(v);
       
   684 	}
       
   685 	return val;
       
   686 };
       
   687 
       
   688 /**
       
   689  * Returns the value of the field element.
       
   690  */
       
   691 $.fieldValue = function(el, successful) {
       
   692 	var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
       
   693 	if (successful === undefined) {
       
   694 		successful = true;
       
   695 	}
       
   696 
       
   697 	if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
       
   698 		(t == 'checkbox' || t == 'radio') && !el.checked ||
       
   699 		(t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
       
   700 		tag == 'select' && el.selectedIndex == -1)) {
       
   701 			return null;
       
   702 	}
       
   703 
       
   704 	if (tag == 'select') {
       
   705 		var index = el.selectedIndex;
       
   706 		if (index < 0) {
       
   707 			return null;
       
   708 		}
       
   709 		var a = [], ops = el.options;
       
   710 		var one = (t == 'select-one');
       
   711 		var max = (one ? index+1 : ops.length);
       
   712 		for(var i=(one ? index : 0); i < max; i++) {
       
   713 			var op = ops[i];
       
   714 			if (op.selected) {
       
   715 				var v = op.value;
       
   716 				if (!v) { // extra pain for IE...
       
   717 					v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
       
   718 				}
       
   719 				if (one) {
       
   720 					return v;
       
   721 				}
       
   722 				a.push(v);
       
   723 			}
       
   724 		}
       
   725 		return a;
       
   726 	}
       
   727 	return $(el).val();
       
   728 };
       
   729 
       
   730 /**
       
   731  * Clears the form data.  Takes the following actions on the form's input fields:
       
   732  *  - input text fields will have their 'value' property set to the empty string
       
   733  *  - select elements will have their 'selectedIndex' property set to -1
       
   734  *  - checkbox and radio inputs will have their 'checked' property set to false
       
   735  *  - inputs of type submit, button, reset, and hidden will *not* be effected
       
   736  *  - button elements will *not* be effected
       
   737  */
       
   738 $.fn.clearForm = function() {
       
   739 	return this.each(function() {
       
   740 		$('input,select,textarea', this).clearFields();
       
   741 	});
       
   742 };
       
   743 
       
   744 /**
       
   745  * Clears the selected form elements.
       
   746  */
       
   747 $.fn.clearFields = $.fn.clearInputs = function() {
       
   748 	return this.each(function() {
       
   749 		var t = this.type, tag = this.tagName.toLowerCase();
       
   750 		if (t == 'text' || t == 'password' || tag == 'textarea') {
       
   751 			this.value = '';
       
   752 		}
       
   753 		else if (t == 'checkbox' || t == 'radio') {
       
   754 			this.checked = false;
       
   755 		}
       
   756 		else if (tag == 'select') {
       
   757 			this.selectedIndex = -1;
       
   758 		}
       
   759 	});
       
   760 };
       
   761 
       
   762 /**
       
   763  * Resets the form data.  Causes all form elements to be reset to their original value.
       
   764  */
       
   765 $.fn.resetForm = function() {
       
   766 	return this.each(function() {
       
   767 		// guard against an input with the name of 'reset'
       
   768 		// note that IE reports the reset function as an 'object'
       
   769 		if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
       
   770 			this.reset();
       
   771 		}
       
   772 	});
       
   773 };
       
   774 
       
   775 /**
       
   776  * Enables or disables any matching elements.
       
   777  */
       
   778 $.fn.enable = function(b) {
       
   779 	if (b === undefined) {
       
   780 		b = true;
       
   781 	}
       
   782 	return this.each(function() {
       
   783 		this.disabled = !b;
       
   784 	});
       
   785 };
       
   786 
       
   787 /**
       
   788  * Checks/unchecks any matching checkboxes or radio buttons and
       
   789  * selects/deselects and matching option elements.
       
   790  */
       
   791 $.fn.selected = function(select) {
       
   792 	if (select === undefined) {
       
   793 		select = true;
       
   794 	}
       
   795 	return this.each(function() {
       
   796 		var t = this.type;
       
   797 		if (t == 'checkbox' || t == 'radio') {
       
   798 			this.checked = select;
       
   799 		}
       
   800 		else if (this.tagName.toLowerCase() == 'option') {
       
   801 			var $sel = $(this).parent('select');
       
   802 			if (select && $sel[0] && $sel[0].type == 'select-one') {
       
   803 				// deselect all other options
       
   804 				$sel.find('option').selected(false);
       
   805 			}
       
   806 			this.selected = select;
       
   807 		}
       
   808 	});
       
   809 };
       
   810 
       
   811 // helper fn for console logging
       
   812 // set $.fn.ajaxSubmit.debug to true to enable debug logging
       
   813 function log() {
       
   814 	if ($.fn.ajaxSubmit.debug) {
       
   815 		var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
       
   816 		if (window.console && window.console.log) {
       
   817 			window.console.log(msg);
       
   818 		}
       
   819 		else if (window.opera && window.opera.postError) {
       
   820 			window.opera.postError(msg);
       
   821 		}
       
   822 	}
       
   823 };
       
   824 
       
   825 })(jQuery);