jquery.form.js
上传用户:stephen_wu
上传日期:2008-07-05
资源大小:1757k
文件大小:32k
源码类别:

网络

开发平台:

Unix_Linux

  1. /*
  2.  * jQuery Form Plugin
  3.  * version: 2.07 (03/04/2008)
  4.  * @requires jQuery v1.2.2 or later
  5.  *
  6.  * Examples at: http://malsup.com/jquery/form/
  7.  * Dual licensed under the MIT and GPL licenses:
  8.  *   http://www.opensource.org/licenses/mit-license.php
  9.  *   http://www.gnu.org/licenses/gpl.html
  10.  *
  11.  * Revision: $Id$
  12.  */
  13.  (function($) {
  14. /**
  15.  * ajaxSubmit() provides a mechanism for submitting an HTML form using AJAX.
  16.  *
  17.  * ajaxSubmit accepts a single argument which can be either a success callback function
  18.  * or an options Object.  If a function is provided it will be invoked upon successful
  19.  * completion of the submit and will be passed the response from the server.
  20.  * If an options Object is provided, the following attributes are supported:
  21.  *
  22.  *  target:   Identifies the element(s) in the page to be updated with the server response.
  23.  *            This value may be specified as a jQuery selection string, a jQuery object,
  24.  *            or a DOM element.
  25.  *            default value: null
  26.  *
  27.  *  url:      URL to which the form data will be submitted.
  28.  *            default value: value of form's 'action' attribute
  29.  *
  30.  *  type:     The method in which the form data should be submitted, 'GET' or 'POST'.
  31.  *            default value: value of form's 'method' attribute (or 'GET' if none found)
  32.  *
  33.  *  data:     Additional data to add to the request, specified as key/value pairs (see $.ajax).
  34.  *
  35.  *  beforeSubmit:  Callback method to be invoked before the form is submitted.
  36.  *            default value: null
  37.  *
  38.  *  success:  Callback method to be invoked after the form has been successfully submitted
  39.  *            and the response has been returned from the server
  40.  *            default value: null
  41.  *
  42.  *  dataType: Expected dataType of the response.  One of: null, 'xml', 'script', or 'json'
  43.  *            default value: null
  44.  *
  45.  *  semantic: Boolean flag indicating whether data must be submitted in semantic order (slower).
  46.  *            default value: false
  47.  *
  48.  *  resetForm: Boolean flag indicating whether the form should be reset if the submit is successful
  49.  *
  50.  *  clearForm: Boolean flag indicating whether the form should be cleared if the submit is successful
  51.  *
  52.  *
  53.  * The 'beforeSubmit' callback can be provided as a hook for running pre-submit logic or for
  54.  * validating the form data.  If the 'beforeSubmit' callback returns false then the form will
  55.  * not be submitted. The 'beforeSubmit' callback is invoked with three arguments: the form data
  56.  * in array format, the jQuery object, and the options object passed into ajaxSubmit.
  57.  * The form data array takes the following form:
  58.  *
  59.  *     [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
  60.  *
  61.  * If a 'success' callback method is provided it is invoked after the response has been returned
  62.  * from the server.  It is passed the responseText or responseXML value (depending on dataType).
  63.  * See jQuery.ajax for further details.
  64.  *
  65.  *
  66.  * The dataType option provides a means for specifying how the server response should be handled.
  67.  * This maps directly to the jQuery.httpData method.  The following values are supported:
  68.  *
  69.  *      'xml':    if dataType == 'xml' the server response is treated as XML and the 'success'
  70.  *                   callback method, if specified, will be passed the responseXML value
  71.  *      'json':   if dataType == 'json' the server response will be evaluted and passed to
  72.  *                   the 'success' callback, if specified
  73.  *      'script': if dataType == 'script' the server response is evaluated in the global context
  74.  *
  75.  *
  76.  * Note that it does not make sense to use both the 'target' and 'dataType' options.  If both
  77.  * are provided the target will be ignored.
  78.  *
  79.  * The semantic argument can be used to force form serialization in semantic order.
  80.  * This is normally true anyway, unless the form contains input elements of type='image'.
  81.  * If your form must be submitted with name/value pairs in semantic order and your form
  82.  * contains an input of type='image" then pass true for this arg, otherwise pass false
  83.  * (or nothing) to avoid the overhead for this logic.
  84.  *
  85.  *
  86.  * When used on its own, ajaxSubmit() is typically bound to a form's submit event like this:
  87.  *
  88.  * $("#form-id").submit(function() {
  89.  *     $(this).ajaxSubmit(options);
  90.  *     return false; // cancel conventional submit
  91.  * });
  92.  *
  93.  * When using ajaxForm(), however, this is done for you.
  94.  *
  95.  * @example
  96.  * $('#myForm').ajaxSubmit(function(data) {
  97.  *     alert('Form submit succeeded! Server returned: ' + data);
  98.  * });
  99.  * @desc Submit form and alert server response
  100.  *
  101.  *
  102.  * @example
  103.  * var options = {
  104.  *     target: '#myTargetDiv'
  105.  * };
  106.  * $('#myForm').ajaxSubmit(options);
  107.  * @desc Submit form and update page element with server response
  108.  *
  109.  *
  110.  * @example
  111.  * var options = {
  112.  *     success: function(responseText) {
  113.  *         alert(responseText);
  114.  *     }
  115.  * };
  116.  * $('#myForm').ajaxSubmit(options);
  117.  * @desc Submit form and alert the server response
  118.  *
  119.  *
  120.  * @example
  121.  * var options = {
  122.  *     beforeSubmit: function(formArray, jqForm) {
  123.  *         if (formArray.length == 0) {
  124.  *             alert('Please enter data.');
  125.  *             return false;
  126.  *         }
  127.  *     }
  128.  * };
  129.  * $('#myForm').ajaxSubmit(options);
  130.  * @desc Pre-submit validation which aborts the submit operation if form data is empty
  131.  *
  132.  *
  133.  * @example
  134.  * var options = {
  135.  *     url: myJsonUrl.php,
  136.  *     dataType: 'json',
  137.  *     success: function(data) {
  138.  *        // 'data' is an object representing the the evaluated json data
  139.  *     }
  140.  * };
  141.  * $('#myForm').ajaxSubmit(options);
  142.  * @desc json data returned and evaluated
  143.  *
  144.  *
  145.  * @example
  146.  * var options = {
  147.  *     url: myXmlUrl.php,
  148.  *     dataType: 'xml',
  149.  *     success: function(responseXML) {
  150.  *        // responseXML is XML document object
  151.  *        var data = $('myElement', responseXML).text();
  152.  *     }
  153.  * };
  154.  * $('#myForm').ajaxSubmit(options);
  155.  * @desc XML data returned from server
  156.  *
  157.  *
  158.  * @example
  159.  * var options = {
  160.  *     resetForm: true
  161.  * };
  162.  * $('#myForm').ajaxSubmit(options);
  163.  * @desc submit form and reset it if successful
  164.  *
  165.  * @example
  166.  * $('#myForm).submit(function() {
  167.  *    $(this).ajaxSubmit();
  168.  *    return false;
  169.  * });
  170.  * @desc Bind form's submit event to use ajaxSubmit
  171.  *
  172.  *
  173.  * @name ajaxSubmit
  174.  * @type jQuery
  175.  * @param options  object literal containing options which control the form submission process
  176.  * @cat Plugins/Form
  177.  * @return jQuery
  178.  */
  179. $.fn.ajaxSubmit = function(options) {
  180.     if (typeof options == 'function')
  181.         options = { success: options };
  182.     options = $.extend({
  183.         url:  this.attr('action') || window.location.toString(),
  184.         type: this.attr('method') || 'GET'
  185.     }, options || {});
  186.     // hook for manipulating the form data before it is extracted;
  187.     // convenient for use with rich editors like tinyMCE or FCKEditor
  188.     var veto = {};
  189.     this.trigger('form-pre-serialize', [this, options, veto]);
  190.     if (veto.veto) return this;
  191.     var a = this.formToArray(options.semantic);
  192.     if (options.data) {
  193.         options.extraData = options.data;
  194.         for (var n in options.data)
  195.             a.push( { name: n, value: options.data[n] } );
  196.     }
  197.     // give pre-submit callback an opportunity to abort the submit
  198.     if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) return this;
  199.     // fire vetoable 'validate' event
  200.     this.trigger('form-submit-validate', [a, this, options, veto]);
  201.     if (veto.veto) return this;
  202.     var q = $.param(a);
  203.     if (options.type.toUpperCase() == 'GET') {
  204.         options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
  205.         options.data = null;  // data is null for 'get'
  206.     }
  207.     else
  208.         options.data = q; // data is the query string for 'post'
  209.     var $form = this, callbacks = [];
  210.     if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
  211.     if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
  212.     // perform a load on the target only if dataType is not provided
  213.     if (!options.dataType && options.target) {
  214.         var oldSuccess = options.success || function(){};
  215.         callbacks.push(function(data) {
  216.             $(options.target).html(data).each(oldSuccess, arguments);
  217.         });
  218.     }
  219.     else if (options.success)
  220.         callbacks.push(options.success);
  221.     options.success = function(data, status) {
  222.         for (var i=0, max=callbacks.length; i < max; i++)
  223.             callbacks[i](data, status, $form);
  224.     };
  225.     // are there files to upload?
  226.     var files = $('input:file', this).fieldValue();
  227.     var found = false;
  228.     for (var j=0; j < files.length; j++)
  229.         if (files[j])
  230.             found = true;
  231.     // options.iframe allows user to force iframe mode
  232.    if (options.iframe || found) { 
  233.        // hack to fix Safari hang (thanks to Tim Molendijk for this)
  234.        // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
  235.        if ($.browser.safari && options.closeKeepAlive)
  236.            $.get(options.closeKeepAlive, fileUpload);
  237.        else
  238.            fileUpload();
  239.        }
  240.    else
  241.        $.ajax(options);
  242.     // fire 'notify' event
  243.     this.trigger('form-submit-notify', [this, options]);
  244.     return this;
  245.     // private function for handling file uploads (hat tip to YAHOO!)
  246.     function fileUpload() {
  247.         var form = $form[0];
  248.         var opts = $.extend({}, $.ajaxSettings, options);
  249.         var id = 'jqFormIO' + (new Date().getTime());
  250.         var $io = $('<iframe id="' + id + '" name="' + id + '" />');
  251.         var io = $io[0];
  252.         var op8 = $.browser.opera && window.opera.version() < 9;
  253.         if ($.browser.msie || op8) io.src = 'javascript:false;document.write("");';
  254.         $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
  255.         var xhr = { // mock object
  256.             responseText: null,
  257.             responseXML: null,
  258.             status: 0,
  259.             statusText: 'n/a',
  260.             getAllResponseHeaders: function() {},
  261.             getResponseHeader: function() {},
  262.             setRequestHeader: function() {}
  263.         };
  264.         var g = opts.global;
  265.         // trigger ajax global events so that activity/block indicators work like normal
  266.         if (g && ! $.active++) $.event.trigger("ajaxStart");
  267.         if (g) $.event.trigger("ajaxSend", [xhr, opts]);
  268.         var cbInvoked = 0;
  269.         var timedOut = 0;
  270.         // take a breath so that pending repaints get some cpu time before the upload starts
  271.         setTimeout(function() {
  272.             // make sure form attrs are set
  273.             var t = $form.attr('target'), a = $form.attr('action');
  274.             $form.attr({
  275.                 target:   id,
  276.                 encoding: 'multipart/form-data',
  277.                 enctype:  'multipart/form-data',
  278.                 method:   'POST',
  279.                 action:   opts.url
  280.             });
  281.             // support timout
  282.             if (opts.timeout)
  283.                 setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
  284.             // add "extra" data to form if provided in options
  285.             var extraInputs = [];
  286.             try {
  287.                 if (options.extraData)
  288.                     for (var n in options.extraData)
  289.                         extraInputs.push(
  290.                             $('<input type="hidden" name="'+n+'" value="'+options.extraData[n]+'" />')
  291.                                 .appendTo(form)[0]);
  292.             
  293.                 // add iframe to doc and submit the form
  294.                 $io.appendTo('body');
  295.                 io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
  296.                 form.submit();
  297.             }
  298.             finally {
  299.                 // reset attrs and remove "extra" input elements
  300.                 $form.attr('action', a);
  301.                 t ? $form.attr('target', t) : $form.removeAttr('target');
  302.                 $(extraInputs).remove();
  303.             }
  304.         }, 10);
  305.         function cb() {
  306.             if (cbInvoked++) return;
  307.             io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
  308.             var ok = true;
  309.             try {
  310.                 if (timedOut) throw 'timeout';
  311.                 // extract the server response from the iframe
  312.                 var data, doc;
  313.                 doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
  314.                 xhr.responseText = doc.body ? doc.body.innerHTML : null;
  315.                 xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
  316.                 xhr.getResponseHeader = function(header){
  317.                     var headers = {'content-type': opts.dataType};
  318.                     return headers[header];
  319.                 };
  320.                 if (opts.dataType == 'json' || opts.dataType == 'script') {
  321.                     var ta = doc.getElementsByTagName('textarea')[0];
  322.                     xhr.responseText = ta ? ta.value : xhr.responseText;
  323.                 }
  324.                 else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
  325.                     xhr.responseXML = toXml(xhr.responseText);
  326.                 }
  327.                 data = $.httpData(xhr, opts.dataType);
  328.             }
  329.             catch(e){
  330.                 ok = false;
  331.                 $.handleError(opts, xhr, 'error', e);
  332.             }
  333.             // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
  334.             if (ok) {
  335.                 opts.success(data, 'success');
  336.                 if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
  337.             }
  338.             if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
  339.             if (g && ! --$.active) $.event.trigger("ajaxStop");
  340.             if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
  341.             // clean up
  342.             setTimeout(function() {
  343.                 $io.remove();
  344.                 xhr.responseXML = null;
  345.             }, 100);
  346.         };
  347.         function toXml(s, doc) {
  348.             if (window.ActiveXObject) {
  349.                 doc = new ActiveXObject('Microsoft.XMLDOM');
  350.                 doc.async = 'false';
  351.                 doc.loadXML(s);
  352.             }
  353.             else
  354.                 doc = (new DOMParser()).parseFromString(s, 'text/xml');
  355.             return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
  356.         };
  357.     };
  358. };
  359. /**
  360.  * ajaxForm() provides a mechanism for fully automating form submission.
  361.  *
  362.  * The advantages of using this method instead of ajaxSubmit() are:
  363.  *
  364.  * 1: This method will include coordinates for <input type="image" /> elements (if the element
  365.  *    is used to submit the form).
  366.  * 2. This method will include the submit element's name/value data (for the element that was
  367.  *    used to submit the form).
  368.  * 3. This method binds the submit() method to the form for you.
  369.  *
  370.  * Note that for accurate x/y coordinates of image submit elements in all browsers
  371.  * you need to also use the "dimensions" plugin (this method will auto-detect its presence).
  372.  *
  373.  * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
  374.  * passes the options argument along after properly binding events for submit elements and
  375.  * the form itself.  See ajaxSubmit for a full description of the options argument.
  376.  *
  377.  *
  378.  * @example
  379.  * var options = {
  380.  *     target: '#myTargetDiv'
  381.  * };
  382.  * $('#myForm').ajaxSForm(options);
  383.  * @desc Bind form's submit event so that 'myTargetDiv' is updated with the server response
  384.  *       when the form is submitted.
  385.  *
  386.  *
  387.  * @example
  388.  * var options = {
  389.  *     success: function(responseText) {
  390.  *         alert(responseText);
  391.  *     }
  392.  * };
  393.  * $('#myForm').ajaxSubmit(options);
  394.  * @desc Bind form's submit event so that server response is alerted after the form is submitted.
  395.  *
  396.  *
  397.  * @example
  398.  * var options = {
  399.  *     beforeSubmit: function(formArray, jqForm) {
  400.  *         if (formArray.length == 0) {
  401.  *             alert('Please enter data.');
  402.  *             return false;
  403.  *         }
  404.  *     }
  405.  * };
  406.  * $('#myForm').ajaxSubmit(options);
  407.  * @desc Bind form's submit event so that pre-submit callback is invoked before the form
  408.  *       is submitted.
  409.  *
  410.  *
  411.  * @name   ajaxForm
  412.  * @param  options  object literal containing options which control the form submission process
  413.  * @return jQuery
  414.  * @cat    Plugins/Form
  415.  * @type   jQuery
  416.  */
  417. $.fn.ajaxForm = function(options) {
  418.     return this.ajaxFormUnbind().bind('submit.form-plugin',function() {
  419.         $(this).ajaxSubmit(options);
  420.         return false;
  421.     }).each(function() {
  422.         // store options in hash
  423.         $(":submit,input:image", this).bind('click.form-plugin',function(e) {
  424.             var $form = this.form;
  425.             $form.clk = this;
  426.             if (this.type == 'image') {
  427.                 if (e.offsetX != undefined) {
  428.                     $form.clk_x = e.offsetX;
  429.                     $form.clk_y = e.offsetY;
  430.                 } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
  431.                     var offset = $(this).offset();
  432.                     $form.clk_x = e.pageX - offset.left;
  433.                     $form.clk_y = e.pageY - offset.top;
  434.                 } else {
  435.                     $form.clk_x = e.pageX - this.offsetLeft;
  436.                     $form.clk_y = e.pageY - this.offsetTop;
  437.                 }
  438.             }
  439.             // clear form vars
  440.             setTimeout(function() { $form.clk = $form.clk_x = $form.clk_y = null; }, 10);
  441.         });
  442.     });
  443. };
  444. /**
  445.  * ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
  446.  *
  447.  * @name   ajaxFormUnbind
  448.  * @return jQuery
  449.  * @cat    Plugins/Form
  450.  * @type   jQuery
  451.  */
  452. $.fn.ajaxFormUnbind = function() {
  453.     this.unbind('submit.form-plugin');
  454.     return this.each(function() {
  455.         $(":submit,input:image", this).unbind('click.form-plugin');
  456.     });
  457. };
  458. /**
  459.  * formToArray() gathers form element data into an array of objects that can
  460.  * be passed to any of the following ajax functions: $.get, $.post, or load.
  461.  * Each object in the array has both a 'name' and 'value' property.  An example of
  462.  * an array for a simple login form might be:
  463.  *
  464.  * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
  465.  *
  466.  * It is this array that is passed to pre-submit callback functions provided to the
  467.  * ajaxSubmit() and ajaxForm() methods.
  468.  *
  469.  * The semantic argument can be used to force form serialization in semantic order.
  470.  * This is normally true anyway, unless the form contains input elements of type='image'.
  471.  * If your form must be submitted with name/value pairs in semantic order and your form
  472.  * contains an input of type='image" then pass true for this arg, otherwise pass false
  473.  * (or nothing) to avoid the overhead for this logic.
  474.  *
  475.  * @example var data = $("#myForm").formToArray();
  476.  * $.post( "myscript.cgi", data );
  477.  * @desc Collect all the data from a form and submit it to the server.
  478.  *
  479.  * @name formToArray
  480.  * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
  481.  * @type Array<Object>
  482.  * @cat Plugins/Form
  483.  */
  484. $.fn.formToArray = function(semantic) {
  485.     var a = [];
  486.     if (this.length == 0) return a;
  487.     var form = this[0];
  488.     var els = semantic ? form.getElementsByTagName('*') : form.elements;
  489.     if (!els) return a;
  490.     for(var i=0, max=els.length; i < max; i++) {
  491.         var el = els[i];
  492.         var n = el.name;
  493.         if (!n) continue;
  494.         if (semantic && form.clk && el.type == "image") {
  495.             // handle image inputs on the fly when semantic == true
  496.             if(!el.disabled && form.clk == el)
  497.                 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
  498.             continue;
  499.         }
  500.         var v = $.fieldValue(el, true);
  501.         if (v && v.constructor == Array) {
  502.             for(var j=0, jmax=v.length; j < jmax; j++)
  503.                 a.push({name: n, value: v[j]});
  504.         }
  505.         else if (v !== null && typeof v != 'undefined')
  506.             a.push({name: n, value: v});
  507.     }
  508.     if (!semantic && form.clk) {
  509.         // input type=='image' are not found in elements array! handle them here
  510.         var inputs = form.getElementsByTagName("input");
  511.         for(var i=0, max=inputs.length; i < max; i++) {
  512.             var input = inputs[i];
  513.             var n = input.name;
  514.             if(n && !input.disabled && input.type == "image" && form.clk == input)
  515.                 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
  516.         }
  517.     }
  518.     return a;
  519. };
  520. /**
  521.  * Serializes form data into a 'submittable' string. This method will return a string
  522.  * in the format: name1=value1&amp;name2=value2
  523.  *
  524.  * The semantic argument can be used to force form serialization in semantic order.
  525.  * If your form must be submitted with name/value pairs in semantic order then pass
  526.  * true for this arg, otherwise pass false (or nothing) to avoid the overhead for
  527.  * this logic (which can be significant for very large forms).
  528.  *
  529.  * @example var data = $("#myForm").formSerialize();
  530.  * $.ajax('POST', "myscript.cgi", data);
  531.  * @desc Collect all the data from a form into a single string
  532.  *
  533.  * @name formSerialize
  534.  * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
  535.  * @type String
  536.  * @cat Plugins/Form
  537.  */
  538. $.fn.formSerialize = function(semantic) {
  539.     //hand off to jQuery.param for proper encoding
  540.     return $.param(this.formToArray(semantic));
  541. };
  542. /**
  543.  * Serializes all field elements in the jQuery object into a query string.
  544.  * This method will return a string in the format: name1=value1&amp;name2=value2
  545.  *
  546.  * The successful argument controls whether or not serialization is limited to
  547.  * 'successful' controls (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
  548.  * The default value of the successful argument is true.
  549.  *
  550.  * @example var data = $("input").fieldSerialize();
  551.  * @desc Collect the data from all successful input elements into a query string
  552.  *
  553.  * @example var data = $(":radio").fieldSerialize();
  554.  * @desc Collect the data from all successful radio input elements into a query string
  555.  *
  556.  * @example var data = $("#myForm :checkbox").fieldSerialize();
  557.  * @desc Collect the data from all successful checkbox input elements in myForm into a query string
  558.  *
  559.  * @example var data = $("#myForm :checkbox").fieldSerialize(false);
  560.  * @desc Collect the data from all checkbox elements in myForm (even the unchecked ones) into a query string
  561.  *
  562.  * @example var data = $(":input").fieldSerialize();
  563.  * @desc Collect the data from all successful input, select, textarea and button elements into a query string
  564.  *
  565.  * @name fieldSerialize
  566.  * @param successful true if only successful controls should be serialized (default is true)
  567.  * @type String
  568.  * @cat Plugins/Form
  569.  */
  570. $.fn.fieldSerialize = function(successful) {
  571.     var a = [];
  572.     this.each(function() {
  573.         var n = this.name;
  574.         if (!n) return;
  575.         var v = $.fieldValue(this, successful);
  576.         if (v && v.constructor == Array) {
  577.             for (var i=0,max=v.length; i < max; i++)
  578.                 a.push({name: n, value: v[i]});
  579.         }
  580.         else if (v !== null && typeof v != 'undefined')
  581.             a.push({name: this.name, value: v});
  582.     });
  583.     //hand off to jQuery.param for proper encoding
  584.     return $.param(a);
  585. };
  586. /**
  587.  * Returns the value(s) of the element in the matched set.  For example, consider the following form:
  588.  *
  589.  *  <form><fieldset>
  590.  *      <input name="A" type="text" />
  591.  *      <input name="A" type="text" />
  592.  *      <input name="B" type="checkbox" value="B1" />
  593.  *      <input name="B" type="checkbox" value="B2"/>
  594.  *      <input name="C" type="radio" value="C1" />
  595.  *      <input name="C" type="radio" value="C2" />
  596.  *  </fieldset></form>
  597.  *
  598.  *  var v = $(':text').fieldValue();
  599.  *  // if no values are entered into the text inputs
  600.  *  v == ['','']
  601.  *  // if values entered into the text inputs are 'foo' and 'bar'
  602.  *  v == ['foo','bar']
  603.  *
  604.  *  var v = $(':checkbox').fieldValue();
  605.  *  // if neither checkbox is checked
  606.  *  v === undefined
  607.  *  // if both checkboxes are checked
  608.  *  v == ['B1', 'B2']
  609.  *
  610.  *  var v = $(':radio').fieldValue();
  611.  *  // if neither radio is checked
  612.  *  v === undefined
  613.  *  // if first radio is checked
  614.  *  v == ['C1']
  615.  *
  616.  * The successful argument controls whether or not the field element must be 'successful'
  617.  * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
  618.  * The default value of the successful argument is true.  If this value is false the value(s)
  619.  * for each element is returned.
  620.  *
  621.  * Note: This method *always* returns an array.  If no valid value can be determined the
  622.  *       array will be empty, otherwise it will contain one or more values.
  623.  *
  624.  * @example var data = $("#myPasswordElement").fieldValue();
  625.  * alert(data[0]);
  626.  * @desc Alerts the current value of the myPasswordElement element
  627.  *
  628.  * @example var data = $("#myForm :input").fieldValue();
  629.  * @desc Get the value(s) of the form elements in myForm
  630.  *
  631.  * @example var data = $("#myForm :checkbox").fieldValue();
  632.  * @desc Get the value(s) for the successful checkbox element(s) in the jQuery object.
  633.  *
  634.  * @example var data = $("#mySingleSelect").fieldValue();
  635.  * @desc Get the value(s) of the select control
  636.  *
  637.  * @example var data = $(':text').fieldValue();
  638.  * @desc Get the value(s) of the text input or textarea elements
  639.  *
  640.  * @example var data = $("#myMultiSelect").fieldValue();
  641.  * @desc Get the values for the select-multiple control
  642.  *
  643.  * @name fieldValue
  644.  * @param Boolean successful true if only the values for successful controls should be returned (default is true)
  645.  * @type Array<String>
  646.  * @cat Plugins/Form
  647.  */
  648. $.fn.fieldValue = function(successful) {
  649.     for (var val=[], i=0, max=this.length; i < max; i++) {
  650.         var el = this[i];
  651.         var v = $.fieldValue(el, successful);
  652.         if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
  653.             continue;
  654.         v.constructor == Array ? $.merge(val, v) : val.push(v);
  655.     }
  656.     return val;
  657. };
  658. /**
  659.  * Returns the value of the field element.
  660.  *
  661.  * The successful argument controls whether or not the field element must be 'successful'
  662.  * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
  663.  * The default value of the successful argument is true.  If the given element is not
  664.  * successful and the successful arg is not false then the returned value will be null.
  665.  *
  666.  * Note: If the successful flag is true (default) but the element is not successful, the return will be null
  667.  * Note: The value returned for a successful select-multiple element will always be an array.
  668.  * Note: If the element has no value the return value will be undefined.
  669.  *
  670.  * @example var data = jQuery.fieldValue($("#myPasswordElement")[0]);
  671.  * @desc Gets the current value of the myPasswordElement element
  672.  *
  673.  * @name fieldValue
  674.  * @param Element el The DOM element for which the value will be returned
  675.  * @param Boolean successful true if value returned must be for a successful controls (default is true)
  676.  * @type String or Array<String> or null or undefined
  677.  * @cat Plugins/Form
  678.  */
  679. $.fieldValue = function(el, successful) {
  680.     var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
  681.     if (typeof successful == 'undefined') successful = true;
  682.     if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
  683.         (t == 'checkbox' || t == 'radio') && !el.checked ||
  684.         (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
  685.         tag == 'select' && el.selectedIndex == -1))
  686.             return null;
  687.     if (tag == 'select') {
  688.         var index = el.selectedIndex;
  689.         if (index < 0) return null;
  690.         var a = [], ops = el.options;
  691.         var one = (t == 'select-one');
  692.         var max = (one ? index+1 : ops.length);
  693.         for(var i=(one ? index : 0); i < max; i++) {
  694.             var op = ops[i];
  695.             if (op.selected) {
  696.                 // extra pain for IE...
  697.                 var v = $.browser.msie && !(op.attributes['value'].specified) ? op.text : op.value;
  698.                 if (one) return v;
  699.                 a.push(v);
  700.             }
  701.         }
  702.         return a;
  703.     }
  704.     return el.value;
  705. };
  706. /**
  707.  * Clears the form data.  Takes the following actions on the form's input fields:
  708.  *  - input text fields will have their 'value' property set to the empty string
  709.  *  - select elements will have their 'selectedIndex' property set to -1
  710.  *  - checkbox and radio inputs will have their 'checked' property set to false
  711.  *  - inputs of type submit, button, reset, and hidden will *not* be effected
  712.  *  - button elements will *not* be effected
  713.  *
  714.  * @example $('form').clearForm();
  715.  * @desc Clears all forms on the page.
  716.  *
  717.  * @name clearForm
  718.  * @type jQuery
  719.  * @cat Plugins/Form
  720.  */
  721. $.fn.clearForm = function() {
  722.     return this.each(function() {
  723.         $('input,select,textarea', this).clearFields();
  724.     });
  725. };
  726. /**
  727.  * Clears the selected form elements.  Takes the following actions on the matched elements:
  728.  *  - input text fields will have their 'value' property set to the empty string
  729.  *  - select elements will have their 'selectedIndex' property set to -1
  730.  *  - checkbox and radio inputs will have their 'checked' property set to false
  731.  *  - inputs of type submit, button, reset, and hidden will *not* be effected
  732.  *  - button elements will *not* be effected
  733.  *
  734.  * @example $('.myInputs').clearFields();
  735.  * @desc Clears all inputs with class myInputs
  736.  *
  737.  * @name clearFields
  738.  * @type jQuery
  739.  * @cat Plugins/Form
  740.  */
  741. $.fn.clearFields = $.fn.clearInputs = function() {
  742.     return this.each(function() {
  743.         var t = this.type, tag = this.tagName.toLowerCase();
  744.         if (t == 'text' || t == 'password' || tag == 'textarea')
  745.             this.value = '';
  746.         else if (t == 'checkbox' || t == 'radio')
  747.             this.checked = false;
  748.         else if (tag == 'select')
  749.             this.selectedIndex = -1;
  750.     });
  751. };
  752. /**
  753.  * Resets the form data.  Causes all form elements to be reset to their original value.
  754.  *
  755.  * @example $('form').resetForm();
  756.  * @desc Resets all forms on the page.
  757.  *
  758.  * @name resetForm
  759.  * @type jQuery
  760.  * @cat Plugins/Form
  761.  */
  762. $.fn.resetForm = function() {
  763.     return this.each(function() {
  764.         // guard against an input with the name of 'reset'
  765.         // note that IE reports the reset function as an 'object'
  766.         if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
  767.             this.reset();
  768.     });
  769. };
  770. /**
  771.  * Enables or disables any matching elements.
  772.  *
  773.  * @example $(':radio').enabled(false);
  774.  * @desc Disables all radio buttons
  775.  *
  776.  * @name select
  777.  * @type jQuery
  778.  * @cat Plugins/Form
  779.  */
  780. $.fn.enable = function(b) { 
  781.     if (b == undefined) b = true;
  782.     return this.each(function() { 
  783.         this.disabled = !b 
  784.     });
  785. };
  786. /**
  787.  * Checks/unchecks any matching checkboxes or radio buttons and
  788.  * selects/deselects and matching option elements.
  789.  *
  790.  * @example $(':checkbox').select();
  791.  * @desc Checks all checkboxes
  792.  *
  793.  * @name select
  794.  * @type jQuery
  795.  * @cat Plugins/Form
  796.  */
  797. $.fn.select = function(select) {
  798.     if (select == undefined) select = true;
  799.     return this.each(function() { 
  800.         var t = this.type;
  801.         if (t == 'checkbox' || t == 'radio')
  802.             this.checked = select;
  803.         else if (this.tagName.toLowerCase() == 'option') {
  804.             var $sel = $(this).parent('select');
  805.             if (select && $sel[0] && $sel[0].type == 'select-one') {
  806.                 // deselect all other options
  807.                 $sel.find('option').select(false);
  808.             }
  809.             this.selected = select;
  810.         }
  811.     });
  812. };
  813. })(jQuery);