hgbook

diff web/javascript/form.js @ 703:cbdff5945f9d

Added tag submitted for changeset 18131160f7ee
author Bryan O'Sullivan <bos@serpentine.com>
date Thu May 07 21:06:49 2009 -0700 (2009-05-07)
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/web/javascript/form.js	Thu May 07 21:06:49 2009 -0700
     1.3 @@ -0,0 +1,819 @@
     1.4 +/*
     1.5 + * jQuery Form Plugin
     1.6 + * @requires jQuery v1.1 or later
     1.7 + *
     1.8 + * Examples at: http://malsup.com/jquery/form/
     1.9 + * Dual licensed under the MIT and GPL licenses:
    1.10 + *   http://www.opensource.org/licenses/mit-license.php
    1.11 + *   http://www.gnu.org/licenses/gpl.html
    1.12 + *
    1.13 + * Revision: $Id$
    1.14 + */
    1.15 + (function($) {
    1.16 +/**
    1.17 + * ajaxSubmit() provides a mechanism for submitting an HTML form using AJAX.
    1.18 + *
    1.19 + * ajaxSubmit accepts a single argument which can be either a success callback function
    1.20 + * or an options Object.  If a function is provided it will be invoked upon successful
    1.21 + * completion of the submit and will be passed the response from the server.
    1.22 + * If an options Object is provided, the following attributes are supported:
    1.23 + *
    1.24 + *  target:   Identifies the element(s) in the page to be updated with the server response.
    1.25 + *            This value may be specified as a jQuery selection string, a jQuery object,
    1.26 + *            or a DOM element.
    1.27 + *            default value: null
    1.28 + *
    1.29 + *  url:      URL to which the form data will be submitted.
    1.30 + *            default value: value of form's 'action' attribute
    1.31 + *
    1.32 + *  type:     The method in which the form data should be submitted, 'GET' or 'POST'.
    1.33 + *            default value: value of form's 'method' attribute (or 'GET' if none found)
    1.34 + *
    1.35 + *  data:     Additional data to add to the request, specified as key/value pairs (see $.ajax).
    1.36 + *
    1.37 + *  beforeSubmit:  Callback method to be invoked before the form is submitted.
    1.38 + *            default value: null
    1.39 + *
    1.40 + *  success:  Callback method to be invoked after the form has been successfully submitted
    1.41 + *            and the response has been returned from the server
    1.42 + *            default value: null
    1.43 + *
    1.44 + *  dataType: Expected dataType of the response.  One of: null, 'xml', 'script', or 'json'
    1.45 + *            default value: null
    1.46 + *
    1.47 + *  semantic: Boolean flag indicating whether data must be submitted in semantic order (slower).
    1.48 + *            default value: false
    1.49 + *
    1.50 + *  resetForm: Boolean flag indicating whether the form should be reset if the submit is successful
    1.51 + *
    1.52 + *  clearForm: Boolean flag indicating whether the form should be cleared if the submit is successful
    1.53 + *
    1.54 + *
    1.55 + * The 'beforeSubmit' callback can be provided as a hook for running pre-submit logic or for
    1.56 + * validating the form data.  If the 'beforeSubmit' callback returns false then the form will
    1.57 + * not be submitted. The 'beforeSubmit' callback is invoked with three arguments: the form data
    1.58 + * in array format, the jQuery object, and the options object passed into ajaxSubmit.
    1.59 + * The form data array takes the following form:
    1.60 + *
    1.61 + *     [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
    1.62 + *
    1.63 + * If a 'success' callback method is provided it is invoked after the response has been returned
    1.64 + * from the server.  It is passed the responseText or responseXML value (depending on dataType).
    1.65 + * See jQuery.ajax for further details.
    1.66 + *
    1.67 + *
    1.68 + * The dataType option provides a means for specifying how the server response should be handled.
    1.69 + * This maps directly to the jQuery.httpData method.  The following values are supported:
    1.70 + *
    1.71 + *      'xml':    if dataType == 'xml' the server response is treated as XML and the 'success'
    1.72 + *                   callback method, if specified, will be passed the responseXML value
    1.73 + *      'json':   if dataType == 'json' the server response will be evaluted and passed to
    1.74 + *                   the 'success' callback, if specified
    1.75 + *      'script': if dataType == 'script' the server response is evaluated in the global context
    1.76 + *
    1.77 + *
    1.78 + * Note that it does not make sense to use both the 'target' and 'dataType' options.  If both
    1.79 + * are provided the target will be ignored.
    1.80 + *
    1.81 + * The semantic argument can be used to force form serialization in semantic order.
    1.82 + * This is normally true anyway, unless the form contains input elements of type='image'.
    1.83 + * If your form must be submitted with name/value pairs in semantic order and your form
    1.84 + * contains an input of type='image" then pass true for this arg, otherwise pass false
    1.85 + * (or nothing) to avoid the overhead for this logic.
    1.86 + *
    1.87 + *
    1.88 + * When used on its own, ajaxSubmit() is typically bound to a form's submit event like this:
    1.89 + *
    1.90 + * $("#form-id").submit(function() {
    1.91 + *     $(this).ajaxSubmit(options);
    1.92 + *     return false; // cancel conventional submit
    1.93 + * });
    1.94 + *
    1.95 + * When using ajaxForm(), however, this is done for you.
    1.96 + *
    1.97 + * @example
    1.98 + * $('#myForm').ajaxSubmit(function(data) {
    1.99 + *     alert('Form submit succeeded! Server returned: ' + data);
   1.100 + * });
   1.101 + * @desc Submit form and alert server response
   1.102 + *
   1.103 + *
   1.104 + * @example
   1.105 + * var options = {
   1.106 + *     target: '#myTargetDiv'
   1.107 + * };
   1.108 + * $('#myForm').ajaxSubmit(options);
   1.109 + * @desc Submit form and update page element with server response
   1.110 + *
   1.111 + *
   1.112 + * @example
   1.113 + * var options = {
   1.114 + *     success: function(responseText) {
   1.115 + *         alert(responseText);
   1.116 + *     }
   1.117 + * };
   1.118 + * $('#myForm').ajaxSubmit(options);
   1.119 + * @desc Submit form and alert the server response
   1.120 + *
   1.121 + *
   1.122 + * @example
   1.123 + * var options = {
   1.124 + *     beforeSubmit: function(formArray, jqForm) {
   1.125 + *         if (formArray.length == 0) {
   1.126 + *             alert('Please enter data.');
   1.127 + *             return false;
   1.128 + *         }
   1.129 + *     }
   1.130 + * };
   1.131 + * $('#myForm').ajaxSubmit(options);
   1.132 + * @desc Pre-submit validation which aborts the submit operation if form data is empty
   1.133 + *
   1.134 + *
   1.135 + * @example
   1.136 + * var options = {
   1.137 + *     url: myJsonUrl.php,
   1.138 + *     dataType: 'json',
   1.139 + *     success: function(data) {
   1.140 + *        // 'data' is an object representing the the evaluated json data
   1.141 + *     }
   1.142 + * };
   1.143 + * $('#myForm').ajaxSubmit(options);
   1.144 + * @desc json data returned and evaluated
   1.145 + *
   1.146 + *
   1.147 + * @example
   1.148 + * var options = {
   1.149 + *     url: myXmlUrl.php,
   1.150 + *     dataType: 'xml',
   1.151 + *     success: function(responseXML) {
   1.152 + *        // responseXML is XML document object
   1.153 + *        var data = $('myElement', responseXML).text();
   1.154 + *     }
   1.155 + * };
   1.156 + * $('#myForm').ajaxSubmit(options);
   1.157 + * @desc XML data returned from server
   1.158 + *
   1.159 + *
   1.160 + * @example
   1.161 + * var options = {
   1.162 + *     resetForm: true
   1.163 + * };
   1.164 + * $('#myForm').ajaxSubmit(options);
   1.165 + * @desc submit form and reset it if successful
   1.166 + *
   1.167 + * @example
   1.168 + * $('#myForm).submit(function() {
   1.169 + *    $(this).ajaxSubmit();
   1.170 + *    return false;
   1.171 + * });
   1.172 + * @desc Bind form's submit event to use ajaxSubmit
   1.173 + *
   1.174 + *
   1.175 + * @name ajaxSubmit
   1.176 + * @type jQuery
   1.177 + * @param options  object literal containing options which control the form submission process
   1.178 + * @cat Plugins/Form
   1.179 + * @return jQuery
   1.180 + */
   1.181 +$.fn.ajaxSubmit = function(options) {
   1.182 +    if (typeof options == 'function')
   1.183 +        options = { success: options };
   1.184 +
   1.185 +    options = $.extend({
   1.186 +        url:  this.attr('action') || window.location,
   1.187 +        type: this.attr('method') || 'GET'
   1.188 +    }, options || {});
   1.189 +
   1.190 +    // hook for manipulating the form data before it is extracted;
   1.191 +    // convenient for use with rich editors like tinyMCE or FCKEditor
   1.192 +    var veto = {};
   1.193 +    $.event.trigger('form.pre.serialize', [this, options, veto]);
   1.194 +    if (veto.veto) return this;
   1.195 +
   1.196 +    var a = this.formToArray(options.semantic);
   1.197 +	if (options.data) {
   1.198 +	    for (var n in options.data)
   1.199 +	        a.push( { name: n, value: options.data[n] } );
   1.200 +	}
   1.201 +
   1.202 +    // give pre-submit callback an opportunity to abort the submit
   1.203 +    if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) return this;
   1.204 +
   1.205 +    // fire vetoable 'validate' event
   1.206 +    $.event.trigger('form.submit.validate', [a, this, options, veto]);
   1.207 +    if (veto.veto) return this;
   1.208 +
   1.209 +    var q = $.param(a);//.replace(/%20/g,'+');
   1.210 +
   1.211 +    if (options.type.toUpperCase() == 'GET') {
   1.212 +        options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
   1.213 +        options.data = null;  // data is null for 'get'
   1.214 +    }
   1.215 +    else
   1.216 +        options.data = q; // data is the query string for 'post'
   1.217 +
   1.218 +    var $form = this, callbacks = [];
   1.219 +    if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
   1.220 +    if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
   1.221 +
   1.222 +    // perform a load on the target only if dataType is not provided
   1.223 +    if (!options.dataType && options.target) {
   1.224 +        var oldSuccess = options.success || function(){};
   1.225 +        callbacks.push(function(data) {
   1.226 +            if (this.evalScripts)
   1.227 +                $(options.target).attr("innerHTML", data).evalScripts().each(oldSuccess, arguments);
   1.228 +            else // jQuery v1.1.4
   1.229 +                $(options.target).html(data).each(oldSuccess, arguments);
   1.230 +        });
   1.231 +    }
   1.232 +    else if (options.success)
   1.233 +        callbacks.push(options.success);
   1.234 +
   1.235 +    options.success = function(data, status) {
   1.236 +        for (var i=0, max=callbacks.length; i < max; i++)
   1.237 +            callbacks[i](data, status, $form);
   1.238 +    };
   1.239 +
   1.240 +    // are there files to upload?
   1.241 +    var files = $('input:file', this).fieldValue();
   1.242 +    var found = false;
   1.243 +    for (var j=0; j < files.length; j++)
   1.244 +        if (files[j])
   1.245 +            found = true;
   1.246 +
   1.247 +    if (options.iframe || found) // options.iframe allows user to force iframe mode
   1.248 +        fileUpload();
   1.249 +    else
   1.250 +        $.ajax(options);
   1.251 +
   1.252 +    // fire 'notify' event
   1.253 +    $.event.trigger('form.submit.notify', [this, options]);
   1.254 +    return this;
   1.255 +
   1.256 +
   1.257 +    // private function for handling file uploads (hat tip to YAHOO!)
   1.258 +    function fileUpload() {
   1.259 +        var form = $form[0];
   1.260 +        var opts = $.extend({}, $.ajaxSettings, options);
   1.261 +
   1.262 +        var id = 'jqFormIO' + $.fn.ajaxSubmit.counter++;
   1.263 +        var $io = $('<iframe id="' + id + '" name="' + id + '" />');
   1.264 +        var io = $io[0];
   1.265 +        var op8 = $.browser.opera && window.opera.version() < 9;
   1.266 +        if ($.browser.msie || op8) io.src = 'javascript:false;document.write("");';
   1.267 +        $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
   1.268 +
   1.269 +        var xhr = { // mock object
   1.270 +            responseText: null,
   1.271 +            responseXML: null,
   1.272 +            status: 0,
   1.273 +            statusText: 'n/a',
   1.274 +            getAllResponseHeaders: function() {},
   1.275 +            getResponseHeader: function() {},
   1.276 +            setRequestHeader: function() {}
   1.277 +        };
   1.278 +
   1.279 +        var g = opts.global;
   1.280 +        // trigger ajax global events so that activity/block indicators work like normal
   1.281 +        if (g && ! $.active++) $.event.trigger("ajaxStart");
   1.282 +        if (g) $.event.trigger("ajaxSend", [xhr, opts]);
   1.283 +
   1.284 +        var cbInvoked = 0;
   1.285 +        var timedOut = 0;
   1.286 +
   1.287 +        // take a breath so that pending repaints get some cpu time before the upload starts
   1.288 +        setTimeout(function() {
   1.289 +            $io.appendTo('body');
   1.290 +            // jQuery's event binding doesn't work for iframe events in IE
   1.291 +            io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
   1.292 +
   1.293 +            // make sure form attrs are set
   1.294 +            var encAttr = form.encoding ? 'encoding' : 'enctype';
   1.295 +            var t = $form.attr('target');
   1.296 +            $form.attr({
   1.297 +                target:   id,
   1.298 +                method:  'POST',
   1.299 +                action:   opts.url
   1.300 +            });
   1.301 +            form[encAttr] = 'multipart/form-data';
   1.302 +
   1.303 +            // support timout
   1.304 +            if (opts.timeout)
   1.305 +                setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
   1.306 +
   1.307 +            form.submit();
   1.308 +            $form.attr('target', t); // reset target
   1.309 +        }, 10);
   1.310 +
   1.311 +        function cb() {
   1.312 +            if (cbInvoked++) return;
   1.313 +
   1.314 +            io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
   1.315 +
   1.316 +            var ok = true;
   1.317 +            try {
   1.318 +                if (timedOut) throw 'timeout';
   1.319 +                // extract the server response from the iframe
   1.320 +                var data, doc;
   1.321 +                doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
   1.322 +                xhr.responseText = doc.body ? doc.body.innerHTML : null;
   1.323 +                xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
   1.324 +
   1.325 +                if (opts.dataType == 'json' || opts.dataType == 'script') {
   1.326 +                    var ta = doc.getElementsByTagName('textarea')[0];
   1.327 +                    data = ta ? ta.value : xhr.responseText;
   1.328 +                    if (opts.dataType == 'json')
   1.329 +                        eval("data = " + data);
   1.330 +                    else
   1.331 +                        $.globalEval(data);
   1.332 +                }
   1.333 +                else if (opts.dataType == 'xml') {
   1.334 +                    data = xhr.responseXML;
   1.335 +                    if (!data && xhr.responseText != null)
   1.336 +                        data = toXml(xhr.responseText);
   1.337 +                }
   1.338 +                else {
   1.339 +                    data = xhr.responseText;
   1.340 +                }
   1.341 +            }
   1.342 +            catch(e){
   1.343 +                ok = false;
   1.344 +                $.handleError(opts, xhr, 'error', e);
   1.345 +            }
   1.346 +
   1.347 +            // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
   1.348 +            if (ok) {
   1.349 +                opts.success(data, 'success');
   1.350 +                if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
   1.351 +            }
   1.352 +            if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
   1.353 +            if (g && ! --$.active) $.event.trigger("ajaxStop");
   1.354 +            if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
   1.355 +
   1.356 +            // clean up
   1.357 +            setTimeout(function() {
   1.358 +                $io.remove();
   1.359 +                xhr.responseXML = null;
   1.360 +            }, 100);
   1.361 +        };
   1.362 +
   1.363 +        function toXml(s, doc) {
   1.364 +            if (window.ActiveXObject) {
   1.365 +                doc = new ActiveXObject('Microsoft.XMLDOM');
   1.366 +                doc.async = 'false';
   1.367 +                doc.loadXML(s);
   1.368 +            }
   1.369 +            else
   1.370 +                doc = (new DOMParser()).parseFromString(s, 'text/xml');
   1.371 +            return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
   1.372 +        };
   1.373 +    };
   1.374 +};
   1.375 +$.fn.ajaxSubmit.counter = 0; // used to create unique iframe ids
   1.376 +
   1.377 +/**
   1.378 + * ajaxForm() provides a mechanism for fully automating form submission.
   1.379 + *
   1.380 + * The advantages of using this method instead of ajaxSubmit() are:
   1.381 + *
   1.382 + * 1: This method will include coordinates for <input type="image" /> elements (if the element
   1.383 + *    is used to submit the form).
   1.384 + * 2. This method will include the submit element's name/value data (for the element that was
   1.385 + *    used to submit the form).
   1.386 + * 3. This method binds the submit() method to the form for you.
   1.387 + *
   1.388 + * Note that for accurate x/y coordinates of image submit elements in all browsers
   1.389 + * you need to also use the "dimensions" plugin (this method will auto-detect its presence).
   1.390 + *
   1.391 + * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
   1.392 + * passes the options argument along after properly binding events for submit elements and
   1.393 + * the form itself.  See ajaxSubmit for a full description of the options argument.
   1.394 + *
   1.395 + *
   1.396 + * @example
   1.397 + * var options = {
   1.398 + *     target: '#myTargetDiv'
   1.399 + * };
   1.400 + * $('#myForm').ajaxSForm(options);
   1.401 + * @desc Bind form's submit event so that 'myTargetDiv' is updated with the server response
   1.402 + *       when the form is submitted.
   1.403 + *
   1.404 + *
   1.405 + * @example
   1.406 + * var options = {
   1.407 + *     success: function(responseText) {
   1.408 + *         alert(responseText);
   1.409 + *     }
   1.410 + * };
   1.411 + * $('#myForm').ajaxSubmit(options);
   1.412 + * @desc Bind form's submit event so that server response is alerted after the form is submitted.
   1.413 + *
   1.414 + *
   1.415 + * @example
   1.416 + * var options = {
   1.417 + *     beforeSubmit: function(formArray, jqForm) {
   1.418 + *         if (formArray.length == 0) {
   1.419 + *             alert('Please enter data.');
   1.420 + *             return false;
   1.421 + *         }
   1.422 + *     }
   1.423 + * };
   1.424 + * $('#myForm').ajaxSubmit(options);
   1.425 + * @desc Bind form's submit event so that pre-submit callback is invoked before the form
   1.426 + *       is submitted.
   1.427 + *
   1.428 + *
   1.429 + * @name   ajaxForm
   1.430 + * @param  options  object literal containing options which control the form submission process
   1.431 + * @return jQuery
   1.432 + * @cat    Plugins/Form
   1.433 + * @type   jQuery
   1.434 + */
   1.435 +$.fn.ajaxForm = function(options) {
   1.436 +    return this.ajaxFormUnbind().submit(submitHandler).each(function() {
   1.437 +        // store options in hash
   1.438 +        this.formPluginId = $.fn.ajaxForm.counter++;
   1.439 +        $.fn.ajaxForm.optionHash[this.formPluginId] = options;
   1.440 +        $(":submit,input:image", this).click(clickHandler);
   1.441 +    });
   1.442 +};
   1.443 +
   1.444 +$.fn.ajaxForm.counter = 1;
   1.445 +$.fn.ajaxForm.optionHash = {};
   1.446 +
   1.447 +function clickHandler(e) {
   1.448 +    var $form = this.form;
   1.449 +    $form.clk = this;
   1.450 +    if (this.type == 'image') {
   1.451 +        if (e.offsetX != undefined) {
   1.452 +            $form.clk_x = e.offsetX;
   1.453 +            $form.clk_y = e.offsetY;
   1.454 +        } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
   1.455 +            var offset = $(this).offset();
   1.456 +            $form.clk_x = e.pageX - offset.left;
   1.457 +            $form.clk_y = e.pageY - offset.top;
   1.458 +        } else {
   1.459 +            $form.clk_x = e.pageX - this.offsetLeft;
   1.460 +            $form.clk_y = e.pageY - this.offsetTop;
   1.461 +        }
   1.462 +    }
   1.463 +    // clear form vars
   1.464 +    setTimeout(function() { $form.clk = $form.clk_x = $form.clk_y = null; }, 10);
   1.465 +};
   1.466 +
   1.467 +function submitHandler() {
   1.468 +    // retrieve options from hash
   1.469 +    var id = this.formPluginId;
   1.470 +    var options = $.fn.ajaxForm.optionHash[id];
   1.471 +    $(this).ajaxSubmit(options);
   1.472 +    return false;
   1.473 +};
   1.474 +
   1.475 +/**
   1.476 + * ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
   1.477 + *
   1.478 + * @name   ajaxFormUnbind
   1.479 + * @return jQuery
   1.480 + * @cat    Plugins/Form
   1.481 + * @type   jQuery
   1.482 + */
   1.483 +$.fn.ajaxFormUnbind = function() {
   1.484 +    this.unbind('submit', submitHandler);
   1.485 +    return this.each(function() {
   1.486 +        $(":submit,input:image", this).unbind('click', clickHandler);
   1.487 +    });
   1.488 +
   1.489 +};
   1.490 +
   1.491 +/**
   1.492 + * formToArray() gathers form element data into an array of objects that can
   1.493 + * be passed to any of the following ajax functions: $.get, $.post, or load.
   1.494 + * Each object in the array has both a 'name' and 'value' property.  An example of
   1.495 + * an array for a simple login form might be:
   1.496 + *
   1.497 + * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
   1.498 + *
   1.499 + * It is this array that is passed to pre-submit callback functions provided to the
   1.500 + * ajaxSubmit() and ajaxForm() methods.
   1.501 + *
   1.502 + * The semantic argument can be used to force form serialization in semantic order.
   1.503 + * This is normally true anyway, unless the form contains input elements of type='image'.
   1.504 + * If your form must be submitted with name/value pairs in semantic order and your form
   1.505 + * contains an input of type='image" then pass true for this arg, otherwise pass false
   1.506 + * (or nothing) to avoid the overhead for this logic.
   1.507 + *
   1.508 + * @example var data = $("#myForm").formToArray();
   1.509 + * $.post( "myscript.cgi", data );
   1.510 + * @desc Collect all the data from a form and submit it to the server.
   1.511 + *
   1.512 + * @name formToArray
   1.513 + * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
   1.514 + * @type Array<Object>
   1.515 + * @cat Plugins/Form
   1.516 + */
   1.517 +$.fn.formToArray = function(semantic) {
   1.518 +    var a = [];
   1.519 +    if (this.length == 0) return a;
   1.520 +
   1.521 +    var form = this[0];
   1.522 +    var els = semantic ? form.getElementsByTagName('*') : form.elements;
   1.523 +    if (!els) return a;
   1.524 +    for(var i=0, max=els.length; i < max; i++) {
   1.525 +        var el = els[i];
   1.526 +        var n = el.name;
   1.527 +        if (!n) continue;
   1.528 +
   1.529 +        if (semantic && form.clk && el.type == "image") {
   1.530 +            // handle image inputs on the fly when semantic == true
   1.531 +            if(!el.disabled && form.clk == el)
   1.532 +                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
   1.533 +            continue;
   1.534 +        }
   1.535 +
   1.536 +        var v = $.fieldValue(el, true);
   1.537 +        if (v && v.constructor == Array) {
   1.538 +            for(var j=0, jmax=v.length; j < jmax; j++)
   1.539 +                a.push({name: n, value: v[j]});
   1.540 +        }
   1.541 +        else if (v !== null && typeof v != 'undefined')
   1.542 +            a.push({name: n, value: v});
   1.543 +    }
   1.544 +
   1.545 +    if (!semantic && form.clk) {
   1.546 +        // input type=='image' are not found in elements array! handle them here
   1.547 +        var inputs = form.getElementsByTagName("input");
   1.548 +        for(var i=0, max=inputs.length; i < max; i++) {
   1.549 +            var input = inputs[i];
   1.550 +            var n = input.name;
   1.551 +            if(n && !input.disabled && input.type == "image" && form.clk == input)
   1.552 +                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
   1.553 +        }
   1.554 +    }
   1.555 +    return a;
   1.556 +};
   1.557 +
   1.558 +
   1.559 +/**
   1.560 + * Serializes form data into a 'submittable' string. This method will return a string
   1.561 + * in the format: name1=value1&amp;name2=value2
   1.562 + *
   1.563 + * The semantic argument can be used to force form serialization in semantic order.
   1.564 + * If your form must be submitted with name/value pairs in semantic order then pass
   1.565 + * true for this arg, otherwise pass false (or nothing) to avoid the overhead for
   1.566 + * this logic (which can be significant for very large forms).
   1.567 + *
   1.568 + * @example var data = $("#myForm").formSerialize();
   1.569 + * $.ajax('POST', "myscript.cgi", data);
   1.570 + * @desc Collect all the data from a form into a single string
   1.571 + *
   1.572 + * @name formSerialize
   1.573 + * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
   1.574 + * @type String
   1.575 + * @cat Plugins/Form
   1.576 + */
   1.577 +$.fn.formSerialize = function(semantic) {
   1.578 +    //hand off to jQuery.param for proper encoding
   1.579 +    return $.param(this.formToArray(semantic));
   1.580 +};
   1.581 +
   1.582 +
   1.583 +/**
   1.584 + * Serializes all field elements in the jQuery object into a query string.
   1.585 + * This method will return a string in the format: name1=value1&amp;name2=value2
   1.586 + *
   1.587 + * The successful argument controls whether or not serialization is limited to
   1.588 + * 'successful' controls (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
   1.589 + * The default value of the successful argument is true.
   1.590 + *
   1.591 + * @example var data = $("input").formSerialize();
   1.592 + * @desc Collect the data from all successful input elements into a query string
   1.593 + *
   1.594 + * @example var data = $(":radio").formSerialize();
   1.595 + * @desc Collect the data from all successful radio input elements into a query string
   1.596 + *
   1.597 + * @example var data = $("#myForm :checkbox").formSerialize();
   1.598 + * @desc Collect the data from all successful checkbox input elements in myForm into a query string
   1.599 + *
   1.600 + * @example var data = $("#myForm :checkbox").formSerialize(false);
   1.601 + * @desc Collect the data from all checkbox elements in myForm (even the unchecked ones) into a query string
   1.602 + *
   1.603 + * @example var data = $(":input").formSerialize();
   1.604 + * @desc Collect the data from all successful input, select, textarea and button elements into a query string
   1.605 + *
   1.606 + * @name fieldSerialize
   1.607 + * @param successful true if only successful controls should be serialized (default is true)
   1.608 + * @type String
   1.609 + * @cat Plugins/Form
   1.610 + */
   1.611 +$.fn.fieldSerialize = function(successful) {
   1.612 +    var a = [];
   1.613 +    this.each(function() {
   1.614 +        var n = this.name;
   1.615 +        if (!n) return;
   1.616 +        var v = $.fieldValue(this, successful);
   1.617 +        if (v && v.constructor == Array) {
   1.618 +            for (var i=0,max=v.length; i < max; i++)
   1.619 +                a.push({name: n, value: v[i]});
   1.620 +        }
   1.621 +        else if (v !== null && typeof v != 'undefined')
   1.622 +            a.push({name: this.name, value: v});
   1.623 +    });
   1.624 +    //hand off to jQuery.param for proper encoding
   1.625 +    return $.param(a);
   1.626 +};
   1.627 +
   1.628 +
   1.629 +/**
   1.630 + * Returns the value(s) of the element in the matched set.  For example, consider the following form:
   1.631 + *
   1.632 + *  <form><fieldset>
   1.633 + *      <input name="A" type="text" />
   1.634 + *      <input name="A" type="text" />
   1.635 + *      <input name="B" type="checkbox" value="B1" />
   1.636 + *      <input name="B" type="checkbox" value="B2"/>
   1.637 + *      <input name="C" type="radio" value="C1" />
   1.638 + *      <input name="C" type="radio" value="C2" />
   1.639 + *  </fieldset></form>
   1.640 + *
   1.641 + *  var v = $(':text').fieldValue();
   1.642 + *  // if no values are entered into the text inputs
   1.643 + *  v == ['','']
   1.644 + *  // if values entered into the text inputs are 'foo' and 'bar'
   1.645 + *  v == ['foo','bar']
   1.646 + *
   1.647 + *  var v = $(':checkbox').fieldValue();
   1.648 + *  // if neither checkbox is checked
   1.649 + *  v === undefined
   1.650 + *  // if both checkboxes are checked
   1.651 + *  v == ['B1', 'B2']
   1.652 + *
   1.653 + *  var v = $(':radio').fieldValue();
   1.654 + *  // if neither radio is checked
   1.655 + *  v === undefined
   1.656 + *  // if first radio is checked
   1.657 + *  v == ['C1']
   1.658 + *
   1.659 + * The successful argument controls whether or not the field element must be 'successful'
   1.660 + * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
   1.661 + * The default value of the successful argument is true.  If this value is false the value(s)
   1.662 + * for each element is returned.
   1.663 + *
   1.664 + * Note: This method *always* returns an array.  If no valid value can be determined the
   1.665 + *       array will be empty, otherwise it will contain one or more values.
   1.666 + *
   1.667 + * @example var data = $("#myPasswordElement").fieldValue();
   1.668 + * alert(data[0]);
   1.669 + * @desc Alerts the current value of the myPasswordElement element
   1.670 + *
   1.671 + * @example var data = $("#myForm :input").fieldValue();
   1.672 + * @desc Get the value(s) of the form elements in myForm
   1.673 + *
   1.674 + * @example var data = $("#myForm :checkbox").fieldValue();
   1.675 + * @desc Get the value(s) for the successful checkbox element(s) in the jQuery object.
   1.676 + *
   1.677 + * @example var data = $("#mySingleSelect").fieldValue();
   1.678 + * @desc Get the value(s) of the select control
   1.679 + *
   1.680 + * @example var data = $(':text').fieldValue();
   1.681 + * @desc Get the value(s) of the text input or textarea elements
   1.682 + *
   1.683 + * @example var data = $("#myMultiSelect").fieldValue();
   1.684 + * @desc Get the values for the select-multiple control
   1.685 + *
   1.686 + * @name fieldValue
   1.687 + * @param Boolean successful true if only the values for successful controls should be returned (default is true)
   1.688 + * @type Array<String>
   1.689 + * @cat Plugins/Form
   1.690 + */
   1.691 +$.fn.fieldValue = function(successful) {
   1.692 +    for (var val=[], i=0, max=this.length; i < max; i++) {
   1.693 +        var el = this[i];
   1.694 +        var v = $.fieldValue(el, successful);
   1.695 +        if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
   1.696 +            continue;
   1.697 +        v.constructor == Array ? $.merge(val, v) : val.push(v);
   1.698 +    }
   1.699 +    return val;
   1.700 +};
   1.701 +
   1.702 +/**
   1.703 + * Returns the value of the field element.
   1.704 + *
   1.705 + * The successful argument controls whether or not the field element must be 'successful'
   1.706 + * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
   1.707 + * The default value of the successful argument is true.  If the given element is not
   1.708 + * successful and the successful arg is not false then the returned value will be null.
   1.709 + *
   1.710 + * Note: If the successful flag is true (default) but the element is not successful, the return will be null
   1.711 + * Note: The value returned for a successful select-multiple element will always be an array.
   1.712 + * Note: If the element has no value the return value will be undefined.
   1.713 + *
   1.714 + * @example var data = jQuery.fieldValue($("#myPasswordElement")[0]);
   1.715 + * @desc Gets the current value of the myPasswordElement element
   1.716 + *
   1.717 + * @name fieldValue
   1.718 + * @param Element el The DOM element for which the value will be returned
   1.719 + * @param Boolean successful true if value returned must be for a successful controls (default is true)
   1.720 + * @type String or Array<String> or null or undefined
   1.721 + * @cat Plugins/Form
   1.722 + */
   1.723 +$.fieldValue = function(el, successful) {
   1.724 +    var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
   1.725 +    if (typeof successful == 'undefined') successful = true;
   1.726 +
   1.727 +    if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
   1.728 +        (t == 'checkbox' || t == 'radio') && !el.checked ||
   1.729 +        (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
   1.730 +        tag == 'select' && el.selectedIndex == -1))
   1.731 +            return null;
   1.732 +
   1.733 +    if (tag == 'select') {
   1.734 +        var index = el.selectedIndex;
   1.735 +        if (index < 0) return null;
   1.736 +        var a = [], ops = el.options;
   1.737 +        var one = (t == 'select-one');
   1.738 +        var max = (one ? index+1 : ops.length);
   1.739 +        for(var i=(one ? index : 0); i < max; i++) {
   1.740 +            var op = ops[i];
   1.741 +            if (op.selected) {
   1.742 +                // extra pain for IE...
   1.743 +                var v = $.browser.msie && !(op.attributes['value'].specified) ? op.text : op.value;
   1.744 +                if (one) return v;
   1.745 +                a.push(v);
   1.746 +            }
   1.747 +        }
   1.748 +        return a;
   1.749 +    }
   1.750 +    return el.value;
   1.751 +};
   1.752 +
   1.753 +
   1.754 +/**
   1.755 + * Clears the form data.  Takes the following actions on the form's input fields:
   1.756 + *  - input text fields will have their 'value' property set to the empty string
   1.757 + *  - select elements will have their 'selectedIndex' property set to -1
   1.758 + *  - checkbox and radio inputs will have their 'checked' property set to false
   1.759 + *  - inputs of type submit, button, reset, and hidden will *not* be effected
   1.760 + *  - button elements will *not* be effected
   1.761 + *
   1.762 + * @example $('form').clearForm();
   1.763 + * @desc Clears all forms on the page.
   1.764 + *
   1.765 + * @name clearForm
   1.766 + * @type jQuery
   1.767 + * @cat Plugins/Form
   1.768 + */
   1.769 +$.fn.clearForm = function() {
   1.770 +    return this.each(function() {
   1.771 +        $('input,select,textarea', this).clearFields();
   1.772 +    });
   1.773 +};
   1.774 +
   1.775 +/**
   1.776 + * Clears the selected form elements.  Takes the following actions on the matched elements:
   1.777 + *  - input text fields will have their 'value' property set to the empty string
   1.778 + *  - select elements will have their 'selectedIndex' property set to -1
   1.779 + *  - checkbox and radio inputs will have their 'checked' property set to false
   1.780 + *  - inputs of type submit, button, reset, and hidden will *not* be effected
   1.781 + *  - button elements will *not* be effected
   1.782 + *
   1.783 + * @example $('.myInputs').clearFields();
   1.784 + * @desc Clears all inputs with class myInputs
   1.785 + *
   1.786 + * @name clearFields
   1.787 + * @type jQuery
   1.788 + * @cat Plugins/Form
   1.789 + */
   1.790 +$.fn.clearFields = $.fn.clearInputs = function() {
   1.791 +    return this.each(function() {
   1.792 +        var t = this.type, tag = this.tagName.toLowerCase();
   1.793 +        if (t == 'text' || t == 'password' || tag == 'textarea')
   1.794 +            this.value = '';
   1.795 +        else if (t == 'checkbox' || t == 'radio')
   1.796 +            this.checked = false;
   1.797 +        else if (tag == 'select')
   1.798 +            this.selectedIndex = -1;
   1.799 +    });
   1.800 +};
   1.801 +
   1.802 +
   1.803 +/**
   1.804 + * Resets the form data.  Causes all form elements to be reset to their original value.
   1.805 + *
   1.806 + * @example $('form').resetForm();
   1.807 + * @desc Resets all forms on the page.
   1.808 + *
   1.809 + * @name resetForm
   1.810 + * @type jQuery
   1.811 + * @cat Plugins/Form
   1.812 + */
   1.813 +$.fn.resetForm = function() {
   1.814 +    return this.each(function() {
   1.815 +        // guard against an input with the name of 'reset'
   1.816 +        // note that IE reports the reset function as an 'object'
   1.817 +        if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
   1.818 +            this.reset();
   1.819 +    });
   1.820 +};
   1.821 +
   1.822 +})(jQuery);