PageSourceSearch

https://www.fanshawec.ca/core/misc/jquery.form.js?v=4.3.0

js fanshawec.ca collected 2026-09-24 09:17:52 UTC 41,767 bytes, 1,535 lines download raw bytes

1/*!
2 * jQuery Form Plugin
3 * version: 4.3.0
4 * Requires jQuery v1.7.2 or later
5 * Project repository: https://github.com/jquery-form/form
6
7 * Copyright 2017 Kevin Morris
8 * Copyright 2006 M. Alsup
9
10 * Dual licensed under the LGPL-2.1+ or MIT licenses
11 * https://github.com/jquery-form/form#license
12
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 * Lesser General Public License for more details.
21 */
22/* global ActiveXObject */
23
24(function (factory) {
25	if (typeof define === 'function' && define.amd) {
26		// AMD. Register as an anonymous module.
27		define(['jquery'], factory);
28	} else if (typeof module === 'object' && module.exports) {
29		// Node/CommonJS
30		module.exports = function( root, jQuery ) {
31			if (typeof jQuery === 'undefined') {
32				// require('jQuery') returns a factory that requires window to build a jQuery instance, we normalize how we use modules
33				// that require this pattern but the window provided is a noop if it's defined (how jquery works)
34				if (typeof window !== 'undefined') {
35					jQuery = require('jquery');
36				}
37				else {
38					jQuery = require('jquery')(root);
39				}
40			}
41			factory(jQuery);
42			return jQuery;
43		};
44	} else {
45		// Browser globals
46		factory(jQuery);
47	}
48
49}(function ($) {
50/* eslint-enable */
51	'use strict';
52
53	/*
54		Usage Note:
55		-----------
56		Do not use both ajaxSubmit and ajaxForm on the same form. These
57		functions are mutually exclusive. Use ajaxSubmit if you want
58		to bind your own submit handler to the form. For example,
59
60		$(document).ready(function() {
61			$('#myForm').on('submit', function(e) {
62				e.preventDefault(); // <-- important
63				$(this).ajaxSubmit({
64					target: '#output'
65				});
66			});
67		});
68
69		Use ajaxForm when you want the plugin to manage all the event binding
70		for you. For example,
71
72		$(document).ready(function() {
73			$('#myForm').ajaxForm({
74				target: '#output'
75			});
76		});
77
78		You can also use ajaxForm with delegation (requires jQuery v1.7+), so the
79		form does not have to exist when you invoke ajaxForm:
80
81		$('#myForm').ajaxForm({
82			delegation: true,
83			target: '#output'
84		});
85
86		When using ajaxForm, the ajaxSubmit function will be invoked for you
87		at the appropriate time.
88	*/
89
90	var rCRLF = /\r?\n/g;
91
92	/**
93	 * Feature detection
94	 */
95	var feature = {};
96
97	feature.fileapi = $('<input type="file">').get(0).files !== undefined;
98	feature.formdata = (typeof window.FormData !== 'undefined');
99
100	var hasProp = !!$.fn.prop;
101
102	// attr2 uses prop when it can but checks the return type for
103	// an expected string. This accounts for the case where a form
104	// contains inputs with names like "action" or "method"; in those
105	// cases "prop" returns the element
106	$.fn.attr2 = function() {
107		if (!hasProp) {
108			return this.attr.apply(this, arguments);
109		}
110
111		var val = this.prop.apply(this, arguments);
112
113		if ((val && val.jquery) || typeof val === 'string') {
114			return val;
115		}
116
117		return this.attr.apply(this, arguments);
118	};
119
120	/**
121	 * ajaxSubmit() provides a mechanism for immediately submitting
122	 * an HTML form using AJAX.
123	 *
124	 * @param	{object|string}	options		jquery.form.js parameters or custom url for submission
125	 * @param	{object}		data		extraData
126	 * @param	{string}		dataType	ajax dataType
127	 * @param	{function}		onSuccess	ajax success callback function
128	 */
129	$.fn.ajaxSubmit = function(options, data, dataType, onSuccess) {
130		// fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
131		if (!this.length) {
132			log('ajaxSubmit: skipping submit process - no element selected');
133
134			return this;
135		}
136
137		/* eslint consistent-this: ["error", "$form"] */
138		var method, action, url, isMsie, iframeSrc, $form = this;
139
140		if (typeof options === 'function') {
141			options = {success: options};
142
143		} else if (typeof options === 'string' || (options === false && arguments.length > 0)) {
144			options = {
145				'url'      : options,
146				'data'     : data,
147				'dataType' : dataType
148			};
149
150			if (typeof onSuccess === 'function') {
151				options.success = onSuccess;
152			}
153
154		} else if (typeof options === 'undefined') {
155			options = {};
156		}
157
158		method = options.method || options.type || this.attr2('method');
159		action = options.url || this.attr2('action');
160
161		url = (typeof action === 'string') ? action.trim() : '';
162		url = url || window.location.href || '';
163		if (url) {
164			// clean url (don't include hash vaue)
165			url = (url.match(/^([^#]+)/) || [])[1];
166		}
167		// IE requires javascript:false in https, but this breaks chrome >
16783 and goes against spec.
168		// Instead of using javascript:false always, let's only apply it for IE.
169		isMsie = /(MSIE|Trident)/.test(navigator.userAgent || '');
170		iframeSrc = (isMsie && /^https/i.test(window.location.href || '')) ? 'javascript:false' : 'about:blank'; // eslint-disable-line no-script-url
171
172		options = $.extend(true, {
173			url       : url,
174			success   : $.ajaxSettings.success,
175			type      : method || $.ajaxSettings.type,
176			iframeSrc : iframeSrc
177		}, options);
178
179		// hook for manipulating the form data before it is extracted;
180		// convenient for use with rich editors like tinyMCE or FCKEditor
181		var veto = {};
182
183		this.trigger('form-pre-serialize', [this, options, veto]);
184
185		if (veto.veto) {
186			log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
187
188			return this;
189		}
190
191		// provide opportunity to alter form data before it is serialized
192		if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
193			log('ajaxSubmit: submit aborted via beforeSerialize callback');
194
195			return this;
196		}
197
198		var traditional = options.traditional;
199
200		if (typeof traditional === 'undefined') {
201			traditional = $.ajaxSettings.traditional;
202		}
203
204		var elements = [];
205		var qx, a = this.formToArray(options.semantic, elements, options.filtering);
206
207		if (options.data) {
208			var optionsData = typeof(options.data) === "function" ? options.data(a) : options.data;
209
210			options.extraData = optionsData;
211			qx = $.param(optionsData, traditional);
212		}
213
214		// give pre-submit callback an opportunity to abort the submit
215		if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
216			log('ajaxSubmit: submit aborted via beforeSubmit callback');
217
218			return this;
219		}
220
221		// fire vetoable 'validate' event
222		this.trigger('form-submit-validate', [a, this, options, veto]);
223		if (veto.veto) {
224			log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
225
226			return this;
227		}
228
229		var q = $.param(a, traditional);
230
231		if (qx) {
232			q = (q ? (q + '&' + qx) : qx);
233		}
234
235		if (options.type.toUpperCase() === 'GET') {
236			options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
237			options.data = null;	// data is null for 'get'
238		} else {
239			options.data = q;		// data is the query string for 'post'
240		}
241
242		var callbacks = [];
243
244		if (options.resetForm) {
245			callbacks.push(function() {
246				$form.resetForm();
247			});
248		}
249
250		if (options.clearForm) {
251			callbacks.push(function() {
252				$form.clearForm(options.includeHidden);
253			});
254		}
255
256		// perform a load on the target only if dataType is not provided
257		if (!options.dataType && options.target) {
258			var oldSuccess = options.success || function(){};
259
260			callbacks.push(function(data, textStatus, jqXHR) {
261				var successArguments = arguments,
262					fn = options.replaceTarget ? 'replaceWith' : 'html';
263
264				$(options.target)[fn](data).each(function(){
265					oldSuccess.apply(this, successArguments);
266				});
267			});
268
269		} else if (options.success) {
270			if (Array.isArray(options.success)) {
271				callbacks = callbacks.concat(options.success);
272			} else {
273				callbacks.push(options.success);
274			}
275		}
276
277		options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
278			var context = options.context || this;		// jQuery 1.4+ supports scope context
279
280			for (var i = 0, max = callbacks.length; i < max; i++) {
281				callbacks[i].apply(context, [data, status, xhr || $form, $form]);
282			}
283		};
284
285		if (options.error) {
286			var oldError = options.error;
287
288			options.error = function(xhr, status, error) {
289				var context = options.context || this;
290
291				oldError.apply(context, [xhr, status, error, $form]);
292			};
293		}
294
295		if (options.complete) {
296			var oldComplete = options.complete;
297
298			options.complete = function(xhr, status) {
299				var context = options.context || this;
300
301				oldComplete.apply(context, [xhr, status, $form]);
302			};
303		}
304
305		// are there files to upload?
306
307		// [value] (issue #113), also see comment:
308		// https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219
309		var fileInputs = $('input[type=file]:enabled', this).filter(function() {
310			return $(this).val() !== '';
311		});
312		var hasFileInputs = fileInputs.length > 0;
313		var mp = 'multipart/form-data';
314		var multipart = ($form.attr('enctype') === mp || $form.attr('encoding') === mp);
315		var fileAPI = feature.fileapi && feature.formdata;
316
317		log('fileAPI :' + fileAPI);
318
319		var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;
320		var jqxhr;
321
322		// options.iframe allows user to force iframe mode
323		// 06-NOV-09: now defaulting to iframe mode if file input is detected
324		if (options.iframe !== false && (options.iframe || shouldUseFrame)) {
325			// hack to fix Safari hang (thanks to Tim Molendijk for this)
326			// see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
327			if (options.closeKeepAlive) {
328				$.get(options.closeKeepAlive, function() {
329					jqxhr = fileUploadIframe(a);
330				});
331
332			} else {
333				jqxhr = fileUploadIframe(a);
334			}
335
336		} else if ((hasFileInputs || multipart) && fileAPI) {
337			jqxhr = fileUploadXhr(a);
338
339		} else {
340			jqxhr = $.ajax(options);
341		}
342
343		$form.removeData('jqxhr').data('jqxhr', jqxhr);
344
345		// clear element array
346		for (var k = 0; k < elements.length; k++) {
347			elements[k] = null;
348		}
349
350		// fire 'notify' event
351		this.trigger('form-submit-notify', [this, options]);
352
353		return this;
354
355		// utility fn for deep serialization
356		function deepSerialize(extraData) {
357			var serialized = $.param(extraData, options.traditional).split('&');
358			var len = serialized.length;
359			var result = [];
360			var i, part;
361
362			for (i = 0; i < len; i++) {
363				// #252; undo param space replacement
364				serialized[i] = serialized[i].replace(/\+/g, ' ');
365				part = serialized[i].split('=');
366				// #278; use array instead of object storage, favoring array serializations
367				result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]);
368			}
369
370			return result;
371		}
372
373		// XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
374		function fileUploadXhr(a) {
375			var formdata = new FormData();
376
377			for (var i = 0; i < a.length; i++) {
378				formdata.append(a[i].name, a[i].value);
379			}
380
381			if (options.extraData) {
382				var serializedData = deepSerialize(options.extraData);
383
384				for (i = 0; i < serializedData.length; i++) {
385					if (serializedData[i]) {
386						formdata.append(serializedData[i][0], serializedData[i][1]);
387					}
388				}
389			}
390
391			options.data = null;
392
393			var s = $.extend(true, {}, $.ajaxSettings, options, {
394				contentType : false,
395				processData : false,
396				cache       : false,
397				type        : method || 'POST'
398			});
399
400			if (options.uploadProgress) {
401				// workaround because jqXHR does not expose upload property
402				s.xhr = function() {
403					var xhr = $.ajaxSettings.xhr();
404
405					if (xhr.upload) {
406						xhr.upload.addEventListener('progress', function(event) {
407							var percent = 0;
408							var position = event.loaded || event.position;			/* event.position is deprecated */
409							var total = event.total;
410
411							if (event.lengthComputable) {
412								percent = Math.ceil(position / total * 100);
413							}
414
415							options.uploadProgress(event, position, total, percent);
416						}, false);
417					}
418
419					return xhr;
420				};
421			}
422
423			s.data = null;
424
425			var beforeSend = s.beforeSend;
426
427			s.beforeSend = function(xhr, o) {
428				// Send FormData() provided by user
429				if (options.formData) {
430					o.data = options.formData;
431				} else {
432					o.data = formdata;
433				}
434
435				if (beforeSend) {
436					beforeSend.call(this, xhr, o);
437				}
438			};
439
440			return $.ajax(s);
441		}
442
443		// private function for handling file uploads (hat tip to YAHOO!)
444		function fileUploadIframe(a) {
445			var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
446			var deferred = $.Deferred();
447
448			// #341
449			deferred.abort = function(status) {
450				xhr.abort(status);
451			};
452
453			if (a) {
454				// ensure that every serialized input is still enabled
455				for (i = 0; i < elements.length; i++) {
456					el = $(elements[i]);
457					if (hasProp) {
458						el.prop('disabled', false);
459					} else {
460						el.removeAttr('disabled');
461					}
462				}
463			}
464
465			s = $.extend(true, {}, $.ajaxSettings, options);
466			s.context = s.context || s;
467			id = 'jqFormIO' + new Date().getTime();
468			var ownerDocument = form.ownerDocument;
469			var $body = $form.closest('body');
470
471			if (s.iframeTarget) {
472				$io = $(s.iframeTarget, ownerDocument);
473				n = $io.attr2('name');
474				if (!n) {
475					$io.attr2('name', id);
476				} else {
477					id = n;
478				}
479
480			} else {
481				$io = $('<iframe name="' + id + '" src="' + s.iframeSrc + '" />', ownerDocument);
482				$io.css({position: 'absolute', top: '-1000px', left: '-1000px'});
483			}
484			io = $io[0];
485
486
487			xhr = { // mock object
488				aborted               : 0,
489				responseText          : null,
490				responseXML           : null,
491				status                : 0,
492				statusText            : 'n/a',
493				getAllResponseHeaders : function() {},
494				getResponseHeader     : function() {},
495				setRequestHeader      : function() {},
496				abort                 : function(status) {
497					var e = (status === 'timeout' ? 'timeout' : 'aborted');
498
499					log('aborting upload... ' + e);
500					this.aborted = 1;
501
502					try { // #214, #257
503						if (io.contentWindow.document.execCommand) {
504							io.contentWindow.document.execCommand('Stop');
505						}
506					} catch (ignore) {}
507
508					$io.attr('src', s.iframeSrc); // abort op in progress
509					xhr.error = e;
510					if (s.error) {
511						s.error.call(s.context, xhr, e, status);
512					}
513
514					if (g) {
515						$.event.trigger('ajaxError', [xhr, s, e]);
516					}
517
518					if (s.complete) {
519						s.complete.call(s.context, xhr, e);
520					}
521				}
522			};
523
524			g = s.global;
525			// trigger ajax global events so that activity/block indicators work like normal
526			if (g && $.active++ === 0) {
527				$.event.trigger('ajaxStart');
528			}
529			if (g) {
530				$.event.trigger('ajaxSend', [xhr, s]);
531			}
532
533			if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
534				if (s.global) {
535					$.active--;
536				}
537				deferred.reject();
538
539				return deferred;
540			}
541
542			if (xhr.aborted) {
543				deferred.reject();
544
545				return deferred;
546			}
547
548			// add submitting element to data if we know it
549			sub = form.clk;
550			if (sub) {
551				n = sub.name;
552				if (n && !sub.disabled) {
553					s.extraData = s.extraData || {};
554					s.extraData[n] = sub.value;
555					if (sub.type === 'image') {
556						s.extraData[n + '.x'] = form.clk_x;
557						s.extraData[n + '.y'] = form.clk_y;
558					}
559				}
560			}
561
562			var CLIENT_TIMEOUT_ABORT = 1;
563			var SERVER_ABORT = 2;
564
565			function getDoc(frame) {
566				/* it looks like contentWindow or contentDocument do not
567				 * carry the protocol property in ie8, when running under ssl
568				 * frame.document is the only valid response document, since
569				 * the protocol is know but not on the other two objects. strange?
570				 * "Same origin policy" http://en.wikipedia.org/wiki/Same_origin_policy
571				 */
572
573				var doc = null;
574
575				// IE8 cascading access check
576				try {
577					if (frame.contentWindow) {
578						doc = frame.contentWindow.document;
579					}
580				} catch (err) {
581					// IE8 access denied under ssl & missing protocol
582					log('cannot get iframe.contentWindow document: ' + err);
583				}
584
585				if (doc) { // successful getting content
586					return doc;
587				}
588
589				try { // simply checking may throw in ie8 under ssl or mismatched protocol
590					doc = frame.contentDocument ? frame.contentDocument : frame.document;
591				} catch (err) {
592					// last attempt
593					log('cannot get iframe.contentDocument: ' + err);
594					doc = frame.document;
595				}
596
597				return doc;
598			}
599
600			// Rails CSRF hack (thanks to Yvan Barthelemy)
601			var csrf_token = $('meta[name=csrf-token]').attr('content');
602			var csrf_param = $('meta[name=csrf-param]').attr('content');
603
604			if (csrf_param && csrf_token) {
605				s.extraData = s.extraData || {};
606				s.extraData[csrf_param] = csrf_token;
607			}
608
609			// take a breath so that pending repaints get some cpu time before the upload starts
610			function doSubmit() {
611				// make sure form attrs are set
612				var t = $form.attr2('target'),
613					a = $form.attr2('action'),
614					mp = 'multipart/form-data',
615					et = $form.attr('enctype') || $form.attr('encoding') || mp;
616
617				// update form attrs in IE friendly way
618				form.setAttribute('target', id);
619				if (!method || /post/i.test(method)) {
620					form.setAttribute('method', 'POST');
621				}
622				if (a !== s.url) {
623					form.setAttribute('action', s.url);
624				}
625
626				// ie borks in some cases when setting encoding
627				if (!s.skipEncodingOverride && (!method || /post/i.test(method))) {
628					$form.attr({
629						encoding : 'multipart/form-data',
630						enctype  : 'multipart/form-data'
631					});
632				}
633
634				// support timout
635				if (s.timeout) {
636					timeoutHandle = setTimeout(function() {
637						timedOut = true; cb(CLIENT_TIMEOUT_ABORT);
638					}, s.timeout);
639				}
640
641				// look for server aborts
642				function checkState() {
643					try {
644						var state = getDoc(io).readyState;
645
646						log('state = ' + state);
647						if (state && state.toLowerCase() === 'uninitialized') {
648							setTimeout(checkState, 50);
649						}
650
651					} catch (e) {
652						log('Server abort: ', e, ' (', e.name, ')');
653						cb(SERVER_ABORT);				// eslint-disable-line callback-return
654						if (timeoutHandle) {
655							clearTimeout(timeoutHandle);
656						}
657						timeoutHandle = undefined;
658					}
659				}
660
661				// add "extra" data to form if provided in options
662				var extraInputs = [];
663
664				try {
665					if (s.extraData) {
666						for (var n in s.extraData) {
667							if (s.extraData.hasOwnProperty(n)) {
668								// if using the $.param format that allows for multiple values with the same name
669								if ($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {
670									extraInputs.push(
671										$('<input type="hidden" name="' + s.extraData[n].name + '">', ownerDocument).val(s.extraData[n].value)
672											.appendTo(form)[0]);
673								} else {
674									extraInputs.push(
675										$('<input type="hidden" name="' + n + '">', ownerDocument).val(s.extraData[n])
676											.appendTo(form)[0]);
677								}
678							}
679						}
680					}
681
682					if (!s.iframeTarget) {
683						// add iframe to doc and submit the form
684						$io.appendTo($body);
685					}
686
687					if (io.attachEvent) {
688						io.attachEvent('onload', cb);
689					} else {
690						io.addEventListener('load', cb, false);
691					}
692
693					setTimeout(checkState, 15);
694
695					try {
696						form.submit();
697
698					} catch (err) {
699						// just in case form has element with name/id of 'submit'
700						var submitFn = document.createElement('form').submit;
701
702						submitFn.apply(form);
703					}
704
705				} finally {
706					// reset attrs and remove "extra" input elements
707					form.setAttribute('action', a);
708					form.setAttribute('enctype', et); // #380
709					if (t) {
710						form.setAttribute('target', t);
711					} else {
712						$form.removeAttr('target');
713					}
714					$(extraInputs).remove();
715				}
716			}
717
718			if (s.forceSync) {
719				doSubmit();
720			} else {
721				setTimeout(doSubmit, 10); // this lets dom updates render
722			}
723
724			var data, doc, domCheckCount = 50, callbackProcessed;
725
726			function cb(e) {
727				if (xhr.aborted || callbackProcessed) {
728					return;
729				}
730
731				doc = getDoc(io);
732				if (!doc) {
733					log('cannot access response document');
734					e = SERVER_ABORT;
735				}
736				if (e === CLIENT_TIMEOUT_ABORT && xhr) {
737					xhr.abort('timeout');
738					deferred.reject(xhr, 'timeout');
739
740					return;
741
742				}
743				if (e === SERVER_ABORT && xhr) {
744					xhr.abort('server abort');
745					deferred.reject(xhr, 'error', 'server abort');
746
747					return;
748				}
749
750				if (!doc || doc.location.href === s.iframeSrc) {
751					// response not received yet
752					if (!timedOut) {
753						return;
754					}
755				}
756
757				if (io.detachEvent) {
758					io.detachEvent('onload', cb);
759				} else {
760					io.removeEventListener('load', cb, false);
761				}
762
763				var status = 'success', errMsg;
764
765				try {
766					if (timedOut) {
767						throw 'timeout';
768					}
769
770					var isXml = s.dataType === 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
771
772					log('isXml=' + isXml);
773
774					if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {
775						if (--domCheckCount) {
776							// in some browsers (Opera) the iframe DOM is not always traversable when
777							// the onload callback fires, so we loop a bit to accommodate
778							log('requeing onLoad callback, DOM not available');
779							setTimeout(cb, 250);
780
781							return;
782						}
783						// let this fall through because server response could be an empty document
784						// log('Could not access iframe DOM after mutiple tries.');
785						// throw 'DOMException: not available';
786					}
787
788					// log('response detected');
789					var docRoot = doc.body ? doc.body : doc.documentElement;
790
791					xhr.responseText = docRoot ? docRoot.innerHTML : null;
792					xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
793					if (isXml) {
794						s.dataType = 'xml';
795					}
796					xhr.getResponseHeader = function(header){
797						var headers = {'content-type': s.dataType};
798
799						return headers[header.toLowerCase()];
800					};
801					// support for XHR 'status' & 'statusText' emulation :
802					if (docRoot) {
803						xhr.status = Number(docRoot.getAttribute('status')) || xhr.status;
804						xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
805					}
806
807					var dt = (s.dataType || '').toLowerCase();
808					var scr = /(json|script|text)/.test(dt);
809
810					if (scr || s.textarea) {
811						// see if user embedded response in textarea
812						var ta = doc.getElementsByTagName('textarea')[0];
813
814						if (ta) {
815							xhr.responseText = ta.value;
816							// support for XHR 'status' & 'statusText' emulation :
817							xhr.status = Number(ta.getAttribute('status')) || xhr.status;
818							xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
819
820						} else if (scr) {
821							// account for browsers injecting pre around json response
822							var pre = doc.getElementsByTagName('pre')[0];
823							var b = doc.getElementsByTagName('body')[0];
824
825							if (pre) {
826								xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;
827							} else if (b) {
828								xhr.responseText = b.textContent ? b.textContent : b.innerText;
829							}
830						}
831
832					} else if (dt === 'xml' && !xhr.responseXML && xhr.responseText) {
833						xhr.responseXML = toXml(xhr.responseText);			// eslint-disable-line no-use-before-define
834					}
835
836					try {
837						data = httpData(xhr, dt, s);						// eslint-disable-line no-use-before-define
838
839					} catch (err) {
840						status = 'parsererror';
841						xhr.error = errMsg = (err || status);
842					}
843
844				} catch (err) {
845					log('error caught: ', err);
846					status = 'error';
847					xhr.error = errMsg = (err || status);
848				}
849
850				if (xhr.aborted) {
851					log('upload aborted');
852					status = null;
853				}
854
855				if (xhr.status) { // we've set xhr.status
856					status = ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) ? 'success' : 'error';
857				}
858
859				// ordering of these callbacks/triggers is odd, but that's how $.ajax does it
860				if (status === 'success') {
861					if (s.success) {
862						s.success.call(s.context, data, 'success', xhr);
863					}
864
865					deferred.resolve(xhr.responseText, 'success', xhr);
866
867					if (g) {
868						$.event.trigger('ajaxSuccess', [xhr, s]);
869					}
870
871				} else if (status) {
872					if (typeof errMsg === 'undefined') {
873						errMsg = xhr.statusText;
874					}
875					if (s.error) {
876						s.error.call(s.context, xhr, status, errMsg);
877					}
878					deferred.reject(xhr, 'error', errMsg);
879					if (g) {
880						$.event.trigger('ajaxError', [xhr, s, errMsg]);
881					}
882				}
883
884				if (g) {
885					$.event.trigger('ajaxComplete', [xhr, s]);
886				}
887
888				if (g && !--$.active) {
889					$.event.trigger('ajaxStop');
890				}
891
892				if (s.complete) {
893					s.complete.call(s.context, xhr, status);
894				}
895
896				callbackProcessed = true;
897				if (s.timeout) {
898					clearTimeout(timeoutHandle);
899				}
900
901				// clean up
902				setTimeout(function() {
903					if (!s.iframeTarget) {
904						$io.remove();
905					} else { // adding else to clean up existing iframe response.
906						$io.attr('src', s.iframeSrc);
907					}
908					xhr.responseXML = null;
909				}, 100);
910			}
911
912			var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
913				if (window.ActiveXObject) {
914					doc = new ActiveXObject('Microsoft.XMLDOM');
915					doc.async = 'false';
916					doc.loadXML(s);
917
918				} else {
919					doc = (new DOMParser()).parseFromString(s, 'text/xml');
920				}
921
922				return (doc && doc.documentElement && doc.documentElement.nodeName !== 'parsererror') ? doc : null;
923			};
924
925			var httpData = function(xhr, type, s) { // mostly lifted from jq1.4.4
926
927				var ct = xhr.getResponseHeader('content-type') || '',
928					xml = ((type === 'xml' || !type) && ct.indexOf('xml') >= 0),
929					data = xml ? xhr.responseXML : xhr.responseText;
930
931				if (xml && data.documentElement.nodeName === 'parsererror') {
932					if ($.error) {
933						$.error('parsererror');
934					}
935				}
936				if (s && s.dataFilter) {
937					data = s.dataFilter(data, type);
938				}
939				if (typeof data === 'string') {
940					if ((type === 'json' || !type) && ct.indexOf('json') >= 0) {
941						data = JSON.parse(data);
942					} else if ((type === 'script' || !type) && ct.indexOf('javascript') >= 0) {
943						$.globalEval(data);
944					}
945				}
946
947				return data;
948			};
949
950			return deferred;
951		}
952	};
953
954	/**
955	 * ajaxForm() provides a mechanism for fully automating form submission.
956	 *
957	 * The advantages of using this method instead of ajaxSubmit() are:
958	 *
959	 * 1: This method will include coordinates for <input type="image"> elements (if the element
960	 *	is used to submit the form).
961	 * 2. This method will include the submit element's name/value data (for the element that was
962	 *	used to submit the form).
963	 * 3. This method binds the submit() method to the form for you.
964	 *
965	 * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
966	 * passes the options argument along after properly binding events for submit elements and
967	 * the form itself.
968	 */
969	$.fn.ajaxForm = function(options, data, dataType, onSuccess) {
970		if (typeof options === 'string' || (options === false && arguments.length > 0)) {
971			options = {
972				'url'      : options,
973				'data'     : data,
974				'dataType' : dataType
975			};
976
977			if (typeof onSuccess === 'function') {
978				options.success = onSuccess;
979			}
980		}
981
982		options = options || {};
983		options.delegation = options.delegation && typeof $.fn.on === 'function';
984
985		// in jQuery 1.3+ we can fix mistakes with the ready state
986		if (!options.delegation && this.length === 0) {
987			var o = {s: this.selector, c: this.context};
988
989			if (!$.isReady && o.s) {
990				log('DOM not ready, queuing ajaxForm');
991				$(function() {
992					$(o.s, o.c).ajaxForm(options);
993				});
994
995				return this;
996			}
997
998			// is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
999			log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
1000
1001			return this;
1002		}
1003
1004		if (options.delegation) {
1005			$(document)
1006				.off('submit.form-plugin', this.selector, doAjaxSubmit)
1007				.off('click.form-plugin', this.selector, captureSubmittingElement)
1008				.on('submit.form-plugin', this.selector, options, doAjaxSubmit)
1009				.on('click.form-plugin', this.selector, options, captureSubmittingElement);
1010
1011			return this;
1012		}
1013
1014		if (options.beforeFormUnbind) {
1015			options.beforeFormUnbind(this, options);
1016		}
1017
1018		return this.ajaxFormUnbind()
1019			.on('submit.form-plugin', options, doAjaxSubmit)
1020			.on('click.form-plugin', options, captureSubmittingElement);
1021	};
1022
1023	// private event handlers
1024	function doAjaxSubmit(e) {
1025		/* jshint validthis:true */
1026		var options = e.data;
1027
1028		if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
1029			e.preventDefault();
1030			$(e.target).closest('form').ajaxSubmit(options); // #365
1031		}
1032	}
1033
1034	function captureSubmittingElement(e) {
1035		/* jshint validthis:true */
1036		var target = e.target;
1037		var $el = $(target);
1038
1039		if (!$el.is('[type=submit],[type=image]')) {
1040			// is this a child element of the submit el?  (ex: a span within a button)
1041			var t = $el.closest('[type=submit]');
1042
1043			if (t.length === 0) {
1044				return;
1045			}
1046			target = t[0];
1047		}
1048
1049		var form = target.form;
1050
1051		form.clk = target;
1052
1053		if (target.type === 'image') {
1054			if (typeof e.offsetX !== 'undefined') {
1055				form.clk_x = e.offsetX;
1056				form.clk_y = e.offsetY;
1057
1058			} else if (typeof $.fn.offset === 'function') {
1059				var offset = $el.offset();
1060
1061				form.clk_x = e.pageX - offset.left;
1062				form.clk_y = e.pageY - offset.top;
1063
1064			} else {
1065				form.clk_x = e.pageX - target.offsetLeft;
1066				form.clk_y = e.pageY - target.offsetTop;
1067			}
1068		}
1069		// clear form vars
1070		setTimeout(function() {
1071			form.clk = form.clk_x = form.clk_y = null;
1072		}, 100);
1073	}
1074
1075
1076	// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
1077	$.fn.ajaxFormUnbind = function() {
1078		return this.off('submit.form-plugin click.form-plugin');
1079	};
1080
1081	/**
1082	 * formToArray() gathers form element data into an array of objects that can
1083	 * be passed to any of the following ajax functions: $.get, $.post, or load.
1084	 * Each object in the array has both a 'name' and 'value' property. An example of
1085	 * an array for a simple login form might be:
1086	 *
1087	 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
1088	 *
1089	 * It is this array that is passed to pre-submit callback functions provided to the
1090	 * ajaxSubmit() and ajaxForm() methods.
1091	 */
1092	$.fn.formToArray = function(semantic, elements, filtering) {
1093		var a = [];
1094
1095		if (this.length === 0) {
1096			return a;
1097		}
1098
1099		var form = this[0];
1100		var formId = this.attr('id');
1101		var els = (semantic || typeof form.elements === 'undefined') ? form.getElementsByTagName('*') : form.elements;
1102		var els2;
1103
1104		if (els) {
1105			els = $.makeArray(els); // convert to standard array
1106		}
1107
1108		// #386; account for inputs outside the form which use the 'form' attribute
1109		// FinesseRus: in non-IE browsers outside fields are already included in form.elements.
1110		if (formId && (semantic || /(Edge|Trident)\//.test(navigator.userAgent))) {
1111			els2 = $(':input[form="' + formId + '"]').get(); // hat tip @thet
1112			if (els2.length) {
1113				els = (els || []).concat(els2);
1114			}
1115		}
1116
1117		if (!els || !els.length) {
1118			return a;
1119		}
1120
1121		if (typeof(filtering) === "function") {
1122			els = $.map(els, filtering);
1123		}
1124
1125		var i, j, n, v, el, max, jmax;
1126
1127		for (i = 0, max = els.length; i < max; i++) {
1128			el = els[i];
1129			n = el.name;
1130			if (!n || el.disabled) {
1131				continue;
1132			}
1133
1134			if (semantic && form.clk && el.type === 'image') {
1135				// handle image inputs on the fly when semantic == true
1136				if (form.clk === el) {
1137					a.push({name: n, value: $(el).val(), type: el.type});
1138					a.push({name: n + '.x', value: form.clk_x}
1138, {name: n + '.y', value: form.clk_y});
1139				}
1140				continue;
1141			}
1142
1143			v = $.fieldValue(el, true);
1144			if (v && v.constructor === Array) {
1145				if (elements) {
1146					elements.push(el);
1147				}
1148				for (j = 0, jmax = v.length; j < jmax; j++) {
1149					a.push({name: n, value: v[j]});
1150				}
1151
1152			} else if (feature.fileapi && el.type === 'file') {
1153				if (elements) {
1154					elements.push(el);
1155				}
1156
1157				var files = el.files;
1158
1159				if (files.length) {
1160					for (j = 0; j < files.length; j++) {
1161						a.push({name: n, value: files[j], type: el.type});
1162					}
1163				} else {
1164					// #180
1165					a.push({name: n, value: '', type: el.type});
1166				}
1167
1168			} else if (v !== null && typeof v !== 'undefined') {
1169				if (elements) {
1170					elements.push(el);
1171				}
1172				a.push({name: n, value: v, type: el.type, required: el.required});
1173			}
1174		}
1175
1176		if (!semantic && form.clk) {
1177			// input type=='image' are not found in elements array! handle it here
1178			var $input = $(form.clk), input = $input[0];
1179
1180			n = input.name;
1181
1182			if (n && !input.disabled && input.type === 'image') {
1183				a.push({name: n, value: $input.val()});
1184				a.push({name: n + '.x', value: form.clk_x}, {name: n + '.y', value: form.clk_y});
1185			}
1186		}
1187
1188		return a;
1189	};
1190
1191	/**
1192	 * Serializes form data into a 'submittable' string. This method will return a string
1193	 * in the format: name1=value1&amp;name2=value2
1194	 */
1195	$.fn.formSerialize = function(semantic) {
1196		// hand off to jQuery.param for proper encoding
1197		return $.param(this.formToArray(semantic));
1198	};
1199
1200	/**
1201	 * Serializes all field elements in the jQuery object into a query string.
1202	 * This method will return a string in the format: name1=value1&amp;name2=value2
1203	 */
1204	$.fn.fieldSerialize = function(successful) {
1205		var a = [];
1206
1207		this.each(function() {
1208			var n = this.name;
1209
1210			if (!n) {
1211				return;
1212			}
1213
1214			var v = $.fieldValue(this, successful);
1215
1216			if (v && v.constructor === Array) {
1217				for (var i = 0, max = v.length; i < max; i++) {
1218					a.push({name: n, value: v[i]});
1219				}
1220
1221			} else if (v !== null && typeof v !== 'undefined') {
1222				a.push({name: this.name, value: v});
1223			}
1224		});
1225
1226		// hand off to jQuery.param for proper encoding
1227		return $.param(a);
1228	};
1229
1230	/**
1231	 * Returns the value(s) of the element in the matched set. For example, consider the following form:
1232	 *
1233	 *	<form><fieldset>
1234	 *		<input name="A" type="text">
1235	 *		<input name="A" type="text">
1236	 *		<input name="B" type="checkbox" value="B1">
1237	 *		<input name="B" type="checkbox" value="B2">
1238	 *		<input name="C" type="radio" value="C1">
1239	 *		<input name="C" type="radio" value="C2">
1240	 *	</fieldset></form>
1241	 *
1242	 *	var v = $('input[type=text]').fieldValue();
1243	 *	// if no values are entered into the text inputs
1244	 *	v === ['','']
1245	 *	// if values entered into the text inputs are 'foo' and 'bar'
1246	 *	v === ['foo','bar']
1247	 *
1248	 *	var v = $('input[type=checkbox]').fieldValue();
1249	 *	// if neither checkbox is checked
1250	 *	v === undefined
1251	 *	// if both checkboxes are checked
1252	 *	v === ['B1', 'B2']
1253	 *
1254	 *	var v = $('input[type=radio]').fieldValue();
1255	 *	// if neither radio is checked
1256	 *	v === undefined
1257	 *	// if first radio is checked
1258	 *	v === ['C1']
1259	 *
1260	 * The successful argument controls whether or not the field element must be 'successful'
1261	 * (per https://www.w3.org/TR/html4/interact/forms.html#successful-controls).
1262	 * The default value of the successful argument is true. If this value is false the value(s)
1263	 * for each element is returned.
1264	 *
1265	 * Note: This method *always* returns an array. If no valid value can be determined the
1266	 *	array will be empty, otherwise it will contain one or more values.
1267	 */
1268	$.fn.fieldValue = function(successful) {
1269		for (var val = [], i = 0, max = this.length; i < max; i++) {
1270			var el = this[i];
1271			var v = $.fieldValue(el, successful);
1272
1273			if (v === null || typeof v === 'undefined' || (v.constructor === Array && !v.length)) {
1274				continue;
1275			}
1276
1277			if (Array.isArray(v)) {
1278				val = val.concat(v);
1279			} else {
1280				val.push(v);
1281			}
1282		}
1283
1284		return val;
1285	};
1286
1287	/**
1288	 * Returns the value of the field element.
1289	 */
1290	$.fieldValue = function(el, successful) {
1291		var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
1292
1293		if (typeof successful === 'undefined') {
1294			successful = true;
1295		}
1296
1297		/* eslint-disable no-mixed-operators */
1298		if (successful && (!n || el.disabled || t === 'reset' || t === 'button' ||
1299			(t === 'checkbox' || t === 'radio') && !el.checked ||
1300			(t === 'submit' || t === 'image') && el.form && el.form.clk !== el ||
1301			tag === 'select' && el.selectedIndex === -1)) {
1302		/* eslint-enable no-mixed-operators */
1303			return null;
1304		}
1305
1306		if (tag === 'select') {
1307			var index = el.selectedIndex;
1308
1309			if (index < 0) {
1310				return null;
1311			}
1312
1313			var a = [], ops = el.options;
1314			var one = (t === 'select-one');
1315			var max = (one ? index + 1 : ops.length);
1316
1317			for (var i = (one ? index : 0); i < max; i++) {
1318				var op = ops[i];
1319
1320				if (op.selected && !op.disabled) {
1321					var v = op.value;
1322
1323					if (!v) { // extra pain for IE...
1324						v = (op.attributes && op.attributes.value && !(op.attributes.value.specified)) ? op.text : op.value;
1325					}
1326
1327					if (one) {
1328						return v;
1329					}
1330
1331					a.push(v);
1332				}
1333			}
1334
1335			return a;
1336		}
1337
1338		return $(el).val().replace(rCRLF, '\r\n');
1339	};
1340
1341	/**
1342	 * Clears the form data. Takes the following actions on the form's input fields:
1343	 *  - input text fields will have their 'value' property set to the empty string
1344	 *  - select elements will have their 'selectedIndex' property set to -1
1345	 *  - checkbox and radio inputs will have their 'checked' property set to false
1346	 *  - inputs of type submit, button, reset, and hidden will *not* be effected
1347	 *  - button elements will *not* be effected
1348	 */
1349	$.fn.clearForm = function(includeHidden) {
1350		return this.each(function() {
1351			$('input,select,textarea', this).clearFields(includeHidden);
1352		});
1353	};
1354
1355	/**
1356	 * Clears the selected form elements.
1357	 */
1358	$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
1359		var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
1360
1361		return this.each(function() {
1362			var t = this.type, tag = this.tagName.toLowerCase();
1363
1364			if (re.test(t) || tag === 'textarea') {
1365				this.value = '';
1366
1367			} else if (t === 'checkbox' || t === 'radio') {
1368				this.checked = false;
1369
1370			} else if (tag === 'select') {
1371				this.selectedIndex = -1;
1372
1373			} else if (t === 'file') {
1374				if (/MSIE/.test(navigator.userAgent)) {
1375					$(this).replaceWith($(this).clone(true));
1376				} else {
1377					$(this).val('');
1378				}
1379
1380			} else if (includeHidden) {
1381				// includeHidden can be the value true, or it can be a selector string
1382				// indicating a special test; for example:
1383				// $('#myForm').clearForm('.special:hidden')
1384				// the above would clean hidden inputs that have the class of 'special'
1385				if ((includeHidden === true && /hidden/.test(t)) ||
1386					(typeof includeHidden === 'string' && $(this).is(includeHidden))) {
1387					this.value = '';
1388				}
1389			}
1390		});
1391	};
1392
1393
1394	/**
1395	 * Resets the form data or individual elements. Takes the following actions
1396	 * on the selected tags:
1397	 * - all fields within form elements will be reset to their original value
1398	 * - input / textarea / select fields will be reset to their original value
1399	 * - option / optgroup fields (for multi-selects) will defaulted individually
1400	 * - non-multiple options will find the right select to default
1401	 * - label elements will be searched against its 'for' attribute
1402	 * - all others will be searched for appropriate children to default
1403	 */
1404	$.fn.resetForm = function() {
1405		return this.each(function() {
1406			var el = $(this);
1407			var tag = this.tagName.toLowerCase();
1408
1409			switch (tag) {
1410			case 'input':
1411				this.checked = this.defaultChecked;
1412				// fall through
1413
1414			case 'textarea':
1415				this.value = this.defaultValue;
1416
1417				return true;
1418
1419			case 'option':
1420			case 'optgroup':
1421				var select = el.parents('select');
1422
1423				if (select.length && select[0].multiple) {
1424					if (tag === 'option') {
1425						this.selected = this.defaultSelected;
1426					} else {
1427						el.find('option').resetForm();
1428					}
1429				} else {
1430					select.resetForm();
1431				}
1432
1433				return true;
1434
1435			case 'select':
1436				el.find('option').each(function(i) {				// eslint-disable-line consistent-return
1437					this.selected = this.defaultSelected;
1438					if (this.defaultSelected && !el[0].multiple) {
1439						el[0].selectedIndex = i;
1440
1441						return false;
1442					}
1443				});
1444
1445				return true;
1446
1447			case 'label':
1448				var forEl = $(el.attr('for'));
1449				var list = el.find('input,select,textarea');
1450
1451				if (forEl[0]) {
1452					list.unshift(forEl[0]);
1453				}
1454
1455				list.resetForm();
1456
1457				return true;
1458
1459			case 'form':
1460				// guard against an input with the name of 'reset'
1461				// note that IE reports the reset function as an 'object'
1462				if (typeof this.reset === 'function' || (typeof this.reset === 'object' && !this.reset.nodeType)) {
1463					this.reset();
1464				}
1465
1466				return true;
1467
1468			default:
1469				el.find('form,input,label,select,textarea').resetForm();
1470
1471				return true;
1472			}
1473		});
1474	};
1475
1476	/**
1477	 * Enables or disables any matching elements.
1478	 */
1479	$.fn.enable = function(b) {
1480		if (typeof b === 'undefined') {
1481			b = true;
1482		}
1483
1484		return this.each(function() {
1485			this.disabled = !b;
1486		});
1487	};
1488
1489	/**
1490	 * Checks/unchecks any matching checkboxes or radio buttons and
1491	 * selects/deselects and matching option elements.
1492	 */
1493	$.fn.selected = function(select) {
1494		if (typeof select === 'undefined') {
1495			select = true;
1496		}
1497
1498		return this.each(function() {
1499			var t = this.type;
1500
1501			if (t === 'checkbox' || t === 'radio') {
1502				this.checked = select;
1503
1504			} else if (this.tagName.toLowerCase() === 'option') {
1505				var $sel = $(this).parent('select');
1506
1507				if (select && $sel[0] && $sel[0].type === 'select-one') {
1508					// deselect all other options
1509					$sel.find('option').selected(false);
1510				}
1511
1512				this.selected = select;
1513			}
1514		});
1515	};
1516
1517	// expose debug var
1518	$.fn.ajaxSubmit.debug = false;
1519
1520	// helper fn for console logging
1521	function log() {
1522		if (!$.fn.ajaxSubmit.debug) {
1523			return;
1524		}
1525
1526		var msg = '[jquery.form] ' + Array.prototype.join.call(arguments, '');
1527
1528		if (window.console && window.console.log) {
1529			window.console.log(msg);
1530
1531		} else if (window.opera && window.opera.postError) {
1532			window.opera.postError(msg);
1533		}
1534	}
1535}));

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.