3 * version: 3.25.0-2013.01.18
4 * @requires jQuery v1.5 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?
176 // [value] (issue #113), also see comment:
177 // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219
178 var fileInputs
= $('input[type=file]:enabled[value!=""]', this);
180 var hasFileInputs
= fileInputs
.length
> 0;
181 var mp
= 'multipart/form-data';
182 var multipart
= ($form
.attr('enctype') == mp
|| $form
.attr('encoding') == mp
);
184 var fileAPI
= feature
.fileapi
&& feature
.formdata
;
185 log("fileAPI :" + fileAPI
);
186 var shouldUseFrame
= (hasFileInputs
|| multipart
) && !fileAPI
;
190 // options.iframe allows user to force iframe mode
191 // 06-NOV-09: now defaulting to iframe mode if file input is detected
192 if (options
.iframe
!== false && (options
.iframe
|| shouldUseFrame
)) {
193 // hack to fix Safari hang (thanks to Tim Molendijk for this)
194 // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
195 if (options
.closeKeepAlive
) {
196 $.get(options
.closeKeepAlive
, function() {
197 jqxhr
= fileUploadIframe(a
);
201 jqxhr
= fileUploadIframe(a
);
204 else if ((hasFileInputs
|| multipart
) && fileAPI
) {
205 jqxhr
= fileUploadXhr(a
);
208 jqxhr
= $.ajax(options
);
211 $form
.removeData('jqxhr').data('jqxhr', jqxhr
);
213 // clear element array
214 for (var k
=0; k
< elements
.length
; k
++)
217 // fire 'notify' event
218 this.trigger('form-submit-notify', [this, options
]);
221 // utility fn for deep serialization
222 function deepSerialize(extraData
){
223 var serialized
= $.param(extraData
).split('&');
224 var len
= serialized
.length
;
227 for (i
=0; i
< len
; i
++) {
228 // #252; undo param space replacement
229 serialized
[i
] = serialized
[i
].replace(/\+/g,' ');
230 part
= serialized
[i
].split('=');
231 result
[decodeURIComponent(part
[0])] = decodeURIComponent(part
[1]);
236 // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
237 function fileUploadXhr(a
) {
238 var formdata
= new FormData();
240 for (var i
=0; i
< a
.length
; i
++) {
241 formdata
.append(a
[i
].name
, a
[i
].value
);
244 if (options
.extraData
) {
245 var serializedData
= deepSerialize(options
.extraData
);
246 for (var p
in serializedData
)
247 if (serializedData
.hasOwnProperty(p
))
248 formdata
.append(p
, serializedData
[p
]);
253 var s
= $.extend(true, {}, $.ajaxSettings
, options
, {
257 type
: method
|| 'POST'
260 if (options
.uploadProgress
) {
261 // workaround because jqXHR does not expose upload property
263 var xhr
= jQuery
.ajaxSettings
.xhr();
265 xhr
.upload
.onprogress = function(event
) {
267 var position
= event
.loaded
|| event
.position
; /*event.position is deprecated*/
268 var total
= event
.total
;
269 if (event
.lengthComputable
) {
270 percent
= Math
.ceil(position
/ total
* 100);
272 options
.uploadProgress(event
, position
, total
, percent
);
280 var beforeSend
= s
.beforeSend
;
281 s
.beforeSend = function(xhr
, o
) {
284 beforeSend
.call(this, xhr
, o
);
289 // private function for handling file uploads (hat tip to YAHOO!)
290 function fileUploadIframe(a
) {
291 var form
= $form
[0], el
, i
, s
, g
, id
, $io
, io
, xhr
, sub
, n
, timedOut
, timeoutHandle
;
292 var useProp
= !!$.fn
.prop
;
293 var deferred
= $.Deferred();
295 if ($('[name=submit],[id=submit]', form
).length
) {
296 // if there is an input with a name or id of 'submit' then we won't be
297 // able to invoke the submit fn on the form (at least not x-browser)
298 alert('Error: Form elements must not have name or id of "submit".');
304 // ensure that every serialized input is still enabled
305 for (i
=0; i
< elements
.length
; i
++) {
308 el
.prop('disabled', false);
310 el
.removeAttr('disabled');
314 s
= $.extend(true, {}, $.ajaxSettings
, options
);
315 s
.context
= s
.context
|| s
;
316 id
= 'jqFormIO' + (new Date().getTime());
317 if (s
.iframeTarget
) {
318 $io
= $(s
.iframeTarget
);
319 n
= $io
.attr('name');
321 $io
.attr('name', id
);
326 $io
= $('<iframe name="' + id
+ '" src="'+ s
.iframeSrc
+'" />');
327 $io
.css({ position
: 'absolute', top
: '-1000px', left
: '-1000px' });
332 xhr
= { // mock object
338 getAllResponseHeaders: function() {},
339 getResponseHeader: function() {},
340 setRequestHeader: function() {},
341 abort: function(status
) {
342 var e
= (status
=== 'timeout' ? 'timeout' : 'aborted');
343 log('aborting upload... ' + e
);
347 if (io
.contentWindow
.document
.execCommand
) {
348 io
.contentWindow
.document
.execCommand('Stop');
353 $io
.attr('src', s
.iframeSrc
); // abort op in progress
356 s
.error
.call(s
.context
, xhr
, e
, status
);
358 $.event
.trigger("ajaxError", [xhr
, s
, e
]);
360 s
.complete
.call(s
.context
, xhr
, e
);
365 // trigger ajax global events so that activity/block indicators work like normal
366 if (g
&& 0 === $.active
++) {
367 $.event
.trigger("ajaxStart");
370 $.event
.trigger("ajaxSend", [xhr
, s
]);
373 if (s
.beforeSend
&& s
.beforeSend
.call(s
.context
, xhr
, s
) === false) {
385 // add submitting element to data if we know it
389 if (n
&& !sub
.disabled
) {
390 s
.extraData
= s
.extraData
|| {};
391 s
.extraData
[n
] = sub
.value
;
392 if (sub
.type
== "image") {
393 s
.extraData
[n
+'.x'] = form
.clk_x
;
394 s
.extraData
[n
+'.y'] = form
.clk_y
;
399 var CLIENT_TIMEOUT_ABORT
= 1;
400 var SERVER_ABORT
= 2;
402 function getDoc(frame
) {
403 var doc
= frame
.contentWindow
? frame
.contentWindow
.document
: frame
.contentDocument
? frame
.contentDocument
: frame
.document
;
407 // Rails CSRF hack (thanks to Yvan Barthelemy)
408 var csrf_token
= $('meta[name=csrf-token]').attr('content');
409 var csrf_param
= $('meta[name=csrf-param]').attr('content');
410 if (csrf_param
&& csrf_token
) {
411 s
.extraData
= s
.extraData
|| {};
412 s
.extraData
[csrf_param
] = csrf_token
;
415 // take a breath so that pending repaints get some cpu time before the upload starts
416 function doSubmit() {
417 // make sure form attrs are set
418 var t
= $form
.attr('target'), a
= $form
.attr('action');
420 // update form attrs in IE friendly way
421 form
.setAttribute('target',id
);
423 form
.setAttribute('method', 'POST');
426 form
.setAttribute('action', s
.url
);
429 // ie borks in some cases when setting encoding
430 if (! s
.skipEncodingOverride
&& (!method
|| /post/i.test(method
))) {
432 encoding
: 'multipart/form-data',
433 enctype
: 'multipart/form-data'
439 timeoutHandle
= setTimeout(function() { timedOut
= true; cb(CLIENT_TIMEOUT_ABORT
); }, s
.timeout
);
442 // look for server aborts
443 function checkState() {
445 var state
= getDoc(io
).readyState
;
446 log('state = ' + state
);
447 if (state
&& state
.toLowerCase() == 'uninitialized')
448 setTimeout(checkState
,50);
451 log('Server abort: ' , e
, ' (', e
.name
, ')');
454 clearTimeout(timeoutHandle
);
455 timeoutHandle
= undefined;
459 // add "extra" data to form if provided in options
460 var extraInputs
= [];
463 for (var n
in s
.extraData
) {
464 if (s
.extraData
.hasOwnProperty(n
)) {
465 // if using the $.param format that allows for multiple values with the same name
466 if($.isPlainObject(s
.extraData
[n
]) && s
.extraData
[n
].hasOwnProperty('name') && s
.extraData
[n
].hasOwnProperty('value')) {
468 $('<input type="hidden" name="'+s
.extraData
[n
].name
+'">').val(s
.extraData
[n
].value
)
472 $('<input type="hidden" name="'+n
+'">').val(s
.extraData
[n
])
479 if (!s
.iframeTarget
) {
480 // add iframe to doc and submit the form
481 $io
.appendTo('body');
483 io
.attachEvent('onload', cb
);
485 io
.addEventListener('load', cb
, false);
487 setTimeout(checkState
,15);
491 // reset attrs and remove "extra" input elements
492 form
.setAttribute('action',a
);
494 form
.setAttribute('target', t
);
496 $form
.removeAttr('target');
498 $(extraInputs
).remove();
506 setTimeout(doSubmit
, 10); // this lets dom updates render
509 var data
, doc
, domCheckCount
= 50, callbackProcessed
;
512 if (xhr
.aborted
|| callbackProcessed
) {
519 log('cannot access response document: ', ex
);
522 if (e
=== CLIENT_TIMEOUT_ABORT
&& xhr
) {
523 xhr
.abort('timeout');
524 deferred
.reject(xhr
, 'timeout');
527 else if (e
== SERVER_ABORT
&& xhr
) {
528 xhr
.abort('server abort');
529 deferred
.reject(xhr
, 'error', 'server abort');
533 if (!doc
|| doc
.location
.href
== s
.iframeSrc
) {
534 // response not received yet
539 io
.detachEvent('onload', cb
);
541 io
.removeEventListener('load', cb
, false);
543 var status
= 'success', errMsg
;
549 var isXml
= s
.dataType
== 'xml' || doc
.XMLDocument
|| $.isXMLDoc(doc
);
551 if (!isXml
&& window
.opera
&& (doc
.body
=== null || !doc
.body
.innerHTML
)) {
552 if (--domCheckCount
) {
553 // in some browsers (Opera) the iframe DOM is not always traversable when
554 // the onload callback fires, so we loop a bit to accommodate
555 log('requeing onLoad callback, DOM not available');
559 // let this fall through because server response could be an empty document
560 //log('Could not access iframe DOM after mutiple tries.');
561 //throw 'DOMException: not available';
564 //log('response detected');
565 var docRoot
= doc
.body
? doc
.body
: doc
.documentElement
;
566 xhr
.responseText
= docRoot
? docRoot
.innerHTML
: null;
567 xhr
.responseXML
= doc
.XMLDocument
? doc
.XMLDocument
: doc
;
570 xhr
.getResponseHeader = function(header
){
571 var headers
= {'content-type': s
.dataType
};
572 return headers
[header
];
574 // support for XHR 'status' & 'statusText' emulation :
576 xhr
.status
= Number( docRoot
.getAttribute('status') ) || xhr
.status
;
577 xhr
.statusText
= docRoot
.getAttribute('statusText') || xhr
.statusText
;
580 var dt
= (s
.dataType
|| '').toLowerCase();
581 var scr
= /(json|script|text)/.test(dt
);
582 if (scr
|| s
.textarea
) {
583 // see if user embedded response in textarea
584 var ta
= doc
.getElementsByTagName('textarea')[0];
586 xhr
.responseText
= ta
.value
;
587 // support for XHR 'status' & 'statusText' emulation :
588 xhr
.status
= Number( ta
.getAttribute('status') ) || xhr
.status
;
589 xhr
.statusText
= ta
.getAttribute('statusText') || xhr
.statusText
;
592 // account for browsers injecting pre around json response
593 var pre
= doc
.getElementsByTagName('pre')[0];
594 var b
= doc
.getElementsByTagName('body')[0];
596 xhr
.responseText
= pre
.innerHTML
? pre
.innerHTML
: pre
.textContent
;
599 xhr
.responseText
= b
.innerHTML
? b
.innerHTML
: b
.textContent
;
603 else if (dt
== 'xml' && !xhr
.responseXML
&& xhr
.responseText
) {
604 xhr
.responseXML
= toXml(xhr
.responseText
);
608 data
= httpData(xhr
, dt
, s
);
611 status
= 'parsererror';
612 xhr
.error
= errMsg
= (e
|| status
);
616 log('error caught: ',e
);
618 xhr
.error
= errMsg
= (e
|| status
);
622 log('upload aborted');
626 if (xhr
.status
) { // we've set xhr.status
627 status
= (xhr
.status
>= 200 && xhr
.status
< 300 || xhr
.status
=== 304) ? 'success' : 'error';
630 // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
631 if (status
=== 'success') {
633 s
.success
.call(s
.context
, data
, 'success', xhr
);
634 deferred
.resolve(xhr
.responseText
, 'success', xhr
);
636 $.event
.trigger("ajaxSuccess", [xhr
, s
]);
639 if (errMsg
=== undefined)
640 errMsg
= xhr
.statusText
;
642 s
.error
.call(s
.context
, xhr
, status
, errMsg
);
643 deferred
.reject(xhr
, 'error', errMsg
);
645 $.event
.trigger("ajaxError", [xhr
, s
, errMsg
]);
649 $.event
.trigger("ajaxComplete", [xhr
, s
]);
651 if (g
&& ! --$.active
) {
652 $.event
.trigger("ajaxStop");
656 s
.complete
.call(s
.context
, xhr
, status
);
658 callbackProcessed
= true;
660 clearTimeout(timeoutHandle
);
663 setTimeout(function() {
666 xhr
.responseXML
= null;
670 var toXml
= $.parseXML
;
672 var parseJSON
= $.parseJSON
;
674 var httpData = function( xhr
, type
, s
) { // mostly lifted from jq1.4.4
676 var ct
= xhr
.getResponseHeader('content-type') || '',
677 xml
= type
=== 'xml' || !type
&& ct
.indexOf('xml') >= 0,
678 data
= xml
? xhr
.responseXML
: xhr
.responseText
;
680 if (xml
&& data
.documentElement
.nodeName
=== 'parsererror') {
682 $.error('parsererror');
684 if (s
&& s
.dataFilter
) {
685 data
= s
.dataFilter(data
, type
);
687 if (typeof data
=== 'string') {
688 if (type
=== 'json' || !type
&& ct
.indexOf('json') >= 0) {
689 data
= parseJSON(data
);
690 } else if (type
=== "script" || !type
&& ct
.indexOf("javascript") >= 0) {
702 * ajaxForm() provides a mechanism for fully automating form submission.
704 * The advantages of using this method instead of ajaxSubmit() are:
706 * 1: This method will include coordinates for <input type="image" /> elements (if the element
707 * is used to submit the form).
708 * 2. This method will include the submit element's name/value data (for the element that was
709 * used to submit the form).
710 * 3. This method binds the submit() method to the form for you.
712 * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
713 * passes the options argument along after properly binding events for submit elements and
716 $.fn
.ajaxForm = function(options
) {
717 options
= options
|| {};
718 options
.delegation
= options
.delegation
&& $.isFunction($.fn
.on
);
720 // in jQuery 1.3+ we can fix mistakes with the ready state
721 if (!options
.delegation
&& this.length
=== 0) {
722 var o
= { s
: this.selector
, c
: this.context
};
723 if (!$.isReady
&& o
.s
) {
724 log('DOM not ready, queuing ajaxForm');
726 $(o
.s
,o
.c
).ajaxForm(options
);
730 // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
731 log('terminating; zero elements found by selector' + ($.isReady
? '' : ' (DOM not ready)'));
735 if ( options
.delegation
) {
737 .off('submit.form-plugin', this.selector
, doAjaxSubmit
)
738 .off('click.form-plugin', this.selector
, captureSubmittingElement
)
739 .on('submit.form-plugin', this.selector
, options
, doAjaxSubmit
)
740 .on('click.form-plugin', this.selector
, options
, captureSubmittingElement
);
744 return this.ajaxFormUnbind()
745 .bind('submit.form-plugin', options
, doAjaxSubmit
)
746 .bind('click.form-plugin', options
, captureSubmittingElement
);
749 // private event handlers
750 function doAjaxSubmit(e
) {
751 /*jshint validthis:true */
752 var options
= e
.data
;
753 if (!e
.isDefaultPrevented()) { // if event has been canceled, don't proceed
755 $(this).ajaxSubmit(options
);
759 function captureSubmittingElement(e
) {
760 /*jshint validthis:true */
761 var target
= e
.target
;
763 if (!($el
.is("[type=submit],[type=image]"))) {
764 // is this a child element of the submit el? (ex: a span within a button)
765 var t
= $el
.closest('[type=submit]');
766 if (t
.length
=== 0) {
773 if (target
.type
== 'image') {
774 if (e
.offsetX
!== undefined) {
775 form
.clk_x
= e
.offsetX
;
776 form
.clk_y
= e
.offsetY
;
777 } else if (typeof $.fn
.offset
== 'function') {
778 var offset
= $el
.offset();
779 form
.clk_x
= e
.pageX
- offset
.left
;
780 form
.clk_y
= e
.pageY
- offset
.top
;
782 form
.clk_x
= e
.pageX
- target
.offsetLeft
;
783 form
.clk_y
= e
.pageY
- target
.offsetTop
;
787 setTimeout(function() { form
.clk
= form
.clk_x
= form
.clk_y
= null; }, 100);
791 // ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
792 $.fn
.ajaxFormUnbind = function() {
793 return this.unbind('submit.form-plugin click.form-plugin');
797 * formToArray() gathers form element data into an array of objects that can
798 * be passed to any of the following ajax functions: $.get, $.post, or load.
799 * Each object in the array has both a 'name' and 'value' property. An example of
800 * an array for a simple login form might be:
802 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
804 * It is this array that is passed to pre-submit callback functions provided to the
805 * ajaxSubmit() and ajaxForm() methods.
807 $.fn
.formToArray = function(semantic
, elements
) {
809 if (this.length
=== 0) {
814 var els
= semantic
? form
.getElementsByTagName('*') : form
.elements
;
819 var i
,j
,n
,v
,el
,max
,jmax
;
820 for(i
=0, max
=els
.length
; i
< max
; i
++) {
827 if (semantic
&& form
.clk
&& el
.type
== "image") {
828 // handle image inputs on the fly when semantic == true
829 if(!el
.disabled
&& form
.clk
== el
) {
830 a
.push({name
: n
, value
: $(el
).val(), type
: el
.type
});
831 a
.push({name
: n
+'.x', value
: form
.clk_x
}, {name
: n
+'.y', value
: form
.clk_y
});
836 v
= $.fieldValue(el
, true);
837 if (v
&& v
.constructor == Array
) {
840 for(j
=0, jmax
=v
.length
; j
< jmax
; j
++) {
841 a
.push({name
: n
, value
: v
[j
]});
844 else if (feature
.fileapi
&& el
.type
== 'file' && !el
.disabled
) {
847 var files
= el
.files
;
849 for (j
=0; j
< files
.length
; j
++) {
850 a
.push({name
: n
, value
: files
[j
], type
: el
.type
});
855 a
.push({ name
: n
, value
: '', type
: el
.type
});
858 else if (v
!== null && typeof v
!= 'undefined') {
861 a
.push({name
: n
, value
: v
, type
: el
.type
, required
: el
.required
});
865 if (!semantic
&& form
.clk
) {
866 // input type=='image' are not found in elements array! handle it here
867 var $input
= $(form
.clk
), input
= $input
[0];
869 if (n
&& !input
.disabled
&& input
.type
== 'image') {
870 a
.push({name
: n
, value
: $input
.val()});
871 a
.push({name
: n
+'.x', value
: form
.clk_x
}, {name
: n
+'.y', value
: form
.clk_y
});
878 * Serializes form data into a 'submittable' string. This method will return a string
879 * in the format: name1=value1&name2=value2
881 $.fn
.formSerialize = function(semantic
) {
882 //hand off to jQuery.param for proper encoding
883 return $.param(this.formToArray(semantic
));
887 * Serializes all field elements in the jQuery object into a query string.
888 * This method will return a string in the format: name1=value1&name2=value2
890 $.fn
.fieldSerialize = function(successful
) {
892 this.each(function() {
897 var v
= $.fieldValue(this, successful
);
898 if (v
&& v
.constructor == Array
) {
899 for (var i
=0,max
=v
.length
; i
< max
; i
++) {
900 a
.push({name
: n
, value
: v
[i
]});
903 else if (v
!== null && typeof v
!= 'undefined') {
904 a
.push({name
: this.name
, value
: v
});
907 //hand off to jQuery.param for proper encoding
912 * Returns the value(s) of the element in the matched set. For example, consider the following form:
915 * <input name="A" type="text" />
916 * <input name="A" type="text" />
917 * <input name="B" type="checkbox" value="B1" />
918 * <input name="B" type="checkbox" value="B2"/>
919 * <input name="C" type="radio" value="C1" />
920 * <input name="C" type="radio" value="C2" />
923 * var v = $('input[type=text]').fieldValue();
924 * // if no values are entered into the text inputs
926 * // if values entered into the text inputs are 'foo' and 'bar'
929 * var v = $('input[type=checkbox]').fieldValue();
930 * // if neither checkbox is checked
932 * // if both checkboxes are checked
935 * var v = $('input[type=radio]').fieldValue();
936 * // if neither radio is checked
938 * // if first radio is checked
941 * The successful argument controls whether or not the field element must be 'successful'
942 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
943 * The default value of the successful argument is true. If this value is false the value(s)
944 * for each element is returned.
946 * Note: This method *always* returns an array. If no valid value can be determined the
947 * array will be empty, otherwise it will contain one or more values.
949 $.fn
.fieldValue = function(successful
) {
950 for (var val
=[], i
=0, max
=this.length
; i
< max
; i
++) {
952 var v
= $.fieldValue(el
, successful
);
953 if (v
=== null || typeof v
== 'undefined' || (v
.constructor == Array
&& !v
.length
)) {
956 if (v
.constructor == Array
)
965 * Returns the value of the field element.
967 $.fieldValue = function(el
, successful
) {
968 var n
= el
.name
, t
= el
.type
, tag
= el
.tagName
.toLowerCase();
969 if (successful
=== undefined) {
973 if (successful
&& (!n
|| el
.disabled
|| t
== 'reset' || t
== 'button' ||
974 (t
== 'checkbox' || t
== 'radio') && !el
.checked
||
975 (t
== 'submit' || t
== 'image') && el
.form
&& el
.form
.clk
!= el
||
976 tag
== 'select' && el
.selectedIndex
== -1)) {
980 if (tag
== 'select') {
981 var index
= el
.selectedIndex
;
985 var a
= [], ops
= el
.options
;
986 var one
= (t
== 'select-one');
987 var max
= (one
? index
+1 : ops
.length
);
988 for(var i
=(one
? index
: 0); i
< max
; i
++) {
992 if (!v
) { // extra pain for IE...
993 v
= (op
.attributes
&& op
.attributes
['value'] && !(op
.attributes
['value'].specified
)) ? op
.text
: op
.value
;
1007 * Clears the form data. Takes the following actions on the form's input fields:
1008 * - input text fields will have their 'value' property set to the empty string
1009 * - select elements will have their 'selectedIndex' property set to -1
1010 * - checkbox and radio inputs will have their 'checked' property set to false
1011 * - inputs of type submit, button, reset, and hidden will *not* be effected
1012 * - button elements will *not* be effected
1014 $.fn
.clearForm = function(includeHidden
) {
1015 return this.each(function() {
1016 $('input,select,textarea', this).clearFields(includeHidden
);
1021 * Clears the selected form elements.
1023 $.fn
.clearFields
= $.fn
.clearInputs = function(includeHidden
) {
1024 var re
= /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
1025 return this.each(function() {
1026 var t
= this.type
, tag
= this.tagName
.toLowerCase();
1027 if (re
.test(t
) || tag
== 'textarea') {
1030 else if (t
== 'checkbox' || t
== 'radio') {
1031 this.checked
= false;
1033 else if (tag
== 'select') {
1034 this.selectedIndex
= -1;
1036 else if (t
== "file") {
1037 if (/MSIE/.test(navigator
.userAgent
)) {
1038 $(this).replaceWith($(this).clone());
1043 else if (includeHidden
) {
1044 // includeHidden can be the value true, or it can be a selector string
1045 // indicating a special test; for example:
1046 // $('#myForm').clearForm('.special:hidden')
1047 // the above would clean hidden inputs that have the class of 'special'
1048 if ( (includeHidden
=== true && /hidden/.test(t
)) ||
1049 (typeof includeHidden
== 'string' && $(this).is(includeHidden
)) )
1056 * Resets the form data. Causes all form elements to be reset to their original value.
1058 $.fn
.resetForm = function() {
1059 return this.each(function() {
1060 // guard against an input with the name of 'reset'
1061 // note that IE reports the reset function as an 'object'
1062 if (typeof this.reset
== 'function' || (typeof this.reset
== 'object' && !this.reset
.nodeType
)) {
1069 * Enables or disables any matching elements.
1071 $.fn
.enable = function(b
) {
1072 if (b
=== undefined) {
1075 return this.each(function() {
1081 * Checks/unchecks any matching checkboxes or radio buttons and
1082 * selects/deselects and matching option elements.
1084 $.fn
.selected = function(select
) {
1085 if (select
=== undefined) {
1088 return this.each(function() {
1090 if (t
== 'checkbox' || t
== 'radio') {
1091 this.checked
= select
;
1093 else if (this.tagName
.toLowerCase() == 'option') {
1094 var $sel
= $(this).parent('select');
1095 if (select
&& $sel
[0] && $sel
[0].type
== 'select-one') {
1096 // deselect all other options
1097 $sel
.find('option').selected(false);
1099 this.selected
= select
;
1105 $.fn
.ajaxSubmit
.debug
= false;
1107 // helper fn for console logging
1109 if (!$.fn
.ajaxSubmit
.debug
)
1111 var msg
= '[jquery.form] ' + Array
.prototype.join
.call(arguments
,'');
1112 if (window
.console
&& window
.console
.log
) {
1113 window
.console
.log(msg
);
1115 else if (window
.opera
&& window
.opera
.postError
) {
1116 window
.opera
.postError(msg
);