PageSourceSearch

https://www.rockarsenal.ru/bitrix/templates/main/js/jquery.form.js

js rockarsenal.ru collected 2026-10-02 12:32:36 UTC 26,665 bytes, 909 lines download raw bytes

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