3 * version: 3.14 (30-JUL-2012)
4 * @requires jQuery v1.3.2 or later
6 * Examples and documentation at: http://malsup.com/jquery/form/
7 * Project repository: https://github.com/malsup/form
8 * Dual licensed under the MIT and GPL licenses:
9 * http://malsup.github.com/mit-license.txt
10 * http://malsup.github.com/gpl-license-v2.txt
12 /*global ActiveXObject alert */
19 Do not use both ajaxSubmit and ajaxForm on the same form. These
20 functions are mutually exclusive. Use ajaxSubmit if you want
21 to bind your own submit handler to the form. For example,
23 $(document).ready(function() {
24 $('#myForm').on('submit', function(e) {
25 e.preventDefault(); // <-- important
32 Use ajaxForm when you want the plugin to manage all the event binding
35 $(document).ready(function() {
36 $('#myForm').ajaxForm({
41 You can also use ajaxForm with delegation (requires jQuery v1.7+), so the
42 form does not have to exist when you invoke ajaxForm:
44 $('#myForm').ajaxForm({
49 When using ajaxForm, the ajaxSubmit function will be invoked for you
50 at the appropriate time.
57 feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
58 feature.formdata = window.FormData !== undefined;
61 * ajaxSubmit() provides a mechanism for immediately submitting
62 * an HTML form using AJAX.
64 $.fn.ajaxSubmit = function(options) {
65 /*jshint scripturl:true */
67 // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
69 log('ajaxSubmit: skipping submit process - no element selected');
73 var method, action, url, $form = this;
75 if (typeof options == 'function') {
76 options = { success: options };
79 method = this.attr('method');
80 action = this.attr('action');
81 url = (typeof action === 'string') ? $.trim(action) : '';
82 url = url || window.location.href || '';
84 // clean url (don't include hash vaue)
85 url = (url.match(/^([^#]+)/)||[])[1];
88 options = $.extend(true, {
90 success: $.ajaxSettings.success,
91 type: method || 'GET',
92 iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
95 // hook for manipulating the form data before it is extracted;
96 // convenient for use with rich editors like tinyMCE or FCKEditor
98 this.trigger('form-pre-serialize', [this, options, veto]);
100 log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
104 // provide opportunity to alter form data before it is serialized
105 if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
106 log('ajaxSubmit: submit aborted via beforeSerialize callback');
110 var traditional = options.traditional;
111 if ( traditional === undefined ) {
112 traditional = $.ajaxSettings.traditional;
116 var qx, a = this.formToArray(options.semantic, elements);
118 options.extraData = options.data;
119 qx = $.param(options.data, traditional);
122 // give pre-submit callback an opportunity to abort the submit
123 if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
124 log('ajaxSubmit: submit aborted via beforeSubmit callback');
128 // fire vetoable 'validate' event
129 this.trigger('form-submit-validate', [a, this, options, veto]);
131 log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
135 var q = $.param(a, traditional);
137 q = ( q ? (q + '&' + qx) : qx );
139 if (options.type.toUpperCase() == 'GET') {
140 options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
141 options.data = null; // data is null for 'get'
144 options.data = q; // data is the query string for 'post'
148 if (options.resetForm) {
149 callbacks.push(function() { $form.resetForm(); });
151 if (options.clearForm) {
152 callbacks.push(function() { $form.clearForm(options.includeHidden); });
155 // perform a load on the target only if dataType is not provided
156 if (!options.dataType && options.target) {
157 var oldSuccess = options.success || function(){};
158 callbacks.push(function(data) {
159 var fn = options.replaceTarget ? 'replaceWith' : 'html';
160 $(options.target)[fn](data).each(oldSuccess, arguments);
163 else if (options.success) {
164 callbacks.push(options.success);
167 options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
168 var context = options.context || this ; // jQuery 1.4+ supports scope context
169 for (var i=0, max=callbacks.length; i < max; i++) {
170 callbacks[i].apply(context, [data, status, xhr || $form, $form]);
174 // are there files to upload?
175 var fileInputs = $('input:file:enabled[value]', this); // [value] (issue #113)
176 var hasFileInputs = fileInputs.length > 0;
177 var mp = 'multipart/form-data';
178 var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
180 var fileAPI = feature.fileapi && feature.formdata;
181 log("fileAPI :" + fileAPI);
182 var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;
184 // options.iframe allows user to force iframe mode
185 // 06-NOV-09: now defaulting to iframe mode if file input is detected
186 if (options.iframe !== false && (options.iframe || shouldUseFrame)) {
187 // hack to fix Safari hang (thanks to Tim Molendijk for this)
188 // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
189 if (options.closeKeepAlive) {
190 $.get(options.closeKeepAlive, function() {
198 else if ((hasFileInputs || multipart) && fileAPI) {
205 // clear element array
206 for (var k=0; k < elements.length; k++)
209 // fire 'notify' event
210 this.trigger('form-submit-notify', [this, options]);
213 // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
214 function fileUploadXhr(a) {
215 var formdata = new FormData();
217 for (var i=0; i < a.length; i++) {
218 formdata.append(a[i].name, a[i].value);
221 if (options.extraData) {
222 for (var p in options.extraData)
223 if (options.extraData.hasOwnProperty(p))
224 formdata.append(p, options.extraData[p]);
229 var s = $.extend(true, {}, $.ajaxSettings, options, {
236 if (options.uploadProgress) {
237 // workaround because jqXHR does not expose upload property
239 var xhr = jQuery.ajaxSettings.xhr();
241 xhr.upload.onprogress = function(event) {
243 var position = event.loaded || event.position; /*event.position is deprecated*/
244 var total = event.total;
245 if (event.lengthComputable) {
246 percent = Math.ceil(position / total * 100);
248 options.uploadProgress(event, position, total, percent);
256 var beforeSend = s.beforeSend;
257 s.beforeSend = function(xhr, o) {
260 beforeSend.call(this, xhr, o);
265 // private function for handling file uploads (hat tip to YAHOO!)
266 function fileUploadIframe(a) {
267 var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
268 var useProp = !!$.fn.prop;
270 if ($(':input[name=submit],:input[id=submit]', form).length) {
271 // if there is an input with a name or id of 'submit' then we won't be
272 // able to invoke the submit fn on the form (at least not x-browser)
273 alert('Error: Form elements must not have name or id of "submit".');
278 // ensure that every serialized input is still enabled
279 for (i=0; i < elements.length; i++) {
282 el.prop('disabled', false);
284 el.removeAttr('disabled');
288 s = $.extend(true, {}, $.ajaxSettings, options);
289 s.context = s.context || s;
290 id = 'jqFormIO' + (new Date().getTime());
291 if (s.iframeTarget) {
292 $io = $(s.iframeTarget);
293 n = $io.attr('name');
295 $io.attr('name', id);
300 $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
301 $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
306 xhr = { // mock object
312 getAllResponseHeaders: function() {},
313 getResponseHeader: function() {},
314 setRequestHeader: function() {},
315 abort: function(status) {
316 var e = (status === 'timeout' ? 'timeout' : 'aborted');
317 log('aborting upload... ' + e);
320 if (io.contentWindow.document.execCommand) {
322 io.contentWindow.document.execCommand('Stop');
325 $io.attr('src', s.iframeSrc); // abort op in progress
328 s.error.call(s.context, xhr, e, status);
330 $.event.trigger("ajaxError", [xhr, s, e]);
332 s.complete.call(s.context, xhr, e);
337 // trigger ajax global events so that activity/block indicators work like normal
338 if (g && 0 === $.active++) {
339 $.event.trigger("ajaxStart");
342 $.event.trigger("ajaxSend", [xhr, s]);
345 if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
355 // add submitting element to data if we know it
359 if (n && !sub.disabled) {
360 s.extraData = s.extraData || {};
361 s.extraData[n] = sub.value;
362 if (sub.type == "image") {
363 s.extraData[n+'.x'] = form.clk_x;
364 s.extraData[n+'.y'] = form.clk_y;
369 var CLIENT_TIMEOUT_ABORT = 1;
370 var SERVER_ABORT = 2;
372 function getDoc(frame) {
373 var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document;
377 // Rails CSRF hack (thanks to Yvan Barthelemy)
378 var csrf_token = $('meta[name=csrf-token]').attr('content');
379 var csrf_param = $('meta[name=csrf-param]').attr('content');
380 if (csrf_param && csrf_token) {
381 s.extraData = s.extraData || {};
382 s.extraData[csrf_param] = csrf_token;
385 // take a breath so that pending repaints get some cpu time before the upload starts
386 function doSubmit() {
387 // make sure form attrs are set
388 var t = $form.attr('target'), a = $form.attr('action');
390 // update form attrs in IE friendly way
391 form.setAttribute('target',id);
393 form.setAttribute('method', 'POST');
396 form.setAttribute('action', s.url);
399 // ie borks in some cases when setting encoding
400 if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
402 encoding: 'multipart/form-data',
403 enctype: 'multipart/form-data'
409 timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
412 // look for server aborts
413 function checkState() {
415 var state = getDoc(io).readyState;
416 log('state = ' + state);
417 if (state && state.toLowerCase() == 'uninitialized')
418 setTimeout(checkState,50);
421 log('Server abort: ' , e, ' (', e.name, ')');
424 clearTimeout(timeoutHandle);
425 timeoutHandle = undefined;
429 // add "extra" data to form if provided in options
430 var extraInputs = [];
433 for (var n in s.extraData) {
434 if (s.extraData.hasOwnProperty(n)) {
435 // if using the $.param format that allows for multiple values with the same name
436 if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {
438 $('<input type="hidden" name="'+s.extraData[n].name+'">').attr('value',s.extraData[n].value)
442 $('<input type="hidden" name="'+n+'">').attr('value',s.extraData[n])
449 if (!s.iframeTarget) {
450 // add iframe to doc and submit the form
451 $io.appendTo('body');
453 io.attachEvent('onload', cb);
455 io.addEventListener('load', cb, false);
457 setTimeout(checkState,15);
461 // reset attrs and remove "extra" input elements
462 form.setAttribute('action',a);
464 form.setAttribute('target', t);
466 $form.removeAttr('target');
468 $(extraInputs).remove();
476 setTimeout(doSubmit, 10); // this lets dom updates render
479 var data, doc, domCheckCount = 50, callbackProcessed;
482 if (xhr.aborted || callbackProcessed) {
489 log('cannot access response document: ', ex);
492 if (e === CLIENT_TIMEOUT_ABORT && xhr) {
493 xhr.abort('timeout');
496 else if (e == SERVER_ABORT && xhr) {
497 xhr.abort('server abort');
501 if (!doc || doc.location.href == s.iframeSrc) {
502 // response not received yet
507 io.detachEvent('onload', cb);
509 io.removeEventListener('load', cb, false);
511 var status = 'success', errMsg;
517 var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
519 if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {
520 if (--domCheckCount) {
521 // in some browsers (Opera) the iframe DOM is not always traversable when
522 // the onload callback fires, so we loop a bit to accommodate
523 log('requeing onLoad callback, DOM not available');
527 // let this fall through because server response could be an empty document
528 //log('Could not access iframe DOM after mutiple tries.');
529 //throw 'DOMException: not available';
532 //log('response detected');
533 var docRoot = doc.body ? doc.body : doc.documentElement;
534 xhr.responseText = docRoot ? docRoot.innerHTML : null;
535 xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
538 xhr.getResponseHeader = function(header){
539 var headers = {'content-type': s.dataType};
540 return headers[header];
542 // support for XHR 'status' & 'statusText' emulation :
544 xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
545 xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
548 var dt = (s.dataType || '').toLowerCase();
549 var scr = /(json|script|text)/.test(dt);
550 if (scr || s.textarea) {
551 // see if user embedded response in textarea
552 var ta = doc.getElementsByTagName('textarea')[0];
554 xhr.responseText = ta.value;
555 // support for XHR 'status' & 'statusText' emulation :
556 xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
557 xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
560 // account for browsers injecting pre around json response
561 var pre = doc.getElementsByTagName('pre')[0];
562 var b = doc.getElementsByTagName('body')[0];
564 xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;
567 xhr.responseText = b.textContent ? b.textContent : b.innerText;
571 else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) {
572 xhr.responseXML = toXml(xhr.responseText);
576 data = httpData(xhr, dt, s);
579 status = 'parsererror';
580 xhr.error = errMsg = (e || status);
584 log('error caught: ',e);
586 xhr.error = errMsg = (e || status);
590 log('upload aborted');
594 if (xhr.status) { // we've set xhr.status
595 status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
598 // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
599 if (status === 'success') {
601 s.success.call(s.context, data, 'success', xhr);
603 $.event.trigger("ajaxSuccess", [xhr, s]);
606 if (errMsg === undefined)
607 errMsg = xhr.statusText;
609 s.error.call(s.context, xhr, status, errMsg);
611 $.event.trigger("ajaxError", [xhr, s, errMsg]);
615 $.event.trigger("ajaxComplete", [xhr, s]);
617 if (g && ! --$.active) {
618 $.event.trigger("ajaxStop");
622 s.complete.call(s.context, xhr, status);
624 callbackProcessed = true;
626 clearTimeout(timeoutHandle);
629 setTimeout(function() {
632 xhr.responseXML = null;
636 var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
637 if (window.ActiveXObject) {
638 doc = new ActiveXObject('Microsoft.XMLDOM');
643 doc = (new DOMParser()).parseFromString(s, 'text/xml');
645 return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
647 var parseJSON = $.parseJSON || function(s) {
648 /*jslint evil:true */
649 return window['eval']('(' + s + ')');
652 var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
654 var ct = xhr.getResponseHeader('content-type') || '',
655 xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
656 data = xml ? xhr.responseXML : xhr.responseText;
658 if (xml && data.documentElement.nodeName === 'parsererror') {
660 $.error('parsererror');
662 if (s && s.dataFilter) {
663 data = s.dataFilter(data, type);
665 if (typeof data === 'string') {
666 if (type === 'json' || !type && ct.indexOf('json') >= 0) {
667 data = parseJSON(data);
668 } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
678 * ajaxForm() provides a mechanism for fully automating form submission.
680 * The advantages of using this method instead of ajaxSubmit() are:
682 * 1: This method will include coordinates for <input type="image" /> elements (if the element
683 * is used to submit the form).
684 * 2. This method will include the submit element's name/value data (for the element that was
685 * used to submit the form).
686 * 3. This method binds the submit() method to the form for you.
688 * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
689 * passes the options argument along after properly binding events for submit elements and
692 $.fn.ajaxForm = function(options) {
693 options = options || {};
694 options.delegation = options.delegation && $.isFunction($.fn.on);
696 // in jQuery 1.3+ we can fix mistakes with the ready state
697 if (!options.delegation && this.length === 0) {
698 var o = { s: this.selector, c: this.context };
699 if (!$.isReady && o.s) {
700 log('DOM not ready, queuing ajaxForm');
702 $(o.s,o.c).ajaxForm(options);
706 // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
707 log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
711 if ( options.delegation ) {
713 .off('submit.form-plugin', this.selector, doAjaxSubmit)
714 .off('click.form-plugin', this.selector, captureSubmittingElement)
715 .on('submit.form-plugin', this.selector, options, doAjaxSubmit)
716 .on('click.form-plugin', this.selector, options, captureSubmittingElement);
720 return this.ajaxFormUnbind()
721 .bind('submit.form-plugin', options, doAjaxSubmit)
722 .bind('click.form-plugin', options, captureSubmittingElement);
725 // private event handlers
726 function doAjaxSubmit(e) {
727 /*jshint validthis:true */
728 var options = e.data;
729 if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
731 $(this).ajaxSubmit(options);
735 function captureSubmittingElement(e) {
736 /*jshint validthis:true */
737 var target = e.target;
739 if (!($el.is(":submit,input:image"))) {
740 // is this a child element of the submit el? (ex: a span within a button)
741 var t = $el.closest(':submit');
742 if (t.length === 0) {
749 if (target.type == 'image') {
750 if (e.offsetX !== undefined) {
751 form.clk_x = e.offsetX;
752 form.clk_y = e.offsetY;
753 } else if (typeof $.fn.offset == 'function') {
754 var offset = $el.offset();
755 form.clk_x = e.pageX - offset.left;
756 form.clk_y = e.pageY - offset.top;
758 form.clk_x = e.pageX - target.offsetLeft;
759 form.clk_y = e.pageY - target.offsetTop;
763 setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
767 // ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
768 $.fn.ajaxFormUnbind = function() {
769 return this.unbind('submit.form-plugin click.form-plugin');
773 * formToArray() gathers form element data into an array of objects that can
774 * be passed to any of the following ajax functions: $.get, $.post, or load.
775 * Each object in the array has both a 'name' and 'value' property. An example of
776 * an array for a simple login form might be:
778 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
780 * It is this array that is passed to pre-submit callback functions provided to the
781 * ajaxSubmit() and ajaxForm() methods.
783 $.fn.formToArray = function(semantic, elements) {
785 if (this.length === 0) {
790 var els = semantic ? form.getElementsByTagName('*') : form.elements;
795 var i,j,n,v,el,max,jmax;
796 for(i=0, max=els.length; i < max; i++) {
803 if (semantic && form.clk && el.type == "image") {
804 // handle image inputs on the fly when semantic == true
805 if(!el.disabled && form.clk == el) {
806 a.push({name: n, value: $(el).val(), type: el.type });
807 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
812 v = $.fieldValue(el, true);
813 if (v && v.constructor == Array) {
816 for(j=0, jmax=v.length; j < jmax; j++) {
817 a.push({name: n, value: v[j]});
820 else if (feature.fileapi && el.type == 'file' && !el.disabled) {
823 var files = el.files;
825 for (j=0; j < files.length; j++) {
826 a.push({name: n, value: files[j], type: el.type});
831 a.push({ name: n, value: '', type: el.type });
834 else if (v !== null && typeof v != 'undefined') {
837 a.push({name: n, value: v, type: el.type, required: el.required});
841 if (!semantic && form.clk) {
842 // input type=='image' are not found in elements array! handle it here
843 var $input = $(form.clk), input = $input[0];
845 if (n && !input.disabled && input.type == 'image') {
846 a.push({name: n, value: $input.val()});
847 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
854 * Serializes form data into a 'submittable' string. This method will return a string
855 * in the format: name1=value1&name2=value2
857 $.fn.formSerialize = function(semantic) {
858 //hand off to jQuery.param for proper encoding
859 return $.param(this.formToArray(semantic));
863 * Serializes all field elements in the jQuery object into a query string.
864 * This method will return a string in the format: name1=value1&name2=value2
866 $.fn.fieldSerialize = function(successful) {
868 this.each(function() {
873 var v = $.fieldValue(this, successful);
874 if (v && v.constructor == Array) {
875 for (var i=0,max=v.length; i < max; i++) {
876 a.push({name: n, value: v[i]});
879 else if (v !== null && typeof v != 'undefined') {
880 a.push({name: this.name, value: v});
883 //hand off to jQuery.param for proper encoding
888 * Returns the value(s) of the element in the matched set. For example, consider the following form:
891 * <input name="A" type="text" />
892 * <input name="A" type="text" />
893 * <input name="B" type="checkbox" value="B1" />
894 * <input name="B" type="checkbox" value="B2"/>
895 * <input name="C" type="radio" value="C1" />
896 * <input name="C" type="radio" value="C2" />
899 * var v = $(':text').fieldValue();
900 * // if no values are entered into the text inputs
902 * // if values entered into the text inputs are 'foo' and 'bar'
905 * var v = $(':checkbox').fieldValue();
906 * // if neither checkbox is checked
908 * // if both checkboxes are checked
911 * var v = $(':radio').fieldValue();
912 * // if neither radio is checked
914 * // if first radio is checked
917 * The successful argument controls whether or not the field element must be 'successful'
918 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
919 * The default value of the successful argument is true. If this value is false the value(s)
920 * for each element is returned.
922 * Note: This method *always* returns an array. If no valid value can be determined the
923 * array will be empty, otherwise it will contain one or more values.
925 $.fn.fieldValue = function(successful) {
926 for (var val=[], i=0, max=this.length; i < max; i++) {
928 var v = $.fieldValue(el, successful);
929 if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
932 if (v.constructor == Array)
941 * Returns the value of the field element.
943 $.fieldValue = function(el, successful) {
944 var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
945 if (successful === undefined) {
949 if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
950 (t == 'checkbox' || t == 'radio') && !el.checked ||
951 (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
952 tag == 'select' && el.selectedIndex == -1)) {
956 if (tag == 'select') {
957 var index = el.selectedIndex;
961 var a = [], ops = el.options;
962 var one = (t == 'select-one');
963 var max = (one ? index+1 : ops.length);
964 for(var i=(one ? index : 0); i < max; i++) {
968 if (!v) { // extra pain for IE...
969 v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
983 * Clears the form data. Takes the following actions on the form's input fields:
984 * - input text fields will have their 'value' property set to the empty string
985 * - select elements will have their 'selectedIndex' property set to -1
986 * - checkbox and radio inputs will have their 'checked' property set to false
987 * - inputs of type submit, button, reset, and hidden will *not* be effected
988 * - button elements will *not* be effected
990 $.fn.clearForm = function(includeHidden) {
991 return this.each(function() {
992 $('input,select,textarea', this).clearFields(includeHidden);
997 * Clears the selected form elements.
999 $.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
1000 var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
1001 return this.each(function() {
1002 var t = this.type, tag = this.tagName.toLowerCase();
1003 if (re.test(t) || tag == 'textarea') {
1006 else if (t == 'checkbox' || t == 'radio') {
1007 this.checked = false;
1009 else if (tag == 'select') {
1010 this.selectedIndex = -1;
1012 else if (includeHidden) {
1013 // includeHidden can be the value true, or it can be a selector string
1014 // indicating a special test; for example:
1015 // $('#myForm').clearForm('.special:hidden')
1016 // the above would clean hidden inputs that have the class of 'special'
1017 if ( (includeHidden === true && /hidden/.test(t)) ||
1018 (typeof includeHidden == 'string' && $(this).is(includeHidden)) )
1025 * Resets the form data. Causes all form elements to be reset to their original value.
1027 $.fn.resetForm = function() {
1028 return this.each(function() {
1029 // guard against an input with the name of 'reset'
1030 // note that IE reports the reset function as an 'object'
1031 if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
1038 * Enables or disables any matching elements.
1040 $.fn.enable = function(b) {
1041 if (b === undefined) {
1044 return this.each(function() {
1050 * Checks/unchecks any matching checkboxes or radio buttons and
1051 * selects/deselects and matching option elements.
1053 $.fn.selected = function(select) {
1054 if (select === undefined) {
1057 return this.each(function() {
1059 if (t == 'checkbox' || t == 'radio') {
1060 this.checked = select;
1062 else if (this.tagName.toLowerCase() == 'option') {
1063 var $sel = $(this).parent('select');
1064 if (select && $sel[0] && $sel[0].type == 'select-one') {
1065 // deselect all other options
1066 $sel.find('option').selected(false);
1068 this.selected = select;
1074 $.fn.ajaxSubmit.debug = false;
1076 // helper fn for console logging
1078 if (!$.fn.ajaxSubmit.debug)
1080 var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
1081 if (window.console && window.console.log) {
1082 window.console.log(msg);
1084 else if (window.opera && window.opera.postError) {
1085 window.opera.postError(msg);