PageSourceSearch

http://www.unionski.ca/_s/sttc/jquery.form.js

js unionski.ca collected 2026-10-04 13:43:08 UTC 28,038 bytes, 964 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.