WordPress.org

Make WordPress Core

Ticket #23944: 23944.1.diff

File 23944.1.diff, 60.9 KB (added by JustinSainton, 2 years ago)

Updating again to latest.

  • wp-includes/functions.php

     
    37403740        return false; 
    37413741} 
    37423742 
     3743 
     3744 
    37433745/** 
    37443746 * Send a HTTP header to limit rendering of pages to same origin iframes. 
    37453747 * 
  • wp-includes/js/jquery/jquery.form.js

     
    11/*! 
    22 * jQuery Form Plugin 
    3  * version: 2.73 (03-MAY-2011) 
    4  * @requires jQuery v1.3.2 or later 
    5  * 
     3 * version: 3.32.0-2013.04.09 
     4 * @requires jQuery v1.5 or later 
     5 * Copyright (c) 2013 M. Alsup 
    66 * Examples and documentation at: http://malsup.com/jquery/form/ 
    7  * Dual licensed under the MIT and GPL licenses: 
    8  *   http://www.opensource.org/licenses/mit-license.php 
    9  *   http://www.gnu.org/licenses/gpl.html 
     7 * Project repository: https://github.com/malsup/form 
     8 * Dual licensed under the MIT and GPL licenses. 
     9 * https://github.com/malsup/form#copyright-and-license 
    1010 */ 
     11/*global ActiveXObject */ 
    1112;(function($) { 
     13"use strict"; 
    1214 
    1315/* 
    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, 
     16    Usage Note: 
     17    ----------- 
     18    Do not use both ajaxSubmit and ajaxForm on the same form.  These 
     19    functions are mutually exclusive.  Use ajaxSubmit if you want 
     20    to bind your own submit handler to the form.  For example, 
    1921 
    20         $(document).ready(function() { 
    21                 $('#myForm').bind('submit', function(e) { 
    22                         e.preventDefault(); // <-- important 
    23                         $(this).ajaxSubmit({ 
    24                                 target: '#output' 
    25                         }); 
    26                 }); 
    27         }); 
     22    $(document).ready(function() { 
     23        $('#myForm').on('submit', function(e) { 
     24            e.preventDefault(); // <-- important 
     25            $(this).ajaxSubmit({ 
     26                target: '#output' 
     27            }); 
     28        }); 
     29    }); 
    2830 
    29         Use ajaxForm when you want the plugin to manage all the event binding 
    30         for you.  For example, 
     31    Use ajaxForm when you want the plugin to manage all the event binding 
     32    for you.  For example, 
    3133 
    32         $(document).ready(function() { 
    33                 $('#myForm').ajaxForm({ 
    34                         target: '#output' 
    35                 }); 
    36         }); 
     34    $(document).ready(function() { 
     35        $('#myForm').ajaxForm({ 
     36            target: '#output' 
     37        }); 
     38    }); 
    3739 
    38         When using ajaxForm, the ajaxSubmit function will be invoked for you 
    39         at the appropriate time. 
     40    You can also use ajaxForm with delegation (requires jQuery v1.7+), so the 
     41    form does not have to exist when you invoke ajaxForm: 
     42 
     43    $('#myForm').ajaxForm({ 
     44        delegation: true, 
     45        target: '#output' 
     46    }); 
     47 
     48    When using ajaxForm, the ajaxSubmit function will be invoked for you 
     49    at the appropriate time. 
    4050*/ 
    4151 
    4252/** 
     53 * Feature detection 
     54 */ 
     55var feature = {}; 
     56feature.fileapi = $("<input type='file'/>").get(0).files !== undefined; 
     57feature.formdata = window.FormData !== undefined; 
     58 
     59var hasProp = !!$.fn.prop; 
     60 
     61// attr2 uses prop when it can but checks the return type for 
     62// an expected string.  this accounts for the case where a form 
     63// contains inputs with names like "action" or "method"; in those 
     64// cases "prop" returns the element 
     65$.fn.attr2 = function() { 
     66    if ( ! hasProp ) 
     67        return this.attr.apply(this, arguments); 
     68    var val = this.prop.apply(this, arguments); 
     69    if ( ( val && val.jquery ) || typeof val === 'string' ) 
     70        return val; 
     71    return this.attr.apply(this, arguments); 
     72}; 
     73 
     74/** 
    4375 * ajaxSubmit() provides a mechanism for immediately submitting 
    4476 * an HTML form using AJAX. 
    4577 */ 
    4678$.fn.ajaxSubmit = function(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         } 
     79    /*jshint scripturl:true */ 
    5280 
    53         if (typeof options == 'function') { 
    54                 options = { success: options }; 
    55         } 
     81    // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) 
     82    if (!this.length) { 
     83        log('ajaxSubmit: skipping submit process - no element selected'); 
     84        return this; 
     85    } 
    5686 
    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 || ''; 
     87    var method, action, url, $form = this; 
    6488 
    65         options = $.extend(true, { 
    66                 url:  url, 
    67                 success: $.ajaxSettings.success, 
    68                 type: this[0].getAttribute('method') || 'GET', // IE7 massage (see issue 57) 
    69                 iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' 
    70         }, options); 
     89    if (typeof options == 'function') { 
     90        options = { success: options }; 
     91    } 
    7192 
    72         // hook for manipulating the form data before it is extracted; 
    73         // convenient for use with rich editors like tinyMCE or FCKEditor 
    74         var veto = {}; 
    75         this.trigger('form-pre-serialize', [this, options, veto]); 
    76         if (veto.veto) { 
    77                 log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); 
    78                 return this; 
    79         } 
     93    method = this.attr2('method'); 
     94    action = this.attr2('action'); 
    8095 
    81         // provide opportunity to alter form data before it is serialized 
    82         if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { 
    83                 log('ajaxSubmit: submit aborted via beforeSerialize callback'); 
    84                 return this; 
    85         } 
     96    url = (typeof action === 'string') ? $.trim(action) : ''; 
     97    url = url || window.location.href || ''; 
     98    if (url) { 
     99        // clean url (don't include hash vaue) 
     100        url = (url.match(/^([^#]+)/)||[])[1]; 
     101    } 
    86102 
    87         var n,v,a = this.formToArray(options.semantic); 
    88         if (options.data) { 
    89                 options.extraData = options.data; 
    90                 for (n in options.data) { 
    91                         if(options.data[n] instanceof Array) { 
    92                                 for (var k in options.data[n]) { 
    93                                         a.push( { name: n, value: options.data[n][k] } ); 
    94                                 } 
    95                         } 
    96                         else { 
    97                                 v = options.data[n]; 
    98                                 v = $.isFunction(v) ? v() : v; // if value is fn, invoke it 
    99                                 a.push( { name: n, value: v } ); 
    100                         } 
    101                 } 
    102         } 
     103    options = $.extend(true, { 
     104        url:  url, 
     105        success: $.ajaxSettings.success, 
     106        type: method || 'GET', 
     107        iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' 
     108    }, options); 
    103109 
    104         // give pre-submit callback an opportunity to abort the submit 
    105         if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { 
    106                 log('ajaxSubmit: submit aborted via beforeSubmit callback'); 
    107                 return this; 
    108         } 
     110    // hook for manipulating the form data before it is extracted; 
     111    // convenient for use with rich editors like tinyMCE or FCKEditor 
     112    var veto = {}; 
     113    this.trigger('form-pre-serialize', [this, options, veto]); 
     114    if (veto.veto) { 
     115        log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); 
     116        return this; 
     117    } 
    109118 
    110         // fire vetoable 'validate' event 
    111         this.trigger('form-submit-validate', [a, this, options, veto]); 
    112         if (veto.veto) { 
    113                 log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); 
    114                 return this; 
    115         } 
     119    // provide opportunity to alter form data before it is serialized 
     120    if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { 
     121        log('ajaxSubmit: submit aborted via beforeSerialize callback'); 
     122        return this; 
     123    } 
    116124 
    117         var q = $.param(a); 
     125    var traditional = options.traditional; 
     126    if ( traditional === undefined ) { 
     127        traditional = $.ajaxSettings.traditional; 
     128    } 
    118129 
    119         if (options.type.toUpperCase() == 'GET') { 
    120                 options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; 
    121                 options.data = null;  // data is null for 'get' 
    122         } 
    123         else { 
    124                 options.data = q; // data is the query string for 'post' 
    125         } 
     130    var elements = []; 
     131    var qx, a = this.formToArray(options.semantic, elements); 
     132    if (options.data) { 
     133        options.extraData = options.data; 
     134        qx = $.param(options.data, traditional); 
     135    } 
    126136 
    127         var $form = this, callbacks = []; 
    128         if (options.resetForm) { 
    129                 callbacks.push(function() { $form.resetForm(); }); 
    130         } 
    131         if (options.clearForm) { 
    132                 callbacks.push(function() { $form.clearForm(); }); 
    133         } 
     137    // give pre-submit callback an opportunity to abort the submit 
     138    if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { 
     139        log('ajaxSubmit: submit aborted via beforeSubmit callback'); 
     140        return this; 
     141    } 
    134142 
    135         // perform a load on the target only if dataType is not provided 
    136         if (!options.dataType && options.target) { 
    137                 var oldSuccess = options.success || function(){}; 
    138                 callbacks.push(function(data) { 
    139                         var fn = options.replaceTarget ? 'replaceWith' : 'html'; 
    140                         $(options.target)[fn](data).each(oldSuccess, arguments); 
    141                 }); 
    142         } 
    143         else if (options.success) { 
    144                 callbacks.push(options.success); 
    145         } 
     143    // fire vetoable 'validate' event 
     144    this.trigger('form-submit-validate', [a, this, options, veto]); 
     145    if (veto.veto) { 
     146        log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); 
     147        return this; 
     148    } 
    146149 
    147         options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg 
    148                 var context = options.context || options;   // jQuery 1.4+ supports scope context 
    149                 for (var i=0, max=callbacks.length; i < max; i++) { 
    150                         callbacks[i].apply(context, [data, status, xhr || $form, $form]); 
    151                 } 
    152         }; 
     150    var q = $.param(a, traditional); 
     151    if (qx) { 
     152        q = ( q ? (q + '&' + qx) : qx ); 
     153    } 
     154    if (options.type.toUpperCase() == 'GET') { 
     155        options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; 
     156        options.data = null;  // data is null for 'get' 
     157    } 
     158    else { 
     159        options.data = q; // data is the query string for 'post' 
     160    } 
    153161 
    154         // are there files to upload? 
    155         var fileInputs = $('input:file', this).length > 0; 
    156         var mp = 'multipart/form-data'; 
    157         var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); 
     162    var callbacks = []; 
     163    if (options.resetForm) { 
     164        callbacks.push(function() { $form.resetForm(); }); 
     165    } 
     166    if (options.clearForm) { 
     167        callbacks.push(function() { $form.clearForm(options.includeHidden); }); 
     168    } 
    158169 
    159         // options.iframe allows user to force iframe mode 
    160         // 06-NOV-09: now defaulting to iframe mode if file input is detected 
    161    if (options.iframe !== false && (fileInputs || options.iframe || multipart)) { 
    162            // hack to fix Safari hang (thanks to Tim Molendijk for this) 
    163            // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d 
    164            if (options.closeKeepAlive) { 
    165                    $.get(options.closeKeepAlive, fileUpload); 
    166                 } 
    167            else { 
    168                    fileUpload(); 
    169                 } 
    170    } 
    171    else { 
    172                 $.ajax(options); 
    173    } 
     170    // perform a load on the target only if dataType is not provided 
     171    if (!options.dataType && options.target) { 
     172        var oldSuccess = options.success || function(){}; 
     173        callbacks.push(function(data) { 
     174            var fn = options.replaceTarget ? 'replaceWith' : 'html'; 
     175            $(options.target)[fn](data).each(oldSuccess, arguments); 
     176        }); 
     177    } 
     178    else if (options.success) { 
     179        callbacks.push(options.success); 
     180    } 
    174181 
    175         // fire 'notify' event 
    176         this.trigger('form-submit-notify', [this, options]); 
    177         return this; 
     182    options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg 
     183        var context = options.context || this ;    // jQuery 1.4+ supports scope context 
     184        for (var i=0, max=callbacks.length; i < max; i++) { 
     185            callbacks[i].apply(context, [data, status, xhr || $form, $form]); 
     186        } 
     187    }; 
    178188 
     189    // are there files to upload? 
    179190 
    180         // private function for handling file uploads (hat tip to YAHOO!) 
    181         function fileUpload() { 
    182                 var form = $form[0]; 
     191    // [value] (issue #113), also see comment: 
     192    // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219 
     193    var fileInputs = $('input[type=file]:enabled[value!=""]', this); 
    183194 
    184                 if ($(':input[name=submit],:input[id=submit]', form).length) { 
    185                         // if there is an input with a name or id of 'submit' then we won't be 
    186                         // able to invoke the submit fn on the form (at least not x-browser) 
    187                         alert('Error: Form elements must not have name or id of "submit".'); 
    188                         return; 
    189                 } 
     195    var hasFileInputs = fileInputs.length > 0; 
     196    var mp = 'multipart/form-data'; 
     197    var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); 
    190198 
    191                 var s = $.extend(true, {}, $.ajaxSettings, options); 
    192                 s.context = s.context || s; 
    193                 var id = 'jqFormIO' + (new Date().getTime()), fn = '_'+id; 
    194                 var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ s.iframeSrc +'" />'); 
    195                 var io = $io[0]; 
     199    var fileAPI = feature.fileapi && feature.formdata; 
     200    log("fileAPI :" + fileAPI); 
     201    var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI; 
    196202 
    197                 $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' }); 
     203    var jqxhr; 
    198204 
    199                 var xhr = { // mock object 
    200                         aborted: 0, 
    201                         responseText: null, 
    202                         responseXML: null, 
    203                         status: 0, 
    204                         statusText: 'n/a', 
    205                         getAllResponseHeaders: function() {}, 
    206                         getResponseHeader: function() {}, 
    207                         setRequestHeader: function() {}, 
    208                         abort: function(status) { 
    209                                 var e = (status === 'timeout' ? 'timeout' : 'aborted'); 
    210                                 log('aborting upload... ' + e); 
    211                                 this.aborted = 1; 
    212                                 $io.attr('src', s.iframeSrc); // abort op in progress 
    213                                 xhr.error = e; 
    214                                 s.error && s.error.call(s.context, xhr, e, e); 
    215                                 g && $.event.trigger("ajaxError", [xhr, s, e]); 
    216                                 s.complete && s.complete.call(s.context, xhr, e); 
    217                         } 
    218                 }; 
     205    // options.iframe allows user to force iframe mode 
     206    // 06-NOV-09: now defaulting to iframe mode if file input is detected 
     207    if (options.iframe !== false && (options.iframe || shouldUseFrame)) { 
     208        // hack to fix Safari hang (thanks to Tim Molendijk for this) 
     209        // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d 
     210        if (options.closeKeepAlive) { 
     211            $.get(options.closeKeepAlive, function() { 
     212                jqxhr = fileUploadIframe(a); 
     213            }); 
     214        } 
     215        else { 
     216            jqxhr = fileUploadIframe(a); 
     217        } 
     218    } 
     219    else if ((hasFileInputs || multipart) && fileAPI) { 
     220        jqxhr = fileUploadXhr(a); 
     221    } 
     222    else { 
     223        jqxhr = $.ajax(options); 
     224    } 
    219225 
    220                 var g = s.global; 
    221                 // trigger ajax global events so that activity/block indicators work like normal 
    222                 if (g && ! $.active++) { 
    223                         $.event.trigger("ajaxStart"); 
    224                 } 
    225                 if (g) { 
    226                         $.event.trigger("ajaxSend", [xhr, s]); 
    227                 } 
     226    $form.removeData('jqxhr').data('jqxhr', jqxhr); 
    228227 
    229                 if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) { 
    230                         if (s.global) { 
    231                                 $.active--; 
    232                         } 
    233                         return; 
    234                 } 
    235                 if (xhr.aborted) { 
    236                         return; 
    237                 } 
     228    // clear element array 
     229    for (var k=0; k < elements.length; k++) 
     230        elements[k] = null; 
    238231 
    239                 var timedOut = 0, timeoutHandle; 
     232    // fire 'notify' event 
     233    this.trigger('form-submit-notify', [this, options]); 
     234    return this; 
    240235 
    241                 // add submitting element to data if we know it 
    242                 var sub = form.clk; 
    243                 if (sub) { 
    244                         var n = sub.name; 
    245                         if (n && !sub.disabled) { 
    246                                 s.extraData = s.extraData || {}; 
    247                                 s.extraData[n] = sub.value; 
    248                                 if (sub.type == "image") { 
    249                                         s.extraData[n+'.x'] = form.clk_x; 
    250                                         s.extraData[n+'.y'] = form.clk_y; 
    251                                 } 
    252                         } 
    253                 } 
     236    // utility fn for deep serialization 
     237    function deepSerialize(extraData){ 
     238        var serialized = $.param(extraData).split('&'); 
     239        var len = serialized.length; 
     240        var result = []; 
     241        var i, part; 
     242        for (i=0; i < len; i++) { 
     243            // #252; undo param space replacement 
     244            serialized[i] = serialized[i].replace(/\+/g,' '); 
     245            part = serialized[i].split('='); 
     246            // #278; use array instead of object storage, favoring array serializations 
     247            result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]); 
     248        } 
     249        return result; 
     250    } 
    254251 
    255                 // take a breath so that pending repaints get some cpu time before the upload starts 
    256                 function doSubmit() { 
    257                         // make sure form attrs are set 
    258                         var t = $form.attr('target'), a = $form.attr('action'); 
     252     // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz) 
     253    function fileUploadXhr(a) { 
     254        var formdata = new FormData(); 
    259255 
    260                         // update form attrs in IE friendly way 
    261                         form.setAttribute('target',id); 
    262                         if (form.getAttribute('method') != 'POST') { 
    263                                 form.setAttribute('method', 'POST'); 
    264                         } 
    265                         if (form.getAttribute('action') != s.url) { 
    266                                 form.setAttribute('action', s.url); 
    267                         } 
     256        for (var i=0; i < a.length; i++) { 
     257            formdata.append(a[i].name, a[i].value); 
     258        } 
    268259 
    269                         // ie borks in some cases when setting encoding 
    270                         if (! s.skipEncodingOverride) { 
    271                                 $form.attr({ 
    272                                         encoding: 'multipart/form-data', 
    273                                         enctype:  'multipart/form-data' 
    274                                 }); 
    275                         } 
     260        if (options.extraData) { 
     261            var serializedData = deepSerialize(options.extraData); 
     262            for (i=0; i < serializedData.length; i++) 
     263                if (serializedData[i]) 
     264                    formdata.append(serializedData[i][0], serializedData[i][1]); 
     265        } 
    276266 
    277                         // support timout 
    278                         if (s.timeout) { 
    279                                 timeoutHandle = setTimeout(function() { timedOut = true; cb(true); }, s.timeout); 
    280                         } 
     267        options.data = null; 
    281268 
    282                         // add "extra" data to form if provided in options 
    283                         var extraInputs = []; 
    284                         try { 
    285                                 if (s.extraData) { 
    286                                         for (var n in s.extraData) { 
    287                                                 extraInputs.push( 
    288                                                         $('<input type="hidden" name="'+n+'" value="'+s.extraData[n]+'" />') 
    289                                                                 .appendTo(form)[0]); 
    290                                         } 
    291                                 } 
     269        var s = $.extend(true, {}, $.ajaxSettings, options, { 
     270            contentType: false, 
     271            processData: false, 
     272            cache: false, 
     273            type: method || 'POST' 
     274        }); 
    292275 
    293                                 // add iframe to doc and submit the form 
    294                                 $io.appendTo('body'); 
    295                 io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false); 
    296                                 form.submit(); 
    297                         } 
    298                         finally { 
    299                                 // reset attrs and remove "extra" input elements 
    300                                 form.setAttribute('action',a); 
    301                                 if(t) { 
    302                                         form.setAttribute('target', t); 
    303                                 } else { 
    304                                         $form.removeAttr('target'); 
    305                                 } 
    306                                 $(extraInputs).remove(); 
    307                         } 
    308                 } 
     276        if (options.uploadProgress) { 
     277            // workaround because jqXHR does not expose upload property 
     278            s.xhr = function() { 
     279                var xhr = jQuery.ajaxSettings.xhr(); 
     280                if (xhr.upload) { 
     281                    xhr.upload.addEventListener('progress', function(event) { 
     282                        var percent = 0; 
     283                        var position = event.loaded || event.position; /*event.position is deprecated*/ 
     284                        var total = event.total; 
     285                        if (event.lengthComputable) { 
     286                            percent = Math.ceil(position / total * 100); 
     287                        } 
     288                        options.uploadProgress(event, position, total, percent); 
     289                    }, false); 
     290                } 
     291                return xhr; 
     292            }; 
     293        } 
    309294 
    310                 if (s.forceSync) { 
    311                         doSubmit(); 
    312                 } 
    313                 else { 
    314                         setTimeout(doSubmit, 10); // this lets dom updates render 
    315                 } 
     295        s.data = null; 
     296            var beforeSend = s.beforeSend; 
     297            s.beforeSend = function(xhr, o) { 
     298                o.data = formdata; 
     299                if(beforeSend) 
     300                    beforeSend.call(this, xhr, o); 
     301        }; 
     302        return $.ajax(s); 
     303    } 
    316304 
    317                 var data, doc, domCheckCount = 50, callbackProcessed; 
     305    // private function for handling file uploads (hat tip to YAHOO!) 
     306    function fileUploadIframe(a) { 
     307        var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle; 
     308        var deferred = $.Deferred(); 
    318309 
    319                 function cb(e) { 
    320                         if (xhr.aborted || callbackProcessed) { 
    321                                 return; 
    322                         } 
    323                         if (e === true && xhr) { 
    324                                 xhr.abort('timeout'); 
    325                                 return; 
    326                         } 
     310        if (a) { 
     311            // ensure that every serialized input is still enabled 
     312            for (i=0; i < elements.length; i++) { 
     313                el = $(elements[i]); 
     314                if ( hasProp ) 
     315                    el.prop('disabled', false); 
     316                else 
     317                    el.removeAttr('disabled'); 
     318            } 
     319        } 
    327320 
    328                         var doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document; 
    329                         if (!doc || doc.location.href == s.iframeSrc) { 
    330                                 // response not received yet 
    331                                 if (!timedOut) 
    332                                         return; 
    333                         } 
    334             io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false); 
     321        s = $.extend(true, {}, $.ajaxSettings, options); 
     322        s.context = s.context || s; 
     323        id = 'jqFormIO' + (new Date().getTime()); 
     324        if (s.iframeTarget) { 
     325            $io = $(s.iframeTarget); 
     326            n = $io.attr2('name'); 
     327            if (!n) 
     328                 $io.attr2('name', id); 
     329            else 
     330                id = n; 
     331        } 
     332        else { 
     333            $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />'); 
     334            $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' }); 
     335        } 
     336        io = $io[0]; 
    335337 
    336                         var ok = true; 
    337                         try { 
    338                                 if (timedOut) { 
    339                                         throw 'timeout'; 
    340                                 } 
    341338 
    342                                 var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc); 
    343                                 log('isXml='+isXml); 
    344                                 if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) { 
    345                                         if (--domCheckCount) { 
    346                                                 // in some browsers (Opera) the iframe DOM is not always traversable when 
    347                                                 // the onload callback fires, so we loop a bit to accommodate 
    348                                                 log('requeing onLoad callback, DOM not available'); 
    349                                                 setTimeout(cb, 250); 
    350                                                 return; 
    351                                         } 
    352                                         // let this fall through because server response could be an empty document 
    353                                         //log('Could not access iframe DOM after mutiple tries.'); 
    354                                         //throw 'DOMException: not available'; 
    355                                 } 
     339        xhr = { // mock object 
     340            aborted: 0, 
     341            responseText: null, 
     342            responseXML: null, 
     343            status: 0, 
     344            statusText: 'n/a', 
     345            getAllResponseHeaders: function() {}, 
     346            getResponseHeader: function() {}, 
     347            setRequestHeader: function() {}, 
     348            abort: function(status) { 
     349                var e = (status === 'timeout' ? 'timeout' : 'aborted'); 
     350                log('aborting upload... ' + e); 
     351                this.aborted = 1; 
    356352 
    357                                 //log('response detected'); 
    358                                 xhr.responseText = doc.body ? doc.body.innerHTML : doc.documentElement ? doc.documentElement.innerHTML : null; 
    359                                 xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc; 
    360                                 if (isXml) 
    361                                         s.dataType = 'xml'; 
    362                                 xhr.getResponseHeader = function(header){ 
    363                                         var headers = {'content-type': s.dataType}; 
    364                                         return headers[header]; 
    365                                 }; 
     353                try { // #214, #257 
     354                    if (io.contentWindow.document.execCommand) { 
     355                        io.contentWindow.document.execCommand('Stop'); 
     356                    } 
     357                } 
     358                catch(ignore) {} 
    366359 
    367                                 var scr = /(json|script|text)/.test(s.dataType); 
    368                                 if (scr || s.textarea) { 
    369                                         // see if user embedded response in textarea 
    370                                         var ta = doc.getElementsByTagName('textarea')[0]; 
    371                                         if (ta) { 
    372                                                 xhr.responseText = ta.value; 
    373                                         } 
    374                                         else if (scr) { 
    375                                                 // account for browsers injecting pre around json response 
    376                                                 var pre = doc.getElementsByTagName('pre')[0]; 
    377                                                 var b = doc.getElementsByTagName('body')[0]; 
    378                                                 if (pre) { 
    379                                                         xhr.responseText = pre.textContent; 
    380                                                 } 
    381                                                 else if (b) { 
    382                                                         xhr.responseText = b.innerHTML; 
    383                                                 } 
    384                                         } 
    385                                 } 
    386                                 else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) { 
    387                                         xhr.responseXML = toXml(xhr.responseText); 
    388                                 } 
     360                $io.attr('src', s.iframeSrc); // abort op in progress 
     361                xhr.error = e; 
     362                if (s.error) 
     363                    s.error.call(s.context, xhr, e, status); 
     364                if (g) 
     365                    $.event.trigger("ajaxError", [xhr, s, e]); 
     366                if (s.complete) 
     367                    s.complete.call(s.context, xhr, e); 
     368            } 
     369        }; 
    389370 
    390                                 data = httpData(xhr, s.dataType, s); 
    391                         } 
    392                         catch(e){ 
    393                                 log('error caught:',e); 
    394                                 ok = false; 
    395                                 xhr.error = e; 
    396                                 s.error && s.error.call(s.context, xhr, 'error', e); 
    397                                 g && $.event.trigger("ajaxError", [xhr, s, e]); 
    398                         } 
     371        g = s.global; 
     372        // trigger ajax global events so that activity/block indicators work like normal 
     373        if (g && 0 === $.active++) { 
     374            $.event.trigger("ajaxStart"); 
     375        } 
     376        if (g) { 
     377            $.event.trigger("ajaxSend", [xhr, s]); 
     378        } 
    399379 
    400                         if (xhr.aborted) { 
    401                                 log('upload aborted'); 
    402                                 ok = false; 
    403                         } 
     380        if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) { 
     381            if (s.global) { 
     382                $.active--; 
     383            } 
     384            deferred.reject(); 
     385            return deferred; 
     386        } 
     387        if (xhr.aborted) { 
     388            deferred.reject(); 
     389            return deferred; 
     390        } 
    404391 
    405                         // ordering of these callbacks/triggers is odd, but that's how $.ajax does it 
    406                         if (ok) { 
    407                                 s.success && s.success.call(s.context, data, 'success', xhr); 
    408                                 g && $.event.trigger("ajaxSuccess", [xhr, s]); 
    409                         } 
     392        // add submitting element to data if we know it 
     393        sub = form.clk; 
     394        if (sub) { 
     395            n = sub.name; 
     396            if (n && !sub.disabled) { 
     397                s.extraData = s.extraData || {}; 
     398                s.extraData[n] = sub.value; 
     399                if (sub.type == "image") { 
     400                    s.extraData[n+'.x'] = form.clk_x; 
     401                    s.extraData[n+'.y'] = form.clk_y; 
     402                } 
     403            } 
     404        } 
    410405 
    411                         g && $.event.trigger("ajaxComplete", [xhr, s]); 
     406        var CLIENT_TIMEOUT_ABORT = 1; 
     407        var SERVER_ABORT = 2; 
    412408 
    413                         if (g && ! --$.active) { 
    414                                 $.event.trigger("ajaxStop"); 
    415                         } 
     409        function getDoc(frame) { 
     410            /* it looks like contentWindow or contentDocument do not 
     411             * carry the protocol property in ie8, when running under ssl 
     412             * frame.document is the only valid response document, since 
     413             * the protocol is know but not on the other two objects. strange? 
     414             * "Same origin policy" http://en.wikipedia.org/wiki/Same_origin_policy 
     415             */ 
    416416 
    417                         s.complete && s.complete.call(s.context, xhr, ok ? 'success' : 'error'); 
     417            var doc = null; 
    418418 
    419                         callbackProcessed = true; 
    420                         if (s.timeout) 
    421                                 clearTimeout(timeoutHandle); 
     419            // IE8 cascading access check 
     420            try { 
     421                if (frame.contentWindow) { 
     422                    doc = frame.contentWindow.document; 
     423                } 
     424            } catch(err) { 
     425                // IE8 access denied under ssl & missing protocol 
     426                log('cannot get iframe.contentWindow document: ' + err); 
     427            } 
    422428 
    423                         // clean up 
    424                         setTimeout(function() { 
    425                                 $io.removeData('form-plugin-onload'); 
    426                                 $io.remove(); 
    427                                 xhr.responseXML = null; 
    428                         }, 100); 
    429                 } 
     429            if (doc) { // successful getting content 
     430                return doc; 
     431            } 
    430432 
    431                 var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+) 
    432                         if (window.ActiveXObject) { 
    433                                 doc = new ActiveXObject('Microsoft.XMLDOM'); 
    434                                 doc.async = 'false'; 
    435                                 doc.loadXML(s); 
    436                         } 
    437                         else { 
    438                                 doc = (new DOMParser()).parseFromString(s, 'text/xml'); 
    439                         } 
    440                         return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null; 
    441                 }; 
    442                 var parseJSON = $.parseJSON || function(s) { 
    443                         return window['eval']('(' + s + ')'); 
    444                 }; 
     433            try { // simply checking may throw in ie8 under ssl or mismatched protocol 
     434                doc = frame.contentDocument ? frame.contentDocument : frame.document; 
     435            } catch(err) { 
     436                // last attempt 
     437                log('cannot get iframe.contentDocument: ' + err); 
     438                doc = frame.document; 
     439            } 
     440            return doc; 
     441        } 
    445442 
    446                 var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4 
    447                         var ct = xhr.getResponseHeader('content-type') || '', 
    448                                 xml = type === 'xml' || !type && ct.indexOf('xml') >= 0, 
    449                                 data = xml ? xhr.responseXML : xhr.responseText; 
     443        // Rails CSRF hack (thanks to Yvan Barthelemy) 
     444        var csrf_token = $('meta[name=csrf-token]').attr('content'); 
     445        var csrf_param = $('meta[name=csrf-param]').attr('content'); 
     446        if (csrf_param && csrf_token) { 
     447            s.extraData = s.extraData || {}; 
     448            s.extraData[csrf_param] = csrf_token; 
     449        } 
    450450 
    451                         if (xml && data.documentElement.nodeName === 'parsererror') { 
    452                                 $.error && $.error('parsererror'); 
    453                         } 
    454                         if (s && s.dataFilter) { 
    455                                 data = s.dataFilter(data, type); 
    456                         } 
    457                         if (typeof data === 'string') { 
    458                                 if (type === 'json' || !type && ct.indexOf('json') >= 0) { 
    459                                         data = parseJSON(data); 
    460                                 } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) { 
    461                                         $.globalEval(data); 
    462                                 } 
    463                         } 
    464                         return data; 
    465                 }; 
    466         } 
     451        // take a breath so that pending repaints get some cpu time before the upload starts 
     452        function doSubmit() { 
     453            // make sure form attrs are set 
     454            var t = $form.attr2('target'), a = $form.attr2('action'); 
     455 
     456            // update form attrs in IE friendly way 
     457            form.setAttribute('target',id); 
     458            if (!method) { 
     459                form.setAttribute('method', 'POST'); 
     460            } 
     461            if (a != s.url) { 
     462                form.setAttribute('action', s.url); 
     463            } 
     464 
     465            // ie borks in some cases when setting encoding 
     466            if (! s.skipEncodingOverride && (!method || /post/i.test(method))) { 
     467                $form.attr({ 
     468                    encoding: 'multipart/form-data', 
     469                    enctype:  'multipart/form-data' 
     470                }); 
     471            } 
     472 
     473            // support timout 
     474            if (s.timeout) { 
     475                timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout); 
     476            } 
     477 
     478            // look for server aborts 
     479            function checkState() { 
     480                try { 
     481                    var state = getDoc(io).readyState; 
     482                    log('state = ' + state); 
     483                    if (state && state.toLowerCase() == 'uninitialized') 
     484                        setTimeout(checkState,50); 
     485                } 
     486                catch(e) { 
     487                    log('Server abort: ' , e, ' (', e.name, ')'); 
     488                    cb(SERVER_ABORT); 
     489                    if (timeoutHandle) 
     490                        clearTimeout(timeoutHandle); 
     491                    timeoutHandle = undefined; 
     492                } 
     493            } 
     494 
     495            // add "extra" data to form if provided in options 
     496            var extraInputs = []; 
     497            try { 
     498                if (s.extraData) { 
     499                    for (var n in s.extraData) { 
     500                        if (s.extraData.hasOwnProperty(n)) { 
     501                           // if using the $.param format that allows for multiple values with the same name 
     502                           if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) { 
     503                               extraInputs.push( 
     504                               $('<input type="hidden" name="'+s.extraData[n].name+'">').val(s.extraData[n].value) 
     505                                   .appendTo(form)[0]); 
     506                           } else { 
     507                               extraInputs.push( 
     508                               $('<input type="hidden" name="'+n+'">').val(s.extraData[n]) 
     509                                   .appendTo(form)[0]); 
     510                           } 
     511                        } 
     512                    } 
     513                } 
     514 
     515                if (!s.iframeTarget) { 
     516                    // add iframe to doc and submit the form 
     517                    $io.appendTo('body'); 
     518                    if (io.attachEvent) 
     519                        io.attachEvent('onload', cb); 
     520                    else 
     521                        io.addEventListener('load', cb, false); 
     522                } 
     523                setTimeout(checkState,15); 
     524 
     525                try { 
     526                    form.submit(); 
     527                } catch(err) { 
     528                    // just in case form has element with name/id of 'submit' 
     529                    var submitFn = document.createElement('form').submit; 
     530                    submitFn.apply(form); 
     531                } 
     532            } 
     533            finally { 
     534                // reset attrs and remove "extra" input elements 
     535                form.setAttribute('action',a); 
     536                if(t) { 
     537                    form.setAttribute('target', t); 
     538                } else { 
     539                    $form.removeAttr('target'); 
     540                } 
     541                $(extraInputs).remove(); 
     542            } 
     543        } 
     544 
     545        if (s.forceSync) { 
     546            doSubmit(); 
     547        } 
     548        else { 
     549            setTimeout(doSubmit, 10); // this lets dom updates render 
     550        } 
     551 
     552        var data, doc, domCheckCount = 50, callbackProcessed; 
     553 
     554        function cb(e) { 
     555            if (xhr.aborted || callbackProcessed) { 
     556                return; 
     557            } 
     558 
     559            doc = getDoc(io); 
     560            if(!doc) { 
     561                log('cannot access response document'); 
     562                e = SERVER_ABORT; 
     563            } 
     564            if (e === CLIENT_TIMEOUT_ABORT && xhr) { 
     565                xhr.abort('timeout'); 
     566                deferred.reject(xhr, 'timeout'); 
     567                return; 
     568            } 
     569            else if (e == SERVER_ABORT && xhr) { 
     570                xhr.abort('server abort'); 
     571                deferred.reject(xhr, 'error', 'server abort'); 
     572                return; 
     573            } 
     574 
     575            if (!doc || doc.location.href == s.iframeSrc) { 
     576                // response not received yet 
     577                if (!timedOut) 
     578                    return; 
     579            } 
     580            if (io.detachEvent) 
     581                io.detachEvent('onload', cb); 
     582            else 
     583                io.removeEventListener('load', cb, false); 
     584 
     585            var status = 'success', errMsg; 
     586            try { 
     587                if (timedOut) { 
     588                    throw 'timeout'; 
     589                } 
     590 
     591                var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc); 
     592                log('isXml='+isXml); 
     593                if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) { 
     594                    if (--domCheckCount) { 
     595                        // in some browsers (Opera) the iframe DOM is not always traversable when 
     596                        // the onload callback fires, so we loop a bit to accommodate 
     597                        log('requeing onLoad callback, DOM not available'); 
     598                        setTimeout(cb, 250); 
     599                        return; 
     600                    } 
     601                    // let this fall through because server response could be an empty document 
     602                    //log('Could not access iframe DOM after mutiple tries.'); 
     603                    //throw 'DOMException: not available'; 
     604                } 
     605 
     606                //log('response detected'); 
     607                var docRoot = doc.body ? doc.body : doc.documentElement; 
     608                xhr.responseText = docRoot ? docRoot.innerHTML : null; 
     609                xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc; 
     610                if (isXml) 
     611                    s.dataType = 'xml'; 
     612                xhr.getResponseHeader = function(header){ 
     613                    var headers = {'content-type': s.dataType}; 
     614                    return headers[header]; 
     615                }; 
     616                // support for XHR 'status' & 'statusText' emulation : 
     617                if (docRoot) { 
     618                    xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status; 
     619                    xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText; 
     620                } 
     621 
     622                var dt = (s.dataType || '').toLowerCase(); 
     623                var scr = /(json|script|text)/.test(dt); 
     624                if (scr || s.textarea) { 
     625                    // see if user embedded response in textarea 
     626                    var ta = doc.getElementsByTagName('textarea')[0]; 
     627                    if (ta) { 
     628                        xhr.responseText = ta.value; 
     629                        // support for XHR 'status' & 'statusText' emulation : 
     630                        xhr.status = Number( ta.getAttribute('status') ) || xhr.status; 
     631                        xhr.statusText = ta.getAttribute('statusText') || xhr.statusText; 
     632                    } 
     633                    else if (scr) { 
     634                        // account for browsers injecting pre around json response 
     635                        var pre = doc.getElementsByTagName('pre')[0]; 
     636                        var b = doc.getElementsByTagName('body')[0]; 
     637                        if (pre) { 
     638                            xhr.responseText = pre.textContent ? pre.textContent : pre.innerText; 
     639                        } 
     640                        else if (b) { 
     641                            xhr.responseText = b.textContent ? b.textContent : b.innerText; 
     642                        } 
     643                    } 
     644                } 
     645                else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) { 
     646                    xhr.responseXML = toXml(xhr.responseText); 
     647                } 
     648 
     649                try { 
     650                    data = httpData(xhr, dt, s); 
     651                } 
     652                catch (err) { 
     653                    status = 'parsererror'; 
     654                    xhr.error = errMsg = (err || status); 
     655                } 
     656            } 
     657            catch (err) { 
     658                log('error caught: ',err); 
     659                status = 'error'; 
     660                xhr.error = errMsg = (err || status); 
     661            } 
     662 
     663            if (xhr.aborted) { 
     664                log('upload aborted'); 
     665                status = null; 
     666            } 
     667 
     668            if (xhr.status) { // we've set xhr.status 
     669                status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error'; 
     670            } 
     671 
     672            // ordering of these callbacks/triggers is odd, but that's how $.ajax does it 
     673            if (status === 'success') { 
     674                if (s.success) 
     675                    s.success.call(s.context, data, 'success', xhr); 
     676                deferred.resolve(xhr.responseText, 'success', xhr); 
     677                if (g) 
     678                    $.event.trigger("ajaxSuccess", [xhr, s]); 
     679            } 
     680            else if (status) { 
     681                if (errMsg === undefined) 
     682                    errMsg = xhr.statusText; 
     683                if (s.error) 
     684                    s.error.call(s.context, xhr, status, errMsg); 
     685                deferred.reject(xhr, 'error', errMsg); 
     686                if (g) 
     687                    $.event.trigger("ajaxError", [xhr, s, errMsg]); 
     688            } 
     689 
     690            if (g) 
     691                $.event.trigger("ajaxComplete", [xhr, s]); 
     692 
     693            if (g && ! --$.active) { 
     694                $.event.trigger("ajaxStop"); 
     695            } 
     696 
     697            if (s.complete) 
     698                s.complete.call(s.context, xhr, status); 
     699 
     700            callbackProcessed = true; 
     701            if (s.timeout) 
     702                clearTimeout(timeoutHandle); 
     703 
     704            // clean up 
     705            setTimeout(function() { 
     706                if (!s.iframeTarget) 
     707                    $io.remove(); 
     708                xhr.responseXML = null; 
     709            }, 100); 
     710        } 
     711 
     712        var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+) 
     713            if (window.ActiveXObject) { 
     714                doc = new ActiveXObject('Microsoft.XMLDOM'); 
     715                doc.async = 'false'; 
     716                doc.loadXML(s); 
     717            } 
     718            else { 
     719                doc = (new DOMParser()).parseFromString(s, 'text/xml'); 
     720            } 
     721            return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null; 
     722        }; 
     723        var parseJSON = $.parseJSON || function(s) { 
     724            /*jslint evil:true */ 
     725            return window['eval']('(' + s + ')'); 
     726        }; 
     727 
     728        var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4 
     729 
     730            var ct = xhr.getResponseHeader('content-type') || '', 
     731                xml = type === 'xml' || !type && ct.indexOf('xml') >= 0, 
     732                data = xml ? xhr.responseXML : xhr.responseText; 
     733 
     734            if (xml && data.documentElement.nodeName === 'parsererror') { 
     735                if ($.error) 
     736                    $.error('parsererror'); 
     737            } 
     738            if (s && s.dataFilter) { 
     739                data = s.dataFilter(data, type); 
     740            } 
     741            if (typeof data === 'string') { 
     742                if (type === 'json' || !type && ct.indexOf('json') >= 0) { 
     743                    data = parseJSON(data); 
     744                } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) { 
     745                    $.globalEval(data); 
     746                } 
     747            } 
     748            return data; 
     749        }; 
     750 
     751        return deferred; 
     752    } 
    467753}; 
    468754 
    469755/** 
     
    472758 * The advantages of using this method instead of ajaxSubmit() are: 
    473759 * 
    474760 * 1: This method will include coordinates for <input type="image" /> elements (if the element 
    475  *      is used to submit the form). 
     761 *    is used to submit the form). 
    476762 * 2. This method will include the submit element's name/value data (for the element that was 
    477  *      used to submit the form). 
     763 *    used to submit the form). 
    478764 * 3. This method binds the submit() method to the form for you. 
    479765 * 
    480766 * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely 
     
    482768 * the form itself. 
    483769 */ 
    484770$.fn.ajaxForm = function(options) { 
    485         // in jQuery 1.3+ we can fix mistakes with the ready state 
    486         if (this.length === 0) { 
    487                 var o = { s: this.selector, c: this.context }; 
    488                 if (!$.isReady && o.s) { 
    489                         log('DOM not ready, queuing ajaxForm'); 
    490                         $(function() { 
    491                                 $(o.s,o.c).ajaxForm(options); 
    492                         }); 
    493                         return this; 
    494                 } 
    495                 // is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready() 
    496                 log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)')); 
    497                 return this; 
    498         } 
     771    options = options || {}; 
     772    options.delegation = options.delegation && $.isFunction($.fn.on); 
    499773 
    500         return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) { 
    501                 if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed 
    502                         e.preventDefault(); 
    503                         $(this).ajaxSubmit(options); 
    504                 } 
    505         }).bind('click.form-plugin', function(e) { 
    506                 var target = e.target; 
    507                 var $el = $(target); 
    508                 if (!($el.is(":submit,input:image"))) { 
    509                         // is this a child element of the submit el?  (ex: a span within a button) 
    510                         var t = $el.closest(':submit'); 
    511                         if (t.length == 0) { 
    512                                 return; 
    513                         } 
    514                         target = t[0]; 
    515                 } 
    516                 var form = this; 
    517                 form.clk = target; 
    518                 if (target.type == 'image') { 
    519                         if (e.offsetX != undefined) { 
    520                                 form.clk_x = e.offsetX; 
    521                                 form.clk_y = e.offsetY; 
    522                         } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin 
    523                                 var offset = $el.offset(); 
    524                                 form.clk_x = e.pageX - offset.left; 
    525                                 form.clk_y = e.pageY - offset.top; 
    526                         } else { 
    527                                 form.clk_x = e.pageX - target.offsetLeft; 
    528                                 form.clk_y = e.pageY - target.offsetTop; 
    529                         } 
    530                 } 
    531                 // clear form vars 
    532                 setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100); 
    533         }); 
     774    // in jQuery 1.3+ we can fix mistakes with the ready state 
     775    if (!options.delegation && this.length === 0) { 
     776        var o = { s: this.selector, c: this.context }; 
     777        if (!$.isReady && o.s) { 
     778            log('DOM not ready, queuing ajaxForm'); 
     779            $(function() { 
     780                $(o.s,o.c).ajaxForm(options); 
     781            }); 
     782            return this; 
     783        } 
     784        // is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready() 
     785        log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)')); 
     786        return this; 
     787    } 
     788 
     789    if ( options.delegation ) { 
     790        $(document) 
     791            .off('submit.form-plugin', this.selector, doAjaxSubmit) 
     792            .off('click.form-plugin', this.selector, captureSubmittingElement) 
     793            .on('submit.form-plugin', this.selector, options, doAjaxSubmit) 
     794            .on('click.form-plugin', this.selector, options, captureSubmittingElement); 
     795        return this; 
     796    } 
     797 
     798    return this.ajaxFormUnbind() 
     799        .bind('submit.form-plugin', options, doAjaxSubmit) 
     800        .bind('click.form-plugin', options, captureSubmittingElement); 
    534801}; 
    535802 
     803// private event handlers 
     804function doAjaxSubmit(e) { 
     805    /*jshint validthis:true */ 
     806    var options = e.data; 
     807    if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed 
     808        e.preventDefault(); 
     809        $(this).ajaxSubmit(options); 
     810    } 
     811} 
     812 
     813function captureSubmittingElement(e) { 
     814    /*jshint validthis:true */ 
     815    var target = e.target; 
     816    var $el = $(target); 
     817    if (!($el.is("[type=submit],[type=image]"))) { 
     818        // is this a child element of the submit el?  (ex: a span within a button) 
     819        var t = $el.closest('[type=submit]'); 
     820        if (t.length === 0) { 
     821            return; 
     822        } 
     823        target = t[0]; 
     824    } 
     825    var form = this; 
     826    form.clk = target; 
     827    if (target.type == 'image') { 
     828        if (e.offsetX !== undefined) { 
     829            form.clk_x = e.offsetX; 
     830            form.clk_y = e.offsetY; 
     831        } else if (typeof $.fn.offset == 'function') { 
     832            var offset = $el.offset(); 
     833            form.clk_x = e.pageX - offset.left; 
     834            form.clk_y = e.pageY - offset.top; 
     835        } else { 
     836            form.clk_x = e.pageX - target.offsetLeft; 
     837            form.clk_y = e.pageY - target.offsetTop; 
     838        } 
     839    } 
     840    // clear form vars 
     841    setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100); 
     842} 
     843 
     844 
    536845// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm 
    537846$.fn.ajaxFormUnbind = function() { 
    538         return this.unbind('submit.form-plugin click.form-plugin'); 
     847    return this.unbind('submit.form-plugin click.form-plugin'); 
    539848}; 
    540849 
    541850/** 
     
    549858 * It is this array that is passed to pre-submit callback functions provided to the 
    550859 * ajaxSubmit() and ajaxForm() methods. 
    551860 */ 
    552 $.fn.formToArray = function(semantic) { 
    553         var a = []; 
    554         if (this.length === 0) { 
    555                 return a; 
    556         } 
     861$.fn.formToArray = function(semantic, elements) { 
     862    var a = []; 
     863    if (this.length === 0) { 
     864        return a; 
     865    } 
    557866 
    558         var form = this[0]; 
    559         var els = semantic ? form.getElementsByTagName('*') : form.elements; 
    560         if (!els) { 
    561                 return a; 
    562         } 
     867    var form = this[0]; 
     868    var els = semantic ? form.getElementsByTagName('*') : form.elements; 
     869    if (!els) { 
     870        return a; 
     871    } 
    563872 
    564         var i,j,n,v,el,max,jmax; 
    565         for(i=0, max=els.length; i < max; i++) { 
    566                 el = els[i]; 
    567                 n = el.name; 
    568                 if (!n) { 
    569                         continue; 
    570                 } 
     873    var i,j,n,v,el,max,jmax; 
     874    for(i=0, max=els.length; i < max; i++) { 
     875        el = els[i]; 
     876        n = el.name; 
     877        if (!n || el.disabled) { 
     878            continue; 
     879        } 
    571880 
    572                 if (semantic && form.clk && el.type == "image") { 
    573                         // handle image inputs on the fly when semantic == true 
    574                         if(!el.disabled && form.clk == el) { 
    575                                 a.push({name: n, value: $(el).val()}); 
    576                                 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 
    577                         } 
    578                         continue; 
    579                 } 
     881        if (semantic && form.clk && el.type == "image") { 
     882            // handle image inputs on the fly when semantic == true 
     883            if(form.clk == el) { 
     884                a.push({name: n, value: $(el).val(), type: el.type }); 
     885                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 
     886            } 
     887            continue; 
     888        } 
    580889 
    581                 v = $.fieldValue(el, true); 
    582                 if (v && v.constructor == Array) { 
    583                         for(j=0, jmax=v.length; j < jmax; j++) { 
    584                                 a.push({name: n, value: v[j]}); 
    585                         } 
    586                 } 
    587                 else if (v !== null && typeof v != 'undefined') { 
    588                         a.push({name: n, value: v}); 
    589                 } 
    590         } 
     890        v = $.fieldValue(el, true); 
     891        if (v && v.constructor == Array) { 
     892            if (elements) 
     893                elements.push(el); 
     894            for(j=0, jmax=v.length; j < jmax; j++) { 
     895                a.push({name: n, value: v[j]}); 
     896            } 
     897        } 
     898        else if (feature.fileapi && el.type == 'file') { 
     899            if (elements) 
     900                elements.push(el); 
     901            var files = el.files; 
     902            if (files.length) { 
     903                for (j=0; j < files.length; j++) { 
     904                    a.push({name: n, value: files[j], type: el.type}); 
     905                } 
     906            } 
     907            else { 
     908                // #180 
     909                a.push({ name: n, value: '', type: el.type }); 
     910            } 
     911        } 
     912        else if (v !== null && typeof v != 'undefined') { 
     913            if (elements) 
     914                elements.push(el); 
     915            a.push({name: n, value: v, type: el.type, required: el.required}); 
     916        } 
     917    } 
    591918 
    592         if (!semantic && form.clk) { 
    593                 // input type=='image' are not found in elements array! handle it here 
    594                 var $input = $(form.clk), input = $input[0]; 
    595                 n = input.name; 
    596                 if (n && !input.disabled && input.type == 'image') { 
    597                         a.push({name: n, value: $input.val()}); 
    598                         a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 
    599                 } 
    600         } 
    601         return a; 
     919    if (!semantic && form.clk) { 
     920        // input type=='image' are not found in elements array! handle it here 
     921        var $input = $(form.clk), input = $input[0]; 
     922        n = input.name; 
     923        if (n && !input.disabled && input.type == 'image') { 
     924            a.push({name: n, value: $input.val()}); 
     925            a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y}); 
     926        } 
     927    } 
     928    return a; 
    602929}; 
    603930 
    604931/** 
     
    606933 * in the format: name1=value1&amp;name2=value2 
    607934 */ 
    608935$.fn.formSerialize = function(semantic) { 
    609         //hand off to jQuery.param for proper encoding 
    610         return $.param(this.formToArray(semantic)); 
     936    //hand off to jQuery.param for proper encoding 
     937    return $.param(this.formToArray(semantic)); 
    611938}; 
    612939 
    613940/** 
     
    615942 * This method will return a string in the format: name1=value1&amp;name2=value2 
    616943 */ 
    617944$.fn.fieldSerialize = function(successful) { 
    618         var a = []; 
    619         this.each(function() { 
    620                 var n = this.name; 
    621                 if (!n) { 
    622                         return; 
    623                 } 
    624                 var v = $.fieldValue(this, successful); 
    625                 if (v && v.constructor == Array) { 
    626                         for (var i=0,max=v.length; i < max; i++) { 
    627                                 a.push({name: n, value: v[i]}); 
    628                         } 
    629                 } 
    630                 else if (v !== null && typeof v != 'undefined') { 
    631                         a.push({name: this.name, value: v}); 
    632                 } 
    633         }); 
    634         //hand off to jQuery.param for proper encoding 
    635         return $.param(a); 
     945    var a = []; 
     946    this.each(function() { 
     947        var n = this.name; 
     948        if (!n) { 
     949            return; 
     950        } 
     951        var v = $.fieldValue(this, successful); 
     952        if (v && v.constructor == Array) { 
     953            for (var i=0,max=v.length; i < max; i++) { 
     954                a.push({name: n, value: v[i]}); 
     955            } 
     956        } 
     957        else if (v !== null && typeof v != 'undefined') { 
     958            a.push({name: this.name, value: v}); 
     959        } 
     960    }); 
     961    //hand off to jQuery.param for proper encoding 
     962    return $.param(a); 
    636963}; 
    637964 
    638965/** 
    639966 * Returns the value(s) of the element in the matched set.  For example, consider the following form: 
    640967 * 
    641968 *  <form><fieldset> 
    642  *        <input name="A" type="text" /> 
    643  *        <input name="A" type="text" /> 
    644  *        <input name="B" type="checkbox" value="B1" /> 
    645  *        <input name="B" type="checkbox" value="B2"/> 
    646  *        <input name="C" type="radio" value="C1" /> 
    647  *        <input name="C" type="radio" value="C2" /> 
     969 *      <input name="A" type="text" /> 
     970 *      <input name="A" type="text" /> 
     971 *      <input name="B" type="checkbox" value="B1" /> 
     972 *      <input name="B" type="checkbox" value="B2"/> 
     973 *      <input name="C" type="radio" value="C1" /> 
     974 *      <input name="C" type="radio" value="C2" /> 
    648975 *  </fieldset></form> 
    649976 * 
    650  *  var v = $(':text').fieldValue(); 
     977 *  var v = $('input[type=text]').fieldValue(); 
    651978 *  // if no values are entered into the text inputs 
    652979 *  v == ['',''] 
    653980 *  // if values entered into the text inputs are 'foo' and 'bar' 
    654981 *  v == ['foo','bar'] 
    655982 * 
    656  *  var v = $(':checkbox').fieldValue(); 
     983 *  var v = $('input[type=checkbox]').fieldValue(); 
    657984 *  // if neither checkbox is checked 
    658985 *  v === undefined 
    659986 *  // if both checkboxes are checked 
    660987 *  v == ['B1', 'B2'] 
    661988 * 
    662  *  var v = $(':radio').fieldValue(); 
     989 *  var v = $('input[type=radio]').fieldValue(); 
    663990 *  // if neither radio is checked 
    664991 *  v === undefined 
    665992 *  // if first radio is checked 
     
    671998 * for each element is returned. 
    672999 * 
    6731000 * Note: This method *always* returns an array.  If no valid value can be determined the 
    674  *         array will be empty, otherwise it will contain one or more values. 
     1001 *    array will be empty, otherwise it will contain one or more values. 
    6751002 */ 
    6761003$.fn.fieldValue = function(successful) { 
    677         for (var val=[], i=0, max=this.length; i < max; i++) { 
    678                 var el = this[i]; 
    679                 var v = $.fieldValue(el, successful); 
    680                 if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) { 
    681                         continue; 
    682                 } 
    683                 v.constructor == Array ? $.merge(val, v) : val.push(v); 
    684         } 
    685         return val; 
     1004    for (var val=[], i=0, max=this.length; i < max; i++) { 
     1005        var el = this[i]; 
     1006        var v = $.fieldValue(el, successful); 
     1007        if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) { 
     1008            continue; 
     1009        } 
     1010        if (v.constructor == Array) 
     1011            $.merge(val, v); 
     1012        else 
     1013            val.push(v); 
     1014    } 
     1015    return val; 
    6861016}; 
    6871017 
    6881018/** 
    6891019 * Returns the value of the field element. 
    6901020 */ 
    6911021$.fieldValue = function(el, successful) { 
    692         var n = el.name, t = el.type, tag = el.tagName.toLowerCase(); 
    693         if (successful === undefined) { 
    694                 successful = true; 
    695         } 
     1022    var n = el.name, t = el.type, tag = el.tagName.toLowerCase(); 
     1023    if (successful === undefined) { 
     1024        successful = true; 
     1025    } 
    6961026 
    697         if (successful && (!n || el.disabled || t == 'reset' || t == 'button' || 
    698                 (t == 'checkbox' || t == 'radio') && !el.checked || 
    699                 (t == 'submit' || t == 'image') && el.form && el.form.clk != el || 
    700                 tag == 'select' && el.selectedIndex == -1)) { 
    701                         return null; 
    702         } 
     1027    if (successful && (!n || el.disabled || t == 'reset' || t == 'button' || 
     1028        (t == 'checkbox' || t == 'radio') && !el.checked || 
     1029        (t == 'submit' || t == 'image') && el.form && el.form.clk != el || 
     1030        tag == 'select' && el.selectedIndex == -1)) { 
     1031            return null; 
     1032    } 
    7031033 
    704         if (tag == 'select') { 
    705                 var index = el.selectedIndex; 
    706                 if (index < 0) { 
    707                         return null; 
    708                 } 
    709                 var a = [], ops = el.options; 
    710                 var one = (t == 'select-one'); 
    711                 var max = (one ? index+1 : ops.length); 
    712                 for(var i=(one ? index : 0); i < max; i++) { 
    713                         var op = ops[i]; 
    714                         if (op.selected) { 
    715                                 var v = op.value; 
    716                                 if (!v) { // extra pain for IE... 
    717                                         v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value; 
    718                                 } 
    719                                 if (one) { 
    720                                         return v; 
    721                                 } 
    722                                 a.push(v); 
    723                         } 
    724                 } 
    725                 return a; 
    726         } 
    727         return $(el).val(); 
     1034    if (tag == 'select') { 
     1035        var index = el.selectedIndex; 
     1036        if (index < 0) { 
     1037            return null; 
     1038        } 
     1039        var a = [], ops = el.options; 
     1040        var one = (t == 'select-one'); 
     1041        var max = (one ? index+1 : ops.length); 
     1042        for(var i=(one ? index : 0); i < max; i++) { 
     1043            var op = ops[i]; 
     1044            if (op.selected) { 
     1045                var v = op.value; 
     1046                if (!v) { // extra pain for IE... 
     1047                    v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value; 
     1048                } 
     1049                if (one) { 
     1050                    return v; 
     1051                } 
     1052                a.push(v); 
     1053            } 
     1054        } 
     1055        return a; 
     1056    } 
     1057    return $(el).val(); 
    7281058}; 
    7291059 
    7301060/** 
     
    7351065 *  - inputs of type submit, button, reset, and hidden will *not* be effected 
    7361066 *  - button elements will *not* be effected 
    7371067 */ 
    738 $.fn.clearForm = function() { 
    739         return this.each(function() { 
    740                 $('input,select,textarea', this).clearFields(); 
    741         }); 
     1068$.fn.clearForm = function(includeHidden) { 
     1069    return this.each(function() { 
     1070        $('input,select,textarea', this).clearFields(includeHidden); 
     1071    }); 
    7421072}; 
    7431073 
    7441074/** 
    7451075 * Clears the selected form elements. 
    7461076 */ 
    747 $.fn.clearFields = $.fn.clearInputs = function() { 
    748         return this.each(function() { 
    749                 var t = this.type, tag = this.tagName.toLowerCase(); 
    750                 if (t == 'text' || t == 'password' || tag == 'textarea') { 
    751                         this.value = ''; 
    752                 } 
    753                 else if (t == 'checkbox' || t == 'radio') { 
    754                         this.checked = false; 
    755                 } 
    756                 else if (tag == 'select') { 
    757                         this.selectedIndex = -1; 
    758                 } 
    759         }); 
     1077$.fn.clearFields = $.fn.clearInputs = function(includeHidden) { 
     1078    var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list 
     1079    return this.each(function() { 
     1080        var t = this.type, tag = this.tagName.toLowerCase(); 
     1081        if (re.test(t) || tag == 'textarea') { 
     1082            this.value = ''; 
     1083        } 
     1084        else if (t == 'checkbox' || t == 'radio') { 
     1085            this.checked = false; 
     1086        } 
     1087        else if (tag == 'select') { 
     1088            this.selectedIndex = -1; 
     1089        } 
     1090        else if (t == "file") { 
     1091            if (/MSIE/.test(navigator.userAgent)) { 
     1092                $(this).replaceWith($(this).clone(true)); 
     1093            } else { 
     1094                $(this).val(''); 
     1095            } 
     1096        } 
     1097        else if (includeHidden) { 
     1098            // includeHidden can be the value true, or it can be a selector string 
     1099            // indicating a special test; for example: 
     1100            //  $('#myForm').clearForm('.special:hidden') 
     1101            // the above would clean hidden inputs that have the class of 'special' 
     1102            if ( (includeHidden === true && /hidden/.test(t)) || 
     1103                 (typeof includeHidden == 'string' && $(this).is(includeHidden)) ) 
     1104                this.value = ''; 
     1105        } 
     1106    }); 
    7601107}; 
    7611108 
    7621109/** 
    7631110 * Resets the form data.  Causes all form elements to be reset to their original value. 
    7641111 */ 
    7651112$.fn.resetForm = function() { 
    766         return this.each(function() { 
    767                 // guard against an input with the name of 'reset' 
    768                 // note that IE reports the reset function as an 'object' 
    769                 if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) { 
    770                         this.reset(); 
    771                 } 
    772         }); 
     1113    return this.each(function() { 
     1114        // guard against an input with the name of 'reset' 
     1115        // note that IE reports the reset function as an 'object' 
     1116        if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) { 
     1117            this.reset(); 
     1118        } 
     1119    }); 
    7731120}; 
    7741121 
    7751122/** 
    7761123 * Enables or disables any matching elements. 
    7771124 */ 
    7781125$.fn.enable = function(b) { 
    779         if (b === undefined) { 
    780                 b = true; 
    781         } 
    782         return this.each(function() { 
    783                 this.disabled = !b; 
    784         }); 
     1126    if (b === undefined) { 
     1127        b = true; 
     1128    } 
     1129    return this.each(function() { 
     1130        this.disabled = !b; 
     1131    }); 
    7851132}; 
    7861133 
    7871134/** 
     
    7891136 * selects/deselects and matching option elements. 
    7901137 */ 
    7911138$.fn.selected = function(select) { 
    792         if (select === undefined) { 
    793                 select = true; 
    794         } 
    795         return this.each(function() { 
    796                 var t = this.type; 
    797                 if (t == 'checkbox' || t == 'radio') { 
    798                         this.checked = select; 
    799                 } 
    800                 else if (this.tagName.toLowerCase() == 'option') { 
    801                         var $sel = $(this).parent('select'); 
    802                         if (select && $sel[0] && $sel[0].type == 'select-one') { 
    803                                 // deselect all other options 
    804                                 $sel.find('option').selected(false); 
    805                         } 
    806                         this.selected = select; 
    807                 } 
    808         }); 
     1139    if (select === undefined) { 
     1140        select = true; 
     1141    } 
     1142    return this.each(function() { 
     1143        var t = this.type; 
     1144        if (t == 'checkbox' || t == 'radio') { 
     1145            this.checked = select; 
     1146        } 
     1147        else if (this.tagName.toLowerCase() == 'option') { 
     1148            var $sel = $(this).parent('select'); 
     1149            if (select && $sel[0] && $sel[0].type == 'select-one') { 
     1150                // deselect all other options 
     1151                $sel.find('option').selected(false); 
     1152            } 
     1153            this.selected = select; 
     1154        } 
     1155    }); 
    8091156}; 
    8101157 
     1158// expose debug var 
     1159$.fn.ajaxSubmit.debug = false; 
     1160 
    8111161// helper fn for console logging 
    812 // set $.fn.ajaxSubmit.debug to true to enable debug logging 
    8131162function log() { 
    814         if ($.fn.ajaxSubmit.debug) { 
    815                 var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); 
    816                 if (window.console && window.console.log) { 
    817                         window.console.log(msg); 
    818                 } 
    819                 else if (window.opera && window.opera.postError) { 
    820                         window.opera.postError(msg); 
    821                 } 
    822         } 
    823 }; 
     1163    if (!$.fn.ajaxSubmit.debug) 
     1164        return; 
     1165    var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); 
     1166    if (window.console && window.console.log) { 
     1167        window.console.log(msg); 
     1168    } 
     1169    else if (window.opera && window.opera.postError) { 
     1170        window.opera.postError(msg); 
     1171    } 
     1172} 
    8241173 
    825 })(jQuery); 
     1174})(jQuery); 
     1175 No newline at end of file