WordPress.org

Make WordPress Core

Ticket #15909: jquery.form.diff

File jquery.form.diff, 50.3 KB (added by niallkennedy, 7 years ago)

more recent diff from v 2.63 released Jan 29 2011

  • wp-includes/js/jquery/jquery.form.dev.js

     
    1 /*
     1/*!
    22 * jQuery Form Plugin
    3  * version: 2.02 (12/16/2007)
    4  * @requires jQuery v1.1 or later
     3 * version: 2.63 (29-JAN-2011)
     4 * @requires jQuery v1.3.2 or later
    55 *
    6  * Examples at: http://malsup.com/jquery/form/
     6 * Examples and documentation at: http://malsup.com/jquery/form/
    77 * Dual licensed under the MIT and GPL licenses:
    88 *   http://www.opensource.org/licenses/mit-license.php
    99 *   http://www.gnu.org/licenses/gpl.html
    10  *
    11  * Revision: $Id$
    1210 */
    13  (function($) {
     11;(function($) {
     12
     13/*
     14        Usage Note:
     15        -----------
     16        Do not use both ajaxSubmit and ajaxForm on the same form.  These
     17        functions are intended to be exclusive.  Use ajaxSubmit if you want
     18        to bind your own submit handler to the form.  For example,
     19
     20        $(document).ready(function() {
     21                $('#myForm').bind('submit', function(e) {
     22                        e.preventDefault(); // <-- important
     23                        $(this).ajaxSubmit({
     24                                target: '#output'
     25                        });
     26                });
     27        });
     28
     29        Use ajaxForm when you want the plugin to manage all the event binding
     30        for you.  For example,
     31
     32        $(document).ready(function() {
     33                $('#myForm').ajaxForm({
     34                        target: '#output'
     35                });
     36        });
     37
     38        When using ajaxForm, the ajaxSubmit function will be invoked for you
     39        at the appropriate time.
     40*/
     41
    1442/**
    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
     43 * ajaxSubmit() provides a mechanism for immediately submitting
     44 * an HTML form using AJAX.
    17845 */
    17946$.fn.ajaxSubmit = function(options) {
    180     if (typeof options == 'function')
    181         options = { success: options };
     47        // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
     48        if (!this.length) {
     49                log('ajaxSubmit: skipping submit process - no element selected');
     50                return this;
     51        }
    18252
    183     options = $.extend({
    184         url:  this.attr('action') || window.location.toString(),
    185         type: this.attr('method') || 'GET'
    186     }, options || {});
     53        if (typeof options == 'function') {
     54                options = { success: options };
     55        }
    18756
    188     // hook for manipulating the form data before it is extracted;
    189     // convenient for use with rich editors like tinyMCE or FCKEditor
    190     var veto = {};
    191     $.event.trigger('form.pre.serialize', [this, options, veto]);
    192     if (veto.veto) return this;
     57        var action = this.attr('action');
     58        var url = (typeof action === 'string') ? $.trim(action) : '';
     59        if (url) {
     60                // clean url (don't include hash vaue)
     61                url = (url.match(/^([^#]+)/)||[])[1];
     62        }
     63        url = url || window.location.href || '';
    19364
    194     var a = this.formToArray(options.semantic);
     65        options = $.extend(true, {
     66                url:  url,
     67                type: this[0].getAttribute('method') || 'GET', // IE7 massage (see issue 57)
     68                iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
     69        }, options);
     70
     71        // hook for manipulating the form data before it is extracted;
     72        // convenient for use with rich editors like tinyMCE or FCKEditor
     73        var veto = {};
     74        this.trigger('form-pre-serialize', [this, options, veto]);
     75        if (veto.veto) {
     76                log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
     77                return this;
     78        }
     79
     80        // provide opportunity to alter form data before it is serialized
     81        if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
     82                log('ajaxSubmit: submit aborted via beforeSerialize callback');
     83                return this;
     84        }
     85
     86        var n,v,a = this.formToArray(options.semantic);
    19587        if (options.data) {
    196             for (var n in options.data)
    197                 a.push( { name: n, value: options.data[n] } );
     88                options.extraData = options.data;
     89                for (n in options.data) {
     90                        if(options.data[n] instanceof Array) {
     91                                for (var k in options.data[n]) {
     92                                        a.push( { name: n, value: options.data[n][k] } );
     93                                }
     94                        }
     95                        else {
     96                                v = options.data[n];
     97                                v = $.isFunction(v) ? v() : v; // if value is fn, invoke it
     98                                a.push( { name: n, value: v } );
     99                        }
     100                }
    198101        }
    199102
    200     // give pre-submit callback an opportunity to abort the submit
    201     if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) return this;
     103        // give pre-submit callback an opportunity to abort the submit
     104        if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
     105                log('ajaxSubmit: submit aborted via beforeSubmit callback');
     106                return this;
     107        }
    202108
    203     // fire vetoable 'validate' event
    204     $.event.trigger('form.submit.validate', [a, this, options, veto]);
    205     if (veto.veto) return this;
     109        // fire vetoable 'validate' event
     110        this.trigger('form-submit-validate', [a, this, options, veto]);
     111        if (veto.veto) {
     112                log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
     113                return this;
     114        }
    206115
    207     var q = $.param(a);//.replace(/%20/g,'+');
     116        var q = $.param(a);
    208117
    209     if (options.type.toUpperCase() == 'GET') {
    210         options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
    211         options.data = null;  // data is null for 'get'
    212     }
    213     else
    214         options.data = q; // data is the query string for 'post'
     118        if (options.type.toUpperCase() == 'GET') {
     119                options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
     120                options.data = null;  // data is null for 'get'
     121        }
     122        else {
     123                options.data = q; // data is the query string for 'post'
     124        }
    215125
    216     var $form = this, callbacks = [];
    217     if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
    218     if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
     126        var $form = this, callbacks = [];
     127        if (options.resetForm) {
     128                callbacks.push(function() { $form.resetForm(); });
     129        }
     130        if (options.clearForm) {
     131                callbacks.push(function() { $form.clearForm(); });
     132        }
    219133
    220     // perform a load on the target only if dataType is not provided
    221     if (!options.dataType && options.target) {
    222         var oldSuccess = options.success || function(){};
    223         callbacks.push(function(data) {
    224             if (this.evalScripts)
    225                 $(options.target).attr("innerHTML", data).evalScripts().each(oldSuccess, arguments);
    226             else // jQuery v1.1.4
    227                 $(options.target).html(data).each(oldSuccess, arguments);
    228         });
    229     }
    230     else if (options.success)
    231         callbacks.push(options.success);
     134        // perform a load on the target only if dataType is not provided
     135        if (!options.dataType && options.target) {
     136                var oldSuccess = options.success || function(){};
     137                callbacks.push(function(data) {
     138                        var fn = options.replaceTarget ? 'replaceWith' : 'html';
     139                        $(options.target)[fn](data).each(oldSuccess, arguments);
     140                });
     141        }
     142        else if (options.success) {
     143                callbacks.push(options.success);
     144        }
    232145
    233     options.success = function(data, status) {
    234         for (var i=0, max=callbacks.length; i < max; i++)
    235             callbacks[i](data, status, $form);
    236     };
     146        options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
     147                var context = options.context || options;   // jQuery 1.4+ supports scope context
     148                for (var i=0, max=callbacks.length; i < max; i++) {
     149                        callbacks[i].apply(context, [data, status, xhr || $form, $form]);
     150                }
     151        };
    237152
    238     // are there files to upload?
    239     var files = $('input:file', this).fieldValue();
    240     var found = false;
    241     for (var j=0; j < files.length; j++)
    242         if (files[j])
    243             found = true;
     153        // are there files to upload?
     154        var fileInputs = $('input:file', this).length > 0;
     155        var mp = 'multipart/form-data';
     156        var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
    244157
    245     // options.iframe allows user to force iframe mode
    246    if (options.iframe || found) {
    247        // hack to fix Safari hang (thanks to Tim Molendijk for this)
    248        // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
    249        if ($.browser.safari && options.closeKeepAlive)
    250            $.get(options.closeKeepAlive, fileUpload);
    251        else
    252            fileUpload();
    253        }
    254    else
    255        $.ajax(options);
     158        // options.iframe allows user to force iframe mode
     159        // 06-NOV-09: now defaulting to iframe mode if file input is detected
     160   if (options.iframe !== false && (fileInputs || options.iframe || multipart)) {
     161           // hack to fix Safari hang (thanks to Tim Molendijk for this)
     162           // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
     163           if (options.closeKeepAlive) {
     164                   $.get(options.closeKeepAlive, fileUpload);
     165                }
     166           else {
     167                   fileUpload();
     168                }
     169   }
     170   else {
     171                $.ajax(options);
     172   }
    256173
    257     // fire 'notify' event
    258     $.event.trigger('form.submit.notify', [this, options]);
    259     return this;
     174        // fire 'notify' event
     175        this.trigger('form-submit-notify', [this, options]);
     176        return this;
    260177
    261178
    262     // private function for handling file uploads (hat tip to YAHOO!)
    263     function fileUpload() {
    264         var form = $form[0];
    265         var opts = $.extend({}, $.ajaxSettings, options);
     179        // private function for handling file uploads (hat tip to YAHOO!)
     180        function fileUpload() {
     181                var form = $form[0];
    266182
    267         var id = 'jqFormIO' + $.fn.ajaxSubmit.counter++;
    268         var $io = $('<iframe id="' + id + '" name="' + id + '" />');
    269         var io = $io[0];
    270         var op8 = $.browser.opera && window.opera.version() < 9;
    271         if ($.browser.msie || op8) io.src = 'javascript:false;document.write("");';
    272         $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
     183                if ($(':input[name=submit],:input[id=submit]', form).length) {
     184                        // if there is an input with a name or id of 'submit' then we won't be
     185                        // able to invoke the submit fn on the form (at least not x-browser)
     186                        alert('Error: Form elements must not have name or id of "submit".');
     187                        return;
     188                }
     189               
     190                var s = $.extend(true, {}, $.ajaxSettings, options);
     191                s.context = s.context || s;
     192                var id = 'jqFormIO' + (new Date().getTime()), fn = '_'+id;
     193                var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ s.iframeSrc +'" />');
     194                var io = $io[0];
    273195
    274         var xhr = { // mock object
    275             responseText: null,
    276             responseXML: null,
    277             status: 0,
    278             statusText: 'n/a',
    279             getAllResponseHeaders: function() {},
    280             getResponseHeader: function() {},
    281             setRequestHeader: function() {}
    282         };
     196                $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
    283197
    284         var g = opts.global;
    285         // trigger ajax global events so that activity/block indicators work like normal
    286         if (g && ! $.active++) $.event.trigger("ajaxStart");
    287         if (g) $.event.trigger("ajaxSend", [xhr, opts]);
     198                var xhr = { // mock object
     199                        aborted: 0,
     200                        responseText: null,
     201                        responseXML: null,
     202                        status: 0,
     203                        statusText: 'n/a',
     204                        getAllResponseHeaders: function() {},
     205                        getResponseHeader: function() {},
     206                        setRequestHeader: function() {},
     207                        abort: function() {
     208                                this.aborted = 1;
     209                                $io.attr('src', s.iframeSrc); // abort op in progress
     210                        }
     211                };
    288212
    289         var cbInvoked = 0;
    290         var timedOut = 0;
     213                var g = s.global;
     214                // trigger ajax global events so that activity/block indicators work like normal
     215                if (g && ! $.active++) {
     216                        $.event.trigger("ajaxStart");
     217                }
     218                if (g) {
     219                        $.event.trigger("ajaxSend", [xhr, s]);
     220                }
    291221
    292         // take a breath so that pending repaints get some cpu time before the upload starts
    293         setTimeout(function() {
    294             // make sure form attrs are set
    295             var encAttr = form.encoding ? 'encoding' : 'enctype';
    296             var t = $form.attr('target');
    297             $form.attr({
    298                 target:   id,
    299                 method:  'POST',
    300                 action:   opts.url
    301             });
    302             form[encAttr] = 'multipart/form-data';
     222                if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
     223                        if (s.global) {
     224                                $.active--;
     225                        }
     226                        return;
     227                }
     228                if (xhr.aborted) {
     229                        return;
     230                }
    303231
    304             // support timout
    305             if (opts.timeout)
    306                 setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
     232                var timedOut = 0;
    307233
    308             // add iframe to doc and submit the form
    309             $io.appendTo('body');
    310             io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
    311             form.submit();
    312             $form.attr('target', t); // reset target
    313         }, 10);
     234                // add submitting element to data if we know it
     235                var sub = form.clk;
     236                if (sub) {
     237                        var n = sub.name;
     238                        if (n && !sub.disabled) {
     239                                s.extraData = s.extraData || {};
     240                                s.extraData[n] = sub.value;
     241                                if (sub.type == "image") {
     242                                        s.extraData[n+'.x'] = form.clk_x;
     243                                        s.extraData[n+'.y'] = form.clk_y;
     244                                }
     245                        }
     246                }
    314247
    315         function cb() {
    316             if (cbInvoked++) return;
     248                // take a breath so that pending repaints get some cpu time before the upload starts
     249                function doSubmit() {
     250                        // make sure form attrs are set
     251                        var t = $form.attr('target'), a = $form.attr('action');
    317252
     253                        // update form attrs in IE friendly way
     254                        form.setAttribute('target',id);
     255                        if (form.getAttribute('method') != 'POST') {
     256                                form.setAttribute('method', 'POST');
     257                        }
     258                        if (form.getAttribute('action') != s.url) {
     259                                form.setAttribute('action', s.url);
     260                        }
     261
     262                        // ie borks in some cases when setting encoding
     263                        if (! s.skipEncodingOverride) {
     264                                $form.attr({
     265                                        encoding: 'multipart/form-data',
     266                                        enctype:  'multipart/form-data'
     267                                });
     268                        }
     269
     270                        // support timout
     271                        if (s.timeout) {
     272                                setTimeout(function() { timedOut = true; cb(); }, s.timeout);
     273                        }
     274
     275                        // add "extra" data to form if provided in options
     276                        var extraInputs = [];
     277                        try {
     278                                if (s.extraData) {
     279                                        for (var n in s.extraData) {
     280                                                extraInputs.push(
     281                                                        $('<input type="hidden" name="'+n+'" value="'+s.extraData[n]+'" />')
     282                                                                .appendTo(form)[0]);
     283                                        }
     284                                }
     285
     286                                // add iframe to doc and submit the form
     287                                $io.appendTo('body');
     288                io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
     289                                form.submit();
     290                        }
     291                        finally {
     292                                // reset attrs and remove "extra" input elements
     293                                form.setAttribute('action',a);
     294                                if(t) {
     295                                        form.setAttribute('target', t);
     296                                } else {
     297                                        $form.removeAttr('target');
     298                                }
     299                                $(extraInputs).remove();
     300                        }
     301                }
     302
     303                if (s.forceSync) {
     304                        doSubmit();
     305                }
     306                else {
     307                        setTimeout(doSubmit, 10); // this lets dom updates render
     308                }
     309       
     310                var data, doc, domCheckCount = 50;
     311
     312                function cb() {
     313                        doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
     314                        if (!doc || doc.location.href == s.iframeSrc) {
     315                                // response not received yet
     316                                return;
     317                        }
    318318            io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
    319319
    320             var ok = true;
    321             try {
    322                 if (timedOut) throw 'timeout';
    323                 // extract the server response from the iframe
    324                 var data, doc;
    325                 doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
    326                 xhr.responseText = doc.body ? doc.body.innerHTML : null;
    327                 xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
     320                        var ok = true;
     321                        try {
     322                                if (timedOut) {
     323                                        throw 'timeout';
     324                                }
    328325
    329                 if (opts.dataType == 'json' || opts.dataType == 'script') {
    330                     var ta = doc.getElementsByTagName('textarea')[0];
    331                     data = ta ? ta.value : xhr.responseText;
    332                     if (opts.dataType == 'json')
    333                         eval("data = " + data);
    334                     else
    335                         $.globalEval(data);
    336                 }
    337                 else if (opts.dataType == 'xml') {
    338                     data = xhr.responseXML;
    339                     if (!data && xhr.responseText != null)
    340                         data = toXml(xhr.responseText);
    341                 }
    342                 else {
    343                     data = xhr.responseText;
    344                 }
    345             }
    346             catch(e){
    347                 ok = false;
    348                 $.handleError(opts, xhr, 'error', e);
    349             }
     326                                var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
     327                                log('isXml='+isXml);
     328                                if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) {
     329                                        if (--domCheckCount) {
     330                                                // in some browsers (Opera) the iframe DOM is not always traversable when
     331                                                // the onload callback fires, so we loop a bit to accommodate
     332                                                log('requeing onLoad callback, DOM not available');
     333                                                setTimeout(cb, 250);
     334                                                return;
     335                                        }
     336                                        // let this fall through because server response could be an empty document
     337                                        //log('Could not access iframe DOM after mutiple tries.');
     338                                        //throw 'DOMException: not available';
     339                                }
    350340
    351             // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
    352             if (ok) {
    353                 opts.success(data, 'success');
    354                 if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
    355             }
    356             if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
    357             if (g && ! --$.active) $.event.trigger("ajaxStop");
    358             if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
     341                                //log('response detected');
     342                                xhr.responseText = doc.body ? doc.body.innerHTML : doc.documentElement ? doc.documentElement.innerHTML : null;
     343                                xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
     344                                xhr.getResponseHeader = function(header){
     345                                        var headers = {'content-type': s.dataType};
     346                                        return headers[header];
     347                                };
    359348
    360             // clean up
    361             setTimeout(function() {
    362                 $io.remove();
    363                 xhr.responseXML = null;
    364             }, 100);
    365         };
     349                                var scr = /(json|script)/.test(s.dataType);
     350                                if (scr || s.textarea) {
     351                                        // see if user embedded response in textarea
     352                                        var ta = doc.getElementsByTagName('textarea')[0];
     353                                        if (ta) {
     354                                                xhr.responseText = ta.value;
     355                                        }
     356                                        else if (scr) {
     357                                                // account for browsers injecting pre around json response
     358                                                var pre = doc.getElementsByTagName('pre')[0];
     359                                                var b = doc.getElementsByTagName('body')[0];
     360                                                if (pre) {
     361                                                        xhr.responseText = pre.textContent;
     362                                                }
     363                                                else if (b) {
     364                                                        xhr.responseText = b.innerHTML;
     365                                                }
     366                                        }                         
     367                                }
     368                                else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
     369                                        xhr.responseXML = toXml(xhr.responseText);
     370                                }
     371                               
     372                                data = httpData(xhr, s.dataType, s);
     373                        }
     374                        catch(e){
     375                                log('error caught:',e);
     376                                ok = false;
     377                                xhr.error = e;
     378                                s.error.call(s.context, xhr, 'error', e);
     379                                g && $.event.trigger("ajaxError", [xhr, s, e]);
     380                        }
     381                       
     382                        if (xhr.aborted) {
     383                                log('upload aborted');
     384                                ok = false;
     385                        }
    366386
    367         function toXml(s, doc) {
    368             if (window.ActiveXObject) {
    369                 doc = new ActiveXObject('Microsoft.XMLDOM');
    370                 doc.async = 'false';
    371                 doc.loadXML(s);
    372             }
    373             else
    374                 doc = (new DOMParser()).parseFromString(s, 'text/xml');
    375             return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
    376         };
    377     };
     387                        // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
     388                        if (ok) {
     389                                s.success.call(s.context, data, 'success', xhr);
     390                                g && $.event.trigger("ajaxSuccess", [xhr, s]);
     391                        }
     392                       
     393                        g && $.event.trigger("ajaxComplete", [xhr, s]);
     394
     395                        if (g && ! --$.active) {
     396                                $.event.trigger("ajaxStop");
     397                        }
     398                       
     399                        s.complete && s.complete.call(s.context, xhr, ok ? 'success' : 'error');
     400
     401                        // clean up
     402                        setTimeout(function() {
     403                                $io.removeData('form-plugin-onload');
     404                                $io.remove();
     405                                xhr.responseXML = null;
     406                        }, 100);
     407                }
     408
     409                var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
     410                        if (window.ActiveXObject) {
     411                                doc = new ActiveXObject('Microsoft.XMLDOM');
     412                                doc.async = 'false';
     413                                doc.loadXML(s);
     414                        }
     415                        else {
     416                                doc = (new DOMParser()).parseFromString(s, 'text/xml');
     417                        }
     418                        return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
     419                };
     420                var parseJSON = $.parseJSON || function(s) {
     421                        return window['eval']('(' + s + ')');
     422                };
     423               
     424                var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
     425                        var ct = xhr.getResponseHeader('content-type') || '',
     426                                xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
     427                                data = xml ? xhr.responseXML : xhr.responseText;
     428
     429                        if (xml && data.documentElement.nodeName === 'parsererror') {
     430                                $.error && $.error('parsererror');
     431                        }
     432                        if (s && s.dataFilter) {
     433                                data = s.dataFilter(data, type);
     434                        }
     435                        if (typeof data === 'string') {
     436                                if (type === 'json' || !type && ct.indexOf('json') >= 0) {
     437                                        data = parseJSON(data);
     438                                } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
     439                                        $.globalEval(data);
     440                                }
     441                        }
     442                        return data;
     443                };
     444        }
    378445};
    379 $.fn.ajaxSubmit.counter = 0; // used to create unique iframe ids
    380446
    381447/**
    382448 * ajaxForm() provides a mechanism for fully automating form submission.
     
    384450 * The advantages of using this method instead of ajaxSubmit() are:
    385451 *
    386452 * 1: This method will include coordinates for <input type="image" /> elements (if the element
    387  *    is used to submit the form).
     453 *      is used to submit the form).
    388454 * 2. This method will include the submit element's name/value data (for the element that was
    389  *    used to submit the form).
     455 *      used to submit the form).
    390456 * 3. This method binds the submit() method to the form for you.
    391457 *
    392  * Note that for accurate x/y coordinates of image submit elements in all browsers
    393  * you need to also use the "dimensions" plugin (this method will auto-detect its presence).
    394  *
    395458 * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
    396459 * passes the options argument along after properly binding events for submit elements and
    397  * the form itself.  See ajaxSubmit for a full description of the options argument.
    398  *
    399  *
    400  * @example
    401  * var options = {
    402  *     target: '#myTargetDiv'
    403  * };
    404  * $('#myForm').ajaxSForm(options);
    405  * @desc Bind form's submit event so that 'myTargetDiv' is updated with the server response
    406  *       when the form is submitted.
    407  *
    408  *
    409  * @example
    410  * var options = {
    411  *     success: function(responseText) {
    412  *         alert(responseText);
    413  *     }
    414  * };
    415  * $('#myForm').ajaxSubmit(options);
    416  * @desc Bind form's submit event so that server response is alerted after the form is submitted.
    417  *
    418  *
    419  * @example
    420  * var options = {
    421  *     beforeSubmit: function(formArray, jqForm) {
    422  *         if (formArray.length == 0) {
    423  *             alert('Please enter data.');
    424  *             return false;
    425  *         }
    426  *     }
    427  * };
    428  * $('#myForm').ajaxSubmit(options);
    429  * @desc Bind form's submit event so that pre-submit callback is invoked before the form
    430  *       is submitted.
    431  *
    432  *
    433  * @name   ajaxForm
    434  * @param  options  object literal containing options which control the form submission process
    435  * @return jQuery
    436  * @cat    Plugins/Form
    437  * @type   jQuery
     460 * the form itself.
    438461 */
    439462$.fn.ajaxForm = function(options) {
    440     return this.ajaxFormUnbind().submit(submitHandler).each(function() {
    441         // store options in hash
    442         this.formPluginId = $.fn.ajaxForm.counter++;
    443         $.fn.ajaxForm.optionHash[this.formPluginId] = options;
    444         $(":submit,input:image", this).click(clickHandler);
    445     });
     463        // in jQuery 1.3+ we can fix mistakes with the ready state
     464        if (this.length === 0) {
     465                var o = { s: this.selector, c: this.context };
     466                if (!$.isReady && o.s) {
     467                        log('DOM not ready, queuing ajaxForm');
     468                        $(function() {
     469                                $(o.s,o.c).ajaxForm(options);
     470                        });
     471                        return this;
     472                }
     473                // is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
     474                log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
     475                return this;
     476        }
     477       
     478        return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
     479                if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
     480                        e.preventDefault();
     481                        $(this).ajaxSubmit(options);
     482                }
     483        }).bind('click.form-plugin', function(e) {
     484                var target = e.target;
     485                var $el = $(target);
     486                if (!($el.is(":submit,input:image"))) {
     487                        // is this a child element of the submit el?  (ex: a span within a button)
     488                        var t = $el.closest(':submit');
     489                        if (t.length == 0) {
     490                                return;
     491                        }
     492                        target = t[0];
     493                }
     494                var form = this;
     495                form.clk = target;
     496                if (target.type == 'image') {
     497                        if (e.offsetX != undefined) {
     498                                form.clk_x = e.offsetX;
     499                                form.clk_y = e.offsetY;
     500                        } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
     501                                var offset = $el.offset();
     502                                form.clk_x = e.pageX - offset.left;
     503                                form.clk_y = e.pageY - offset.top;
     504                        } else {
     505                                form.clk_x = e.pageX - target.offsetLeft;
     506                                form.clk_y = e.pageY - target.offsetTop;
     507                        }
     508                }
     509                // clear form vars
     510                setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
     511        });
    446512};
    447513
    448 $.fn.ajaxForm.counter = 1;
    449 $.fn.ajaxForm.optionHash = {};
    450 
    451 function clickHandler(e) {
    452     var $form = this.form;
    453     $form.clk = this;
    454     if (this.type == 'image') {
    455         if (e.offsetX != undefined) {
    456             $form.clk_x = e.offsetX;
    457             $form.clk_y = e.offsetY;
    458         } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
    459             var offset = $(this).offset();
    460             $form.clk_x = e.pageX - offset.left;
    461             $form.clk_y = e.pageY - offset.top;
    462         } else {
    463             $form.clk_x = e.pageX - this.offsetLeft;
    464             $form.clk_y = e.pageY - this.offsetTop;
    465         }
    466     }
    467     // clear form vars
    468     setTimeout(function() { $form.clk = $form.clk_x = $form.clk_y = null; }, 10);
    469 };
    470 
    471 function submitHandler() {
    472     // retrieve options from hash
    473     var id = this.formPluginId;
    474     var options = $.fn.ajaxForm.optionHash[id];
    475     $(this).ajaxSubmit(options);
    476     return false;
    477 };
    478 
    479 /**
    480  * ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
    481  *
    482  * @name   ajaxFormUnbind
    483  * @return jQuery
    484  * @cat    Plugins/Form
    485  * @type   jQuery
    486  */
     514// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
    487515$.fn.ajaxFormUnbind = function() {
    488     this.unbind('submit', submitHandler);
    489     return this.each(function() {
    490         $(":submit,input:image", this).unbind('click', clickHandler);
    491     });
    492 
     516        return this.unbind('submit.form-plugin click.form-plugin');
    493517};
    494518
    495519/**
     
    502526 *
    503527 * It is this array that is passed to pre-submit callback functions provided to the
    504528 * ajaxSubmit() and ajaxForm() methods.
    505  *
    506  * The semantic argument can be used to force form serialization in semantic order.
    507  * This is normally true anyway, unless the form contains input elements of type='image'.
    508  * If your form must be submitted with name/value pairs in semantic order and your form
    509  * contains an input of type='image" then pass true for this arg, otherwise pass false
    510  * (or nothing) to avoid the overhead for this logic.
    511  *
    512  * @example var data = $("#myForm").formToArray();
    513  * $.post( "myscript.cgi", data );
    514  * @desc Collect all the data from a form and submit it to the server.
    515  *
    516  * @name formToArray
    517  * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
    518  * @type Array<Object>
    519  * @cat Plugins/Form
    520529 */
    521530$.fn.formToArray = function(semantic) {
    522     var a = [];
    523     if (this.length == 0) return a;
     531        var a = [];
     532        if (this.length === 0) {
     533                return a;
     534        }
    524535
    525     var form = this[0];
    526     var els = semantic ? form.getElementsByTagName('*') : form.elements;
    527     if (!els) return a;
    528     for(var i=0, max=els.length; i < max; i++) {
    529         var el = els[i];
    530         var n = el.name;
    531         if (!n) continue;
     536        var form = this[0];
     537        var els = semantic ? form.getElementsByTagName('*') : form.elements;
     538        if (!els) {
     539                return a;
     540        }
     541       
     542        var i,j,n,v,el,max,jmax;
     543        for(i=0, max=els.length; i < max; i++) {
     544                el = els[i];
     545                n = el.name;
     546                if (!n) {
     547                        continue;
     548                }
    532549
    533         if (semantic && form.clk && el.type == "image") {
    534             // handle image inputs on the fly when semantic == true
    535             if(!el.disabled && form.clk == el)
    536                 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
    537             continue;
    538         }
     550                if (semantic && form.clk && el.type == "image") {
     551                        // handle image inputs on the fly when semantic == true
     552                        if(!el.disabled && form.clk == el) {
     553                                a.push({name: n, value: $(el).val()});
     554                                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
     555                        }
     556                        continue;
     557                }
    539558
    540         var v = $.fieldValue(el, true);
    541         if (v && v.constructor == Array) {
    542             for(var j=0, jmax=v.length; j < jmax; j++)
    543                 a.push({name: n, value: v[j]});
    544         }
    545         else if (v !== null && typeof v != 'undefined')
    546             a.push({name: n, value: v});
    547     }
     559                v = $.fieldValue(el, true);
     560                if (v && v.constructor == Array) {
     561                        for(j=0, jmax=v.length; j < jmax; j++) {
     562                                a.push({name: n, value: v[j]});
     563                        }
     564                }
     565                else if (v !== null && typeof v != 'undefined') {
     566                        a.push({name: n, value: v});
     567                }
     568        }
    548569
    549     if (!semantic && form.clk) {
    550         // input type=='image' are not found in elements array! handle them here
    551         var inputs = form.getElementsByTagName("input");
    552         for(var i=0, max=inputs.length; i < max; i++) {
    553             var input = inputs[i];
    554             var n = input.name;
    555             if(n && !input.disabled && input.type == "image" && form.clk == input)
    556                 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
    557         }
    558     }
    559     return a;
     570        if (!semantic && form.clk) {
     571                // input type=='image' are not found in elements array! handle it here
     572                var $input = $(form.clk), input = $input[0];
     573                n = input.name;
     574                if (n && !input.disabled && input.type == 'image') {
     575                        a.push({name: n, value: $input.val()});
     576                        a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
     577                }
     578        }
     579        return a;
    560580};
    561581
    562 
    563582/**
    564583 * Serializes form data into a 'submittable' string. This method will return a string
    565584 * in the format: name1=value1&amp;name2=value2
    566  *
    567  * The semantic argument can be used to force form serialization in semantic order.
    568  * If your form must be submitted with name/value pairs in semantic order then pass
    569  * true for this arg, otherwise pass false (or nothing) to avoid the overhead for
    570  * this logic (which can be significant for very large forms).
    571  *
    572  * @example var data = $("#myForm").formSerialize();
    573  * $.ajax('POST', "myscript.cgi", data);
    574  * @desc Collect all the data from a form into a single string
    575  *
    576  * @name formSerialize
    577  * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
    578  * @type String
    579  * @cat Plugins/Form
    580585 */
    581586$.fn.formSerialize = function(semantic) {
    582     //hand off to jQuery.param for proper encoding
    583     return $.param(this.formToArray(semantic));
     587        //hand off to jQuery.param for proper encoding
     588        return $.param(this.formToArray(semantic));
    584589};
    585590
    586 
    587591/**
    588592 * Serializes all field elements in the jQuery object into a query string.
    589593 * This method will return a string in the format: name1=value1&amp;name2=value2
    590  *
    591  * The successful argument controls whether or not serialization is limited to
    592  * 'successful' controls (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
    593  * The default value of the successful argument is true.
    594  *
    595  * @example var data = $("input").formSerialize();
    596  * @desc Collect the data from all successful input elements into a query string
    597  *
    598  * @example var data = $(":radio").formSerialize();
    599  * @desc Collect the data from all successful radio input elements into a query string
    600  *
    601  * @example var data = $("#myForm :checkbox").formSerialize();
    602  * @desc Collect the data from all successful checkbox input elements in myForm into a query string
    603  *
    604  * @example var data = $("#myForm :checkbox").formSerialize(false);
    605  * @desc Collect the data from all checkbox elements in myForm (even the unchecked ones) into a query string
    606  *
    607  * @example var data = $(":input").formSerialize();
    608  * @desc Collect the data from all successful input, select, textarea and button elements into a query string
    609  *
    610  * @name fieldSerialize
    611  * @param successful true if only successful controls should be serialized (default is true)
    612  * @type String
    613  * @cat Plugins/Form
    614594 */
    615595$.fn.fieldSerialize = function(successful) {
    616     var a = [];
    617     this.each(function() {
    618         var n = this.name;
    619         if (!n) return;
    620         var v = $.fieldValue(this, successful);
    621         if (v && v.constructor == Array) {
    622             for (var i=0,max=v.length; i < max; i++)
    623                 a.push({name: n, value: v[i]});
    624         }
    625         else if (v !== null && typeof v != 'undefined')
    626             a.push({name: this.name, value: v});
    627     });
    628     //hand off to jQuery.param for proper encoding
    629     return $.param(a);
     596        var a = [];
     597        this.each(function() {
     598                var n = this.name;
     599                if (!n) {
     600                        return;
     601                }
     602                var v = $.fieldValue(this, successful);
     603                if (v && v.constructor == Array) {
     604                        for (var i=0,max=v.length; i < max; i++) {
     605                                a.push({name: n, value: v[i]});
     606                        }
     607                }
     608                else if (v !== null && typeof v != 'undefined') {
     609                        a.push({name: this.name, value: v});
     610                }
     611        });
     612        //hand off to jQuery.param for proper encoding
     613        return $.param(a);
    630614};
    631615
    632 
    633616/**
    634617 * Returns the value(s) of the element in the matched set.  For example, consider the following form:
    635618 *
    636619 *  <form><fieldset>
    637  *      <input name="A" type="text" />
    638  *      <input name="A" type="text" />
    639  *      <input name="B" type="checkbox" value="B1" />
    640  *      <input name="B" type="checkbox" value="B2"/>
    641  *      <input name="C" type="radio" value="C1" />
    642  *      <input name="C" type="radio" value="C2" />
     620 *        <input name="A" type="text" />
     621 *        <input name="A" type="text" />
     622 *        <input name="B" type="checkbox" value="B1" />
     623 *        <input name="B" type="checkbox" value="B2"/>
     624 *        <input name="C" type="radio" value="C1" />
     625 *        <input name="C" type="radio" value="C2" />
    643626 *  </fieldset></form>
    644627 *
    645628 *  var v = $(':text').fieldValue();
     
    666649 * for each element is returned.
    667650 *
    668651 * Note: This method *always* returns an array.  If no valid value can be determined the
    669  *       array will be empty, otherwise it will contain one or more values.
    670  *
    671  * @example var data = $("#myPasswordElement").fieldValue();
    672  * alert(data[0]);
    673  * @desc Alerts the current value of the myPasswordElement element
    674  *
    675  * @example var data = $("#myForm :input").fieldValue();
    676  * @desc Get the value(s) of the form elements in myForm
    677  *
    678  * @example var data = $("#myForm :checkbox").fieldValue();
    679  * @desc Get the value(s) for the successful checkbox element(s) in the jQuery object.
    680  *
    681  * @example var data = $("#mySingleSelect").fieldValue();
    682  * @desc Get the value(s) of the select control
    683  *
    684  * @example var data = $(':text').fieldValue();
    685  * @desc Get the value(s) of the text input or textarea elements
    686  *
    687  * @example var data = $("#myMultiSelect").fieldValue();
    688  * @desc Get the values for the select-multiple control
    689  *
    690  * @name fieldValue
    691  * @param Boolean successful true if only the values for successful controls should be returned (default is true)
    692  * @type Array<String>
    693  * @cat Plugins/Form
     652 *         array will be empty, otherwise it will contain one or more values.
    694653 */
    695654$.fn.fieldValue = function(successful) {
    696     for (var val=[], i=0, max=this.length; i < max; i++) {
    697         var el = this[i];
    698         var v = $.fieldValue(el, successful);
    699         if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
    700             continue;
    701         v.constructor == Array ? $.merge(val, v) : val.push(v);
    702     }
    703     return val;
     655        for (var val=[], i=0, max=this.length; i < max; i++) {
     656                var el = this[i];
     657                var v = $.fieldValue(el, successful);
     658                if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
     659                        continue;
     660                }
     661                v.constructor == Array ? $.merge(val, v) : val.push(v);
     662        }
     663        return val;
    704664};
    705665
    706666/**
    707667 * Returns the value of the field element.
    708  *
    709  * The successful argument controls whether or not the field element must be 'successful'
    710  * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
    711  * The default value of the successful argument is true.  If the given element is not
    712  * successful and the successful arg is not false then the returned value will be null.
    713  *
    714  * Note: If the successful flag is true (default) but the element is not successful, the return will be null
    715  * Note: The value returned for a successful select-multiple element will always be an array.
    716  * Note: If the element has no value the return value will be undefined.
    717  *
    718  * @example var data = jQuery.fieldValue($("#myPasswordElement")[0]);
    719  * @desc Gets the current value of the myPasswordElement element
    720  *
    721  * @name fieldValue
    722  * @param Element el The DOM element for which the value will be returned
    723  * @param Boolean successful true if value returned must be for a successful controls (default is true)
    724  * @type String or Array<String> or null or undefined
    725  * @cat Plugins/Form
    726668 */
    727669$.fieldValue = function(el, successful) {
    728     var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
    729     if (typeof successful == 'undefined') successful = true;
     670        var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
     671        if (successful === undefined) {
     672                successful = true;
     673        }
    730674
    731     if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
    732         (t == 'checkbox' || t == 'radio') && !el.checked ||
    733         (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
    734         tag == 'select' && el.selectedIndex == -1))
    735             return null;
     675        if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
     676                (t == 'checkbox' || t == 'radio') && !el.checked ||
     677                (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
     678                tag == 'select' && el.selectedIndex == -1)) {
     679                        return null;
     680        }
    736681
    737     if (tag == 'select') {
    738         var index = el.selectedIndex;
    739         if (index < 0) return null;
    740         var a = [], ops = el.options;
    741         var one = (t == 'select-one');
    742         var max = (one ? index+1 : ops.length);
    743         for(var i=(one ? index : 0); i < max; i++) {
    744             var op = ops[i];
    745             if (op.selected) {
    746                 // extra pain for IE...
    747                 var v = $.browser.msie && !(op.attributes['value'].specified) ? op.text : op.value;
    748                 if (one) return v;
    749                 a.push(v);
    750             }
    751         }
    752         return a;
    753     }
    754     return el.value;
     682        if (tag == 'select') {
     683                var index = el.selectedIndex;
     684                if (index < 0) {
     685                        return null;
     686                }
     687                var a = [], ops = el.options;
     688                var one = (t == 'select-one');
     689                var max = (one ? index+1 : ops.length);
     690                for(var i=(one ? index : 0); i < max; i++) {
     691                        var op = ops[i];
     692                        if (op.selected) {
     693                                var v = op.value;
     694                                if (!v) { // extra pain for IE...
     695                                        v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
     696                                }
     697                                if (one) {
     698                                        return v;
     699                                }
     700                                a.push(v);
     701                        }
     702                }
     703                return a;
     704        }
     705        return $(el).val();
    755706};
    756707
    757 
    758708/**
    759709 * Clears the form data.  Takes the following actions on the form's input fields:
    760710 *  - input text fields will have their 'value' property set to the empty string
     
    762712 *  - checkbox and radio inputs will have their 'checked' property set to false
    763713 *  - inputs of type submit, button, reset, and hidden will *not* be effected
    764714 *  - button elements will *not* be effected
    765  *
    766  * @example $('form').clearForm();
    767  * @desc Clears all forms on the page.
    768  *
    769  * @name clearForm
    770  * @type jQuery
    771  * @cat Plugins/Form
    772715 */
    773716$.fn.clearForm = function() {
    774     return this.each(function() {
    775         $('input,select,textarea', this).clearFields();
    776     });
     717        return this.each(function() {
     718                $('input,select,textarea', this).clearFields();
     719        });
    777720};
    778721
    779722/**
    780  * Clears the selected form elements.  Takes the following actions on the matched elements:
    781  *  - input text fields will have their 'value' property set to the empty string
    782  *  - select elements will have their 'selectedIndex' property set to -1
    783  *  - checkbox and radio inputs will have their 'checked' property set to false
    784  *  - inputs of type submit, button, reset, and hidden will *not* be effected
    785  *  - button elements will *not* be effected
    786  *
    787  * @example $('.myInputs').clearFields();
    788  * @desc Clears all inputs with class myInputs
    789  *
    790  * @name clearFields
    791  * @type jQuery
    792  * @cat Plugins/Form
     723 * Clears the selected form elements.
    793724 */
    794725$.fn.clearFields = $.fn.clearInputs = function() {
    795     return this.each(function() {
    796         var t = this.type, tag = this.tagName.toLowerCase();
    797         if (t == 'text' || t == 'password' || tag == 'textarea')
    798             this.value = '';
    799         else if (t == 'checkbox' || t == 'radio')
    800             this.checked = false;
    801         else if (tag == 'select')
    802             this.selectedIndex = -1;
    803     });
     726        return this.each(function() {
     727                var t = this.type, tag = this.tagName.toLowerCase();
     728                if (t == 'text' || t == 'password' || tag == 'textarea') {
     729                        this.value = '';
     730                }
     731                else if (t == 'checkbox' || t == 'radio') {
     732                        this.checked = false;
     733                }
     734                else if (tag == 'select') {
     735                        this.selectedIndex = -1;
     736                }
     737        });
    804738};
    805739
    806 
    807740/**
    808741 * Resets the form data.  Causes all form elements to be reset to their original value.
    809  *
    810  * @example $('form').resetForm();
    811  * @desc Resets all forms on the page.
    812  *
    813  * @name resetForm
    814  * @type jQuery
    815  * @cat Plugins/Form
    816742 */
    817743$.fn.resetForm = function() {
    818     return this.each(function() {
    819         // guard against an input with the name of 'reset'
    820         // note that IE reports the reset function as an 'object'
    821         if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
    822             this.reset();
    823     });
     744        return this.each(function() {
     745                // guard against an input with the name of 'reset'
     746                // note that IE reports the reset function as an 'object'
     747                if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
     748                        this.reset();
     749                }
     750        });
    824751};
    825752
    826 
    827753/**
    828754 * Enables or disables any matching elements.
    829  *
    830  * @example $(':radio').enabled(false);
    831  * @desc Disables all radio buttons
    832  *
    833  * @name select
    834  * @type jQuery
    835  * @cat Plugins/Form
    836755 */
    837 $.fn.enable = function(b) {
    838     if (b == undefined) b = true;
    839     return this.each(function() {
    840         this.disabled = !b
    841     });
     756$.fn.enable = function(b) {
     757        if (b === undefined) {
     758                b = true;
     759        }
     760        return this.each(function() {
     761                this.disabled = !b;
     762        });
    842763};
    843764
    844765/**
    845766 * Checks/unchecks any matching checkboxes or radio buttons and
    846767 * selects/deselects and matching option elements.
    847  *
    848  * @example $(':checkbox').selected();
    849  * @desc Checks all checkboxes
    850  *
    851  * @name select
    852  * @type jQuery
    853  * @cat Plugins/Form
    854768 */
    855 $.fn.select = function(select) {
    856     if (select == undefined) select = true;
    857     return this.each(function() {
    858         var t = this.type;
    859         if (t == 'checkbox' || t == 'radio')
    860             this.checked = select;
    861         else if (this.tagName.toLowerCase() == 'option') {
    862             var $sel = $(this).parent('select');
    863             if (select && $sel[0] && $sel[0].type == 'select-one') {
    864                 // deselect all other options
    865                 $sel.find('option').select(false);
    866             }
    867             this.selected = select;
    868         }
    869     });
     769$.fn.selected = function(select) {
     770        if (select === undefined) {
     771                select = true;
     772        }
     773        return this.each(function() {
     774                var t = this.type;
     775                if (t == 'checkbox' || t == 'radio') {
     776                        this.checked = select;
     777                }
     778                else if (this.tagName.toLowerCase() == 'option') {
     779                        var $sel = $(this).parent('select');
     780                        if (select && $sel[0] && $sel[0].type == 'select-one') {
     781                                // deselect all other options
     782                                $sel.find('option').selected(false);
     783                        }
     784                        this.selected = select;
     785                }
     786        });
    870787};
    871788
    872 })(jQuery);
     789// helper fn for console logging
     790// set $.fn.ajaxSubmit.debug to true to enable debug logging
     791function log() {
     792        if ($.fn.ajaxSubmit.debug) {
     793                var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
     794                if (window.console && window.console.log) {
     795                        window.console.log(msg);
     796                }
     797                else if (window.opera && window.opera.postError) {
     798                        window.opera.postError(msg);
     799                }
     800        }
     801};
     802
     803})(jQuery);
     804 No newline at end of file