PageSourceSearch

https://designstory.ru/st/js/jquery/jquery.form.js?1253967395

js designstory.ru collected 2026-10-02 05:17:11 UTC 20,017 bytes, 653 lines download raw bytes

1/*
2 * jQuery Form Plugin
3 * version: 2.33 (22-SEP-2009)
4 * @requires jQuery v1.2.6 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() {
22			$(this).ajaxSubmit({
23				target: '#output'
24			});
25			return false; // <-- important!
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	var url = $.trim(this.attr('action'));
57	if (url) {
58		// clean url (don't include hash vaue)
59		url = (url.match(/^([^#]+)/)||[])[1];
60   	}
61   	url = url || window.location.href || '';
62
63	options = $.extend({
64		url:  url,
65		type: this.attr('method') || 'GET'
66	}, options || {});
67
68	// hook for manipulating the form data before it is extracted;
69	// convenient for use with rich editors like tinyMCE or FCKEditor
70	var veto = {};
71	this.trigger('form-pre-serialize', [this, options, veto]);
72	if (veto.veto) {
73		log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
74		return this;
75	}
76
77	// provide opportunity to alter form data before it is serialized
78	if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
79		log('ajaxSubmit: submit aborted via beforeSerialize callback');
80		return this;
81	}
82
83	var a = this.formToArray(options.semantic);
84	if (options.data) {
85		options.extraData = options.data;
86		for (var n in options.data) {
87		  if(options.data[n] instanceof Array) {
88			for (var k in options.data[n])
89			  a.push( { name: n, value: options.data[n][k] } );
90		  }
91		  else
92			 a.push( { name: n, value: options.data[n] } );
93		}
94	}
95
96	// give pre-submit callback an opportunity to abort the submit
97	if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
98		log('ajaxSubmit: submit aborted via beforeSubmit callback');
99		return this;
100	}
101
102	// fire vetoable 'validate' event
103	this.trigger('form-submit-validate', [a, this, options, veto]);
104	if (veto.veto) {
105		log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
106		return this;
107	}
108
109	var q = $.param(a);
110
111	if (options.type.toUpperCase() == 'GET') {
112		options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
113		options.data = null;  // data is null for 'get'
114	}
115	else
116		options.data = q; // data is the query string for 'post'
117
118	var $form = this, callbacks = [];
119	if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
120	if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
121
122	// perform a load on the target only if dataType is not provided
123	if (!options.dataType && options.target) {
124		var oldSuccess = options.success || function(){};
125		callbacks.push(function(data) {
126			$(options.target).html(data).each(oldSuccess, arguments);
127		});
128	}
129	else if (options.success)
130		callbacks.push(options.success);
131
132	options.success = function(data, status) {
133		for (var i=0, max=callbacks.length; i < max; i++)
134			callbacks[i].apply(options, [data, status, $form]);
135	};
136
137	// are there files to upload?
138	var files = $('input:file', this).fieldValue();
139	var found = false;
140	for (var j=0; j < files.length; j++)
141		if (files[j])
142			found = true;
143
144	var multipart = false;
145//	var mp = 'multipart/form-data';
146//	multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
147
148	// options.iframe allows user to force iframe mode
149   if (options.iframe || found || multipart) {
150	   // hack to fix Safari hang (thanks to Tim Molendijk for this)
151	   // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
152	   if (options.closeKeepAlive)
153		   $.get(options.closeKeepAlive, fileUpload);
154	   else
155		   fileUpload();
156	   }
157   else
158	   $.ajax(options);
159
160	// fire 'notify' event
161	this.trigger('form-submit-notify', [this, options]);
162	return this;
163
164
165	// private function for handling file uploads (hat tip to YAHOO!)
166	function fileUpload() {
167		var form = $form[0];
168
169		if ($(':input[name=submit]', form).length) {
170			alert('Error: Form elements must not be named "submit".');
171			return;
172		}
173
174		var opts = $.extend({}, $.ajaxSettings, options);
175		var s = $.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts);
176
177		var id = 'jqFormIO' + (new Date().getTime());
178		var $io = $('<iframe id="' + id + '" name="' + id + '" src="about:blank" />');
179		var io = $io[0];
180
181		$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
182
183		var xhr = { // mock object
184			aborted: 0,
185			responseText: null,
186			responseXML: null,
187			status: 0,
188			statusText: 'n/a',
189			getAllResponseHeaders: function() {},
190			getResponseHeader: function() {},
191			setRequestHeader: function() {},
192			abort: function() {
193				this.aborted = 1;
194				$io.attr('src','about:blank'); // abort op in progress
195			}
196		};
197
198		var g = opts.global;
199		// trigger ajax global events so that activity/block indicators work like normal
200		if (g && ! $.active++) $.event.trigger("ajaxStart");
201		if (g) $.event.trigger("ajaxSend", [xhr, opts]);
202
203		if (s.beforeSend && s.beforeSend(xhr, s) === false) {
204			s.global && $.active--;
205			return;
206		}
207		if (xhr.aborted)
208			return;
209
210		var cbInvoked = 0;
211		var timedOut = 0;
212
213		// add submitting element to data if we know it
214		var sub = form.clk;
215		if (sub) {
216			var n = sub.name;
217			if (n && !sub.disabled) {
218				options.extraData = options.extraData || {};
219				options.extraData[n] = sub.value;
220				if (sub.type == "image") {
221					options.extraData[name+'.x'] = form.clk_x;
222					options.extraData[name+'.y'] = form.clk_y;
223				}
224			}
225		}
226
227		// take a breath so that pending repaints get some cpu time before the upload starts
228		setTimeout(function() {
229			// make sure form attrs are set
230			var t = $form.attr('target'), a = $form.attr('action');
231
232			// update form attrs in IE friendly way
233			form.setAttribute('target',id);
234			if (form.getAttribute('method') != 'POST')
235				form.setAttribute('method', 'POST');
236			if (form.getAttribute('action') != opts.url)
237				form.setAttribute('action', opts.url);
238
239			// ie borks in some cases when setting encoding
240			if (! options.skipEncodingOverride) {
241				$form.attr({
242					encoding: 'multipart/form-data',
243					enctype:  'multipart/form-data'
244				});
245			}
246
247			// support timout
248			if (opts.timeout)
249				setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
250
251			// add "extra" data to form if provided in options
252			var extraInputs = [];
253			try {
254				if (options.extraData)
255					for (var n in options.extraData)
256						extraInputs.push(
257							$('<input type="hidden" name="'+n+'" value="'+options.extraData[n]+'" />')
258								.appendTo(form)[0]);
259
260				// add iframe to doc and submit the form
261				$io.appendTo('body');
262				io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
263				form.submit();
264			}
265			finally {
266				// reset attrs and remove "extra" input elements
267				form.setAttribute('action',a);
268				t ? form.setAttribute('target', t) : $form.removeAttr('target');
269				$(extraInputs).remove();
270			}
271		}, 10);
272
273		var domCheckCount = 50;
274
275		function cb() {
276			if (cbInvoked++) return;
277
278			io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
279
280			var ok = true;
281			try {
282				if (timedOut) throw 'timeout';
283				// extract the server response from the iframe
284				var data, doc;
285
286				doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
287				
288				var isXml = opts.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
289				log('isXml='+isXml);
290				if (!isXml && (doc.body == null || doc.body.innerHTML == '')) {
291				 	if (--domCheckCount) {
292						// in some browsers (Opera) the iframe DOM is not always traversable when
293						// the onload callback fires, so we loop a bit to accommodate
294						cbInvoked = 0;
295						setTimeout(cb, 100);
296						return;
297					}
298					log('Could not access iframe DOM after 50 tries.');
299					return;
300				}
301
302				xhr.responseText = doc.body ? doc.body.innerHTML : null;
303				xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
304				xhr.getResponseHeader = function(header){
305					var headers = {'content-type': opts.dataType};
306					return headers[header];
307				};
308
309				if (opts.dataType == 'json' || opts.dataType == 'script') {
310					// see if user embedded response in textarea
311					var ta = doc.getElementsByTagName('textarea')[0];
312					if (ta)
313						xhr.responseText = ta.value;
314					else {
315						// account for browsers injecting pre around json response
316						var pre = doc.getElementsByTagName('pre')[0];
317						if (pre)
318							xhr.responseText = pre.innerHTML;
319					}			  
320				}
321				else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
322					xhr.responseXML = toXml(xhr.responseText);
323				}
324				data = $.httpData(xhr, opts.dataType);
325			}
326			catch(e){
327				ok = false;
328				$.handleError(opts, xhr, 'error', e);
329			}
330
331			// ordering of these callbacks/triggers is odd, but that's how $.ajax does it
332			if (ok) {
333				opts.success(data, 'success');
334				if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
335			}
336			if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
337			if (g && ! --$.active) $.event.trigger("ajaxStop");
338			if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
339
340			// clean up
341			setTimeout(function() {
342				$io.remove();
343				xhr.responseXML = null;
344			}, 100);
345		};
346
347		function toXml(s, doc) {
348			if (window.ActiveXObject) {
349				doc = new ActiveXObject('Microsoft.XMLDOM');
350				doc.async = 'false';
351				doc.loadXML(s);
352			}
353			else
354				doc = (new DOMParser()).parseFromString(s, 'text/xml');
355			return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
356		};
357	};
358};
359
360/**
361 * ajaxForm() provides a mechanism for fully automating form submission.
362 *
363 * The advantages of using this method instead of ajaxSubmit() are:
364 *
365 * 1: This method will include coordinates for <input type="image" /> elements (if the element
366 *	is used to submit the form).
367 * 2. This method will include the submit element's name/value data (for the element that was
368 *	used to submit the form).
369 * 3. This method binds the submit() method to the form for you.
370 *
371 * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
372 * passes the options argument along after properly binding events for submit elements and
373 * the form itself.
374 */
375$.fn.ajaxForm = function(options) {
376	return this.ajaxFormUnbind().bind('submit.form-plugin', function() {
377		$(this).ajaxSubmit(options);
378		return false;
379	}).bind('click.form-plugin', function(e) {
380		var $el = $(e.target);
381		if (!($el.is(":submit,input:image"))) {
382			return;
383		}
384		var form = this;
385		form.clk = e.target;
386		if (e.target.type == 'image') {
387			if (e.offsetX != undefined) {
388				form.clk_x = e.offsetX;
389				form.clk_y = e.offsetY;
390			} else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
391				var offset = $el.offset();
392				form.clk_x = e.pageX - offset.left;
393				form.clk_y = e.pageY - offset.top;
394			} else {
395				form.clk_x = e.pageX - e.target.offsetLeft;
396				form.clk_y = e.pageY - e.target.offsetTop;
397			}
398		}
399		// clear form vars
400		setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 10);
401	});
402};
403
404// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
405$.fn.ajaxFormUnbind = function() {
406	return this.unbind('submit.form-plugin click.form-plugin');
407};
408
409/**
410 * formToArray() gathers form element data into an array of objects that can
411 * be passed to any of the following ajax functions: $.get, $.post, or load.
412 * Each object in the array has both a 'name' and 'value' property.  An example of
413 * an array for a simple login form might be:
414 *
415 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
416 *
417 * It is this array that is passed to pre-submit callback functions provided to the
418 * ajaxSubmit() and ajaxForm() methods.
419 */
420$.fn.formToArray = function(semantic) {
421	var a = [];
422	if (this.length == 0) return a;
423
424	var form = this[0];
425	var els = semantic ? form.getElementsByTagName('*') : form.elements;
426	if (!els) return a;
427	for(var i=0, max=els.length; i < max; i++) {
428		var el = els[i];
429		var n = el.name;
430		if (!n) continue;
431
432		if (semantic && form.clk && el.type == "image") {
433			// handle image inputs on the fly when semantic == true
434			if(!el.disabled && form.clk == el) {
435				a.push({name: n, value: $(el).val()});
436				a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
437			}
438			continue;
439		}
440
441		var v = $.fieldValue(el, true);
442		if (v && v.constructor == Array) {
443			for(var j=0, jmax=v.length; j < jmax; j++)
444				a.push({name: n, value: v[j]});
445		}
446		else if (v !== null && typeof v != 'undefined')
447			a.push({name: n, value: v});
448	}
449
450	if (!semantic && form.clk) {
451		// input type=='image' are not found in elements array! handle it here
452		var $input = $(form.clk), input = $input[0], n = input.name;
453		if (n && !input.disabled && input.type == 'image') {
454			a.push({name: n, value: $input.val()});
455			a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
456		}
457	}
458	return a;
459};
460
461/**
462 * Serializes form data into a 'submittable' string. This method will return a string
463 * in the format: name1=value1&amp;name2=value2
464 */
465$.fn.formSerialize = function(semantic) {
466	//hand off to jQuery.param for proper encoding
467	return $.param(this.formToArray(semantic));
468};
469
470/**
471 * Serializes all field elements in the jQuery object into a query string.
472 * This method will return a string in the format: name1=value1&amp;name2=value2
473 */
474$.fn.fieldSerialize = function(successful) {
475	var a = [];
476	this.each(function() {
477		var n = this.name;
478		if (!n) return;
479		var v = $.fieldValue(this, successful);
480		if (v && v.constructor == Array) {
481			for (var i=0,max=v.length; i < max; i++)
482				a.push({name: n, value: v[i]});
483		}
484		else if (v !== null && typeof v != 'undefined')
485			a.push({name: this.name, value: v});
486	});
487	//hand off to jQuery.param for proper encoding
488	return $.param(a);
489};
490
491/**
492 * Returns the value(s) of the element in the matched set.  For example, consider the following form:
493 *
494 *  <form><fieldset>
495 *	  <input name="A" type="text" />
496 *	  <input name="A" type="text" />
497 *	  <input name="B" type="checkbox" value="B1" />
498 *	  <input name="B" type="checkbox" value="B2"/>
499 *	  <input name="C" type="radio" value="C1" />
500 *	  <input name="C" type="radio" value="C2" />
501 *  </fieldset></form>
502 *
503 *  var v = $(':text').fieldValue();
504 *  // if no values are entered into the text inputs
505 *  v == ['','']
506 *  // if values entered into the text inputs are 'foo' and 'bar'
507 *  v == ['foo','bar']
508 *
509 *  var v = $(':checkbox').fieldValue();
510 *  // if neither checkbox is checked
511 *  v === undefined
512 *  // if both checkboxes are checked
513 *  v == ['B1', 'B2']
514 *
515 *  var v = $(':radio').fieldValue();
516 *  // if neither radio is checked
517 *  v === undefined
518 *  // if first radio is checked
519 *  v == ['C1']
520 *
521 * The successful argument controls whether or not the field element must be 'successful'
522 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
523 * The default value of the successful argument is true.  If this value is false the value(s)
524 * for each element is returned.
525 *
526 * Note: This method *always* returns an array.  If no valid value can be determined the
527 *	   array will be empty, otherwise it will contain one or more values.
528 */
529$.fn.fieldValue = function(successful) {
530	for (var val=[], i=0, max=this.length; i < max; i++) {
531		var el = this[i];
532		var v = $.fieldValue(el, successful);
533		if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
534			continue;
535		v.constructor == Array ? $.merge(val, v) : val.push(v);
536	}
537	return val;
538};
539
540/**
541 * Returns the value of the field element.
542 */
543$.fieldValue = function(el, successful) {
544	var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
545	if (typeof successful == 'undefined') successful = true;
546
547	if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
548		(t == 'checkbox' || t == 'radio') && !el.checked ||
549		(t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
550		tag == 'select' && el.selectedIndex == -1))
551			return null;
552
553	if (tag == 'select') {
554		var index = el.selectedIndex;
555		if (index < 0) return null;
556		var a = [], ops = el.options;
557		var one = (t == 'select-one');
558		var max = (one ? index+1 : ops.length);
559		for(var i=(one ? index : 0); i < max; i++) {
560			var op = ops[i];
561			if (op.selected) {
562				var v = op.value;
563				if (!v) // extra pain for IE...
564					v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
565				if (one) return v;
566				a.push(v);
567			}
568		}
569		return a;
570	}
571	return el.value;
572};
573
574/**
575 * Clears the form data.  Takes the following actions on the form's input fields:
576 *  - input text fields will have their 'value' property set to the empty string
577 *  - select elements will have their 'selectedIndex' property set to -1
578 *  - checkbox and radio inputs will have their 'checked' property set to false
579 *  - inputs of type submit, button, reset, and hidden will *not* be effected
580 *  - button elements will *not* be effected
581 */
582$.fn.clearForm = function() {
583	return this.each(function() {
584		$('input,select,textarea', this).clearFields();
585	});
586};
587
588/**
589 * Clears the selected form elements.
590 */
591$.fn.clearFields = $.fn.clearInputs = function() {
592	return this.each(function() {
593		var t = this.type, tag = this.tagName.toLowerCase();
594		if (t == 'text' || t == 'password' || tag == 'textarea')
595			this.value = '';
596		else if (t == 'checkbox' || t == 'radio')
597			this.checked = false;
598		else if (tag == 'select')
599			this.selectedIndex = -1;
600	});
601};
602
603/**
604 * Resets the form data.  Causes all form elements to be reset to their original value.
605 */
606$.fn.resetForm = function() {
607	return this.each(function() {
608		// guard against an input with the name of 'reset'
609		// note that IE reports the reset function as an 'object'
610		if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
611			this.reset();
612	});
613};
614
615/**
616 * Enables or disables any matching elements.
617 */
618$.fn.enable = function(b) {
619	if (b == undefined) b = true;
620	return this.each(function() {
621		this.disabled = !b;
622	});
623};
624
625/**
626 * Checks/unchecks any matching checkboxes or radio buttons and
627 * selects/deselects and matching option elements.
628 */
629$.fn.selected = function(select) {
630	if (select == undefined) select = true;
631	return this.each(function() {
632		var t = this.type;
633		if (t == 'checkbox' || t == 'radio')
634			this.checked = select;
635		else if (this.tagName.toLowerCase() == 'option') {
636			var $sel = $(this).parent('select');
637			if (select && $sel[0] && $sel[0].type == 'select-one') {
638				// deselect all other options
639				$sel.find('option').selected(false);
640			}
641			this.selected = select;
642		}
643	});
644};
645
646// helper fn for console logging
647// set $.fn.ajaxSubmit.debug to true to enable debug logging
648function log() {
649	if ($.fn.ajaxSubmit.debug && window.console && window.console.log)
650		window.console.log('[jquery.form] ' + Array.prototype.join.call(arguments,''));
651};
652
653})(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.