PageSourceSearch

https://collectie.hetnoordbrabantsmuseum.nl/Scripts/External/jquery.form.js

js hetnoordbrabantsmuseum.nl collected 2026-10-02 04:27:41 UTC 27,725 bytes, 912 lines download raw bytes

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