PageSourceSearch

https://angekis.com/res/js/jquery.form.js

js angekis.com collected 2026-10-07 16:46:44 UTC 21,575 bytes, 697 lines download raw bytes

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