File indexing completed on 2024-05-19 06:00:27

0001 /*!
0002  * jQuery Form Plugin
0003  * version: 3.51.0-2014.06.20
0004  * Requires jQuery v1.5 or later
0005  * Copyright (c) 2014 M. Alsup
0006  * Examples and documentation at: http://malsup.com/jquery/form/
0007  * Project repository: https://github.com/malsup/form
0008  * Dual licensed under the MIT and GPL licenses.
0009  * https://github.com/malsup/form#copyright-and-license
0010  */
0011 /*global ActiveXObject */
0012 
0013 // AMD support
0014 (function (factory) {
0015     "use strict";
0016     if (typeof define === 'function' && define.amd) {
0017         // using AMD; register as anon module
0018         define(['jquery'], factory);
0019     } else {
0020         // no AMD; invoke directly
0021         factory( (typeof(jQuery) != 'undefined') ? jQuery : window.Zepto );
0022     }
0023 }
0024 
0025 (function($) {
0026 "use strict";
0027 
0028 /*
0029     Usage Note:
0030     -----------
0031     Do not use both ajaxSubmit and ajaxForm on the same form.  These
0032     functions are mutually exclusive.  Use ajaxSubmit if you want
0033     to bind your own submit handler to the form.  For example,
0034 
0035     $(document).ready(function() {
0036         $('#myForm').on('submit', function(e) {
0037             e.preventDefault(); // <-- important
0038             $(this).ajaxSubmit({
0039                 target: '#output'
0040             });
0041         });
0042     });
0043 
0044     Use ajaxForm when you want the plugin to manage all the event binding
0045     for you.  For example,
0046 
0047     $(document).ready(function() {
0048         $('#myForm').ajaxForm({
0049             target: '#output'
0050         });
0051     });
0052 
0053     You can also use ajaxForm with delegation (requires jQuery v1.7+), so the
0054     form does not have to exist when you invoke ajaxForm:
0055 
0056     $('#myForm').ajaxForm({
0057         delegation: true,
0058         target: '#output'
0059     });
0060 
0061     When using ajaxForm, the ajaxSubmit function will be invoked for you
0062     at the appropriate time.
0063 */
0064 
0065 /**
0066  * Feature detection
0067  */
0068 var feature = {};
0069 feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
0070 feature.formdata = window.FormData !== undefined;
0071 
0072 var hasProp = !!$.fn.prop;
0073 
0074 // attr2 uses prop when it can but checks the return type for
0075 // an expected string.  this accounts for the case where a form 
0076 // contains inputs with names like "action" or "method"; in those
0077 // cases "prop" returns the element
0078 $.fn.attr2 = function() {
0079     if ( ! hasProp ) {
0080         return this.attr.apply(this, arguments);
0081     }
0082     var val = this.prop.apply(this, arguments);
0083     if ( ( val && val.jquery ) || typeof val === 'string' ) {
0084         return val;
0085     }
0086     return this.attr.apply(this, arguments);
0087 };
0088 
0089 /**
0090  * ajaxSubmit() provides a mechanism for immediately submitting
0091  * an HTML form using AJAX.
0092  */
0093 $.fn.ajaxSubmit = function(options) {
0094     /*jshint scripturl:true */
0095 
0096     // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
0097     if (!this.length) {
0098         log('ajaxSubmit: skipping submit process - no element selected');
0099         return this;
0100     }
0101 
0102     var method, action, url, $form = this;
0103 
0104     if (typeof options == 'function') {
0105         options = { success: options };
0106     }
0107     else if ( options === undefined ) {
0108         options = {};
0109     }
0110 
0111     method = options.type || this.attr2('method');
0112     action = options.url  || this.attr2('action');
0113 
0114     url = (typeof action === 'string') ? $.trim(action) : '';
0115     url = url || window.location.href || '';
0116     if (url) {
0117         // clean url (don't include hash vaue)
0118         url = (url.match(/^([^#]+)/)||[])[1];
0119     }
0120 
0121     options = $.extend(true, {
0122         url:  url,
0123         success: $.ajaxSettings.success,
0124         type: method || $.ajaxSettings.type,
0125         iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
0126     }, options);
0127 
0128     // hook for manipulating the form data before it is extracted;
0129     // convenient for use with rich editors like tinyMCE or FCKEditor
0130     var veto = {};
0131     this.trigger('form-pre-serialize', [this, options, veto]);
0132     if (veto.veto) {
0133         log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
0134         return this;
0135     }
0136 
0137     // provide opportunity to alter form data before it is serialized
0138     if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
0139         log('ajaxSubmit: submit aborted via beforeSerialize callback');
0140         return this;
0141     }
0142 
0143     var traditional = options.traditional;
0144     if ( traditional === undefined ) {
0145         traditional = $.ajaxSettings.traditional;
0146     }
0147 
0148     var elements = [];
0149     var qx, a = this.formToArray(options.semantic, elements);
0150     if (options.data) {
0151         options.extraData = options.data;
0152         qx = $.param(options.data, traditional);
0153     }
0154 
0155     // give pre-submit callback an opportunity to abort the submit
0156     if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
0157         log('ajaxSubmit: submit aborted via beforeSubmit callback');
0158         return this;
0159     }
0160 
0161     // fire vetoable 'validate' event
0162     this.trigger('form-submit-validate', [a, this, options, veto]);
0163     if (veto.veto) {
0164         log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
0165         return this;
0166     }
0167 
0168     var q = $.param(a, traditional);
0169     if (qx) {
0170         q = ( q ? (q + '&' + qx) : qx );
0171     }
0172     if (options.type.toUpperCase() == 'GET') {
0173         options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
0174         options.data = null;  // data is null for 'get'
0175     }
0176     else {
0177         options.data = q; // data is the query string for 'post'
0178     }
0179 
0180     var callbacks = [];
0181     if (options.resetForm) {
0182         callbacks.push(function() { $form.resetForm(); });
0183     }
0184     if (options.clearForm) {
0185         callbacks.push(function() { $form.clearForm(options.includeHidden); });
0186     }
0187 
0188     // perform a load on the target only if dataType is not provided
0189     if (!options.dataType && options.target) {
0190         var oldSuccess = options.success || function(){};
0191         callbacks.push(function(data) {
0192             var fn = options.replaceTarget ? 'replaceWith' : 'html';
0193             $(options.target)[fn](data).each(oldSuccess, arguments);
0194         });
0195     }
0196     else if (options.success) {
0197         callbacks.push(options.success);
0198     }
0199 
0200     options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
0201         var context = options.context || this ;    // jQuery 1.4+ supports scope context
0202         for (var i=0, max=callbacks.length; i < max; i++) {
0203             callbacks[i].apply(context, [data, status, xhr || $form, $form]);
0204         }
0205     };
0206 
0207     if (options.error) {
0208         var oldError = options.error;
0209         options.error = function(xhr, status, error) {
0210             var context = options.context || this;
0211             oldError.apply(context, [xhr, status, error, $form]);
0212         };
0213     }
0214 
0215      if (options.complete) {
0216         var oldComplete = options.complete;
0217         options.complete = function(xhr, status) {
0218             var context = options.context || this;
0219             oldComplete.apply(context, [xhr, status, $form]);
0220         };
0221     }
0222 
0223     // are there files to upload?
0224 
0225     // [value] (issue #113), also see comment:
0226     // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219
0227     var fileInputs = $('input[type=file]:enabled', this).filter(function() { return $(this).val() !== ''; });
0228 
0229     var hasFileInputs = fileInputs.length > 0;
0230     var mp = 'multipart/form-data';
0231     var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
0232 
0233     var fileAPI = feature.fileapi && feature.formdata;
0234     log("fileAPI :" + fileAPI);
0235     var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;
0236 
0237     var jqxhr;
0238 
0239     // options.iframe allows user to force iframe mode
0240     // 06-NOV-09: now defaulting to iframe mode if file input is detected
0241     if (options.iframe !== false && (options.iframe || shouldUseFrame)) {
0242         // hack to fix Safari hang (thanks to Tim Molendijk for this)
0243         // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
0244         if (options.closeKeepAlive) {
0245             $.get(options.closeKeepAlive, function() {
0246                 jqxhr = fileUploadIframe(a);
0247             });
0248         }
0249         else {
0250             jqxhr = fileUploadIframe(a);
0251         }
0252     }
0253     else if ((hasFileInputs || multipart) && fileAPI) {
0254         jqxhr = fileUploadXhr(a);
0255     }
0256     else {
0257         jqxhr = $.ajax(options);
0258     }
0259 
0260     $form.removeData('jqxhr').data('jqxhr', jqxhr);
0261 
0262     // clear element array
0263     for (var k=0; k < elements.length; k++) {
0264         elements[k] = null;
0265     }
0266 
0267     // fire 'notify' event
0268     this.trigger('form-submit-notify', [this, options]);
0269     return this;
0270 
0271     // utility fn for deep serialization
0272     function deepSerialize(extraData){
0273         var serialized = $.param(extraData, options.traditional).split('&');
0274         var len = serialized.length;
0275         var result = [];
0276         var i, part;
0277         for (i=0; i < len; i++) {
0278             // #252; undo param space replacement
0279             serialized[i] = serialized[i].replace(/\+/g,' ');
0280             part = serialized[i].split('=');
0281             // #278; use array instead of object storage, favoring array serializations
0282             result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]);
0283         }
0284         return result;
0285     }
0286 
0287      // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
0288     function fileUploadXhr(a) {
0289         var formdata = new FormData();
0290 
0291         for (var i=0; i < a.length; i++) {
0292             formdata.append(a[i].name, a[i].value);
0293         }
0294 
0295         if (options.extraData) {
0296             var serializedData = deepSerialize(options.extraData);
0297             for (i=0; i < serializedData.length; i++) {
0298                 if (serializedData[i]) {
0299                     formdata.append(serializedData[i][0], serializedData[i][1]);
0300                 }
0301             }
0302         }
0303 
0304         options.data = null;
0305 
0306         var s = $.extend(true, {}, $.ajaxSettings, options, {
0307             contentType: false,
0308             processData: false,
0309             cache: false,
0310             type: method || 'POST'
0311         });
0312 
0313         if (options.uploadProgress) {
0314             // workaround because jqXHR does not expose upload property
0315             s.xhr = function() {
0316                 var xhr = $.ajaxSettings.xhr();
0317                 if (xhr.upload) {
0318                     xhr.upload.addEventListener('progress', function(event) {
0319                         var percent = 0;
0320                         var position = event.loaded || event.position; /*event.position is deprecated*/
0321                         var total = event.total;
0322                         if (event.lengthComputable) {
0323                             percent = Math.ceil(position / total * 100);
0324                         }
0325                         options.uploadProgress(event, position, total, percent);
0326                     }, false);
0327                 }
0328                 return xhr;
0329             };
0330         }
0331 
0332         s.data = null;
0333         var beforeSend = s.beforeSend;
0334         s.beforeSend = function(xhr, o) {
0335             //Send FormData() provided by user
0336             if (options.formData) {
0337                 o.data = options.formData;
0338             }
0339             else {
0340                 o.data = formdata;
0341             }
0342             if(beforeSend) {
0343                 beforeSend.call(this, xhr, o);
0344             }
0345         };
0346         return $.ajax(s);
0347     }
0348 
0349     // private function for handling file uploads (hat tip to YAHOO!)
0350     function fileUploadIframe(a) {
0351         var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
0352         var deferred = $.Deferred();
0353 
0354         // #341
0355         deferred.abort = function(status) {
0356             xhr.abort(status);
0357         };
0358 
0359         if (a) {
0360             // ensure that every serialized input is still enabled
0361             for (i=0; i < elements.length; i++) {
0362                 el = $(elements[i]);
0363                 if ( hasProp ) {
0364                     el.prop('disabled', false);
0365                 }
0366                 else {
0367                     el.removeAttr('disabled');
0368                 }
0369             }
0370         }
0371 
0372         s = $.extend(true, {}, $.ajaxSettings, options);
0373         s.context = s.context || s;
0374         id = 'jqFormIO' + (new Date().getTime());
0375         if (s.iframeTarget) {
0376             $io = $(s.iframeTarget);
0377             n = $io.attr2('name');
0378             if (!n) {
0379                 $io.attr2('name', id);
0380             }
0381             else {
0382                 id = n;
0383             }
0384         }
0385         else {
0386             $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
0387             $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
0388         }
0389         io = $io[0];
0390 
0391 
0392         xhr = { // mock object
0393             aborted: 0,
0394             responseText: null,
0395             responseXML: null,
0396             status: 0,
0397             statusText: 'n/a',
0398             getAllResponseHeaders: function() {},
0399             getResponseHeader: function() {},
0400             setRequestHeader: function() {},
0401             abort: function(status) {
0402                 var e = (status === 'timeout' ? 'timeout' : 'aborted');
0403                 log('aborting upload... ' + e);
0404                 this.aborted = 1;
0405 
0406                 try { // #214, #257
0407                     if (io.contentWindow.document.execCommand) {
0408                         io.contentWindow.document.execCommand('Stop');
0409                     }
0410                 }
0411                 catch(ignore) {}
0412 
0413                 $io.attr('src', s.iframeSrc); // abort op in progress
0414                 xhr.error = e;
0415                 if (s.error) {
0416                     s.error.call(s.context, xhr, e, status);
0417                 }
0418                 if (g) {
0419                     $.event.trigger("ajaxError", [xhr, s, e]);
0420                 }
0421                 if (s.complete) {
0422                     s.complete.call(s.context, xhr, e);
0423                 }
0424             }
0425         };
0426 
0427         g = s.global;
0428         // trigger ajax global events so that activity/block indicators work like normal
0429         if (g && 0 === $.active++) {
0430             $.event.trigger("ajaxStart");
0431         }
0432         if (g) {
0433             $.event.trigger("ajaxSend", [xhr, s]);
0434         }
0435 
0436         if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
0437             if (s.global) {
0438                 $.active--;
0439             }
0440             deferred.reject();
0441             return deferred;
0442         }
0443         if (xhr.aborted) {
0444             deferred.reject();
0445             return deferred;
0446         }
0447 
0448         // add submitting element to data if we know it
0449         sub = form.clk;
0450         if (sub) {
0451             n = sub.name;
0452             if (n && !sub.disabled) {
0453                 s.extraData = s.extraData || {};
0454                 s.extraData[n] = sub.value;
0455                 if (sub.type == "image") {
0456                     s.extraData[n+'.x'] = form.clk_x;
0457                     s.extraData[n+'.y'] = form.clk_y;
0458                 }
0459             }
0460         }
0461 
0462         var CLIENT_TIMEOUT_ABORT = 1;
0463         var SERVER_ABORT = 2;
0464                 
0465         function getDoc(frame) {
0466             /* it looks like contentWindow or contentDocument do not
0467              * carry the protocol property in ie8, when running under ssl
0468              * frame.document is the only valid response document, since
0469              * the protocol is know but not on the other two objects. strange?
0470              * "Same origin policy" http://en.wikipedia.org/wiki/Same_origin_policy
0471              */
0472             
0473             var doc = null;
0474             
0475             // IE8 cascading access check
0476             try {
0477                 if (frame.contentWindow) {
0478                     doc = frame.contentWindow.document;
0479                 }
0480             } catch(err) {
0481                 // IE8 access denied under ssl & missing protocol
0482                 log('cannot get iframe.contentWindow document: ' + err);
0483             }
0484 
0485             if (doc) { // successful getting content
0486                 return doc;
0487             }
0488 
0489             try { // simply checking may throw in ie8 under ssl or mismatched protocol
0490                 doc = frame.contentDocument ? frame.contentDocument : frame.document;
0491             } catch(err) {
0492                 // last attempt
0493                 log('cannot get iframe.contentDocument: ' + err);
0494                 doc = frame.document;
0495             }
0496             return doc;
0497         }
0498 
0499         // Rails CSRF hack (thanks to Yvan Barthelemy)
0500         var csrf_token = $('meta[name=csrf-token]').attr('content');
0501         var csrf_param = $('meta[name=csrf-param]').attr('content');
0502         if (csrf_param && csrf_token) {
0503             s.extraData = s.extraData || {};
0504             s.extraData[csrf_param] = csrf_token;
0505         }
0506 
0507         // take a breath so that pending repaints get some cpu time before the upload starts
0508         function doSubmit() {
0509             // make sure form attrs are set
0510             var t = $form.attr2('target'), 
0511                 a = $form.attr2('action'), 
0512                 mp = 'multipart/form-data',
0513                 et = $form.attr('enctype') || $form.attr('encoding') || mp;
0514 
0515             // update form attrs in IE friendly way
0516             form.setAttribute('target',id);
0517             if (!method || /post/i.test(method) ) {
0518                 form.setAttribute('method', 'POST');
0519             }
0520             if (a != s.url) {
0521                 form.setAttribute('action', s.url);
0522             }
0523 
0524             // ie borks in some cases when setting encoding
0525             if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
0526                 $form.attr({
0527                     encoding: 'multipart/form-data',
0528                     enctype:  'multipart/form-data'
0529                 });
0530             }
0531 
0532             // support timout
0533             if (s.timeout) {
0534                 timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
0535             }
0536 
0537             // look for server aborts
0538             function checkState() {
0539                 try {
0540                     var state = getDoc(io).readyState;
0541                     log('state = ' + state);
0542                     if (state && state.toLowerCase() == 'uninitialized') {
0543                         setTimeout(checkState,50);
0544                     }
0545                 }
0546                 catch(e) {
0547                     log('Server abort: ' , e, ' (', e.name, ')');
0548                     cb(SERVER_ABORT);
0549                     if (timeoutHandle) {
0550                         clearTimeout(timeoutHandle);
0551                     }
0552                     timeoutHandle = undefined;
0553                 }
0554             }
0555 
0556             // add "extra" data to form if provided in options
0557             var extraInputs = [];
0558             try {
0559                 if (s.extraData) {
0560                     for (var n in s.extraData) {
0561                         if (s.extraData.hasOwnProperty(n)) {
0562                            // if using the $.param format that allows for multiple values with the same name
0563                            if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {
0564                                extraInputs.push(
0565                                $('<input type="hidden" name="'+s.extraData[n].name+'">').val(s.extraData[n].value)
0566                                    .appendTo(form)[0]);
0567                            } else {
0568                                extraInputs.push(
0569                                $('<input type="hidden" name="'+n+'">').val(s.extraData[n])
0570                                    .appendTo(form)[0]);
0571                            }
0572                         }
0573                     }
0574                 }
0575 
0576                 if (!s.iframeTarget) {
0577                     // add iframe to doc and submit the form
0578                     $io.appendTo('body');
0579                 }
0580                 if (io.attachEvent) {
0581                     io.attachEvent('onload', cb);
0582                 }
0583                 else {
0584                     io.addEventListener('load', cb, false);
0585                 }
0586                 setTimeout(checkState,15);
0587 
0588                 try {
0589                     form.submit();
0590                 } catch(err) {
0591                     // just in case form has element with name/id of 'submit'
0592                     var submitFn = document.createElement('form').submit;
0593                     submitFn.apply(form);
0594                 }
0595             }
0596             finally {
0597                 // reset attrs and remove "extra" input elements
0598                 form.setAttribute('action',a);
0599                 form.setAttribute('enctype', et); // #380
0600                 if(t) {
0601                     form.setAttribute('target', t);
0602                 } else {
0603                     $form.removeAttr('target');
0604                 }
0605                 $(extraInputs).remove();
0606             }
0607         }
0608 
0609         if (s.forceSync) {
0610             doSubmit();
0611         }
0612         else {
0613             setTimeout(doSubmit, 10); // this lets dom updates render
0614         }
0615 
0616         var data, doc, domCheckCount = 50, callbackProcessed;
0617 
0618         function cb(e) {
0619             if (xhr.aborted || callbackProcessed) {
0620                 return;
0621             }
0622             
0623             doc = getDoc(io);
0624             if(!doc) {
0625                 log('cannot access response document');
0626                 e = SERVER_ABORT;
0627             }
0628             if (e === CLIENT_TIMEOUT_ABORT && xhr) {
0629                 xhr.abort('timeout');
0630                 deferred.reject(xhr, 'timeout');
0631                 return;
0632             }
0633             else if (e == SERVER_ABORT && xhr) {
0634                 xhr.abort('server abort');
0635                 deferred.reject(xhr, 'error', 'server abort');
0636                 return;
0637             }
0638 
0639             if (!doc || doc.location.href == s.iframeSrc) {
0640                 // response not received yet
0641                 if (!timedOut) {
0642                     return;
0643                 }
0644             }
0645             if (io.detachEvent) {
0646                 io.detachEvent('onload', cb);
0647             }
0648             else {
0649                 io.removeEventListener('load', cb, false);
0650             }
0651 
0652             var status = 'success', errMsg;
0653             try {
0654                 if (timedOut) {
0655                     throw 'timeout';
0656                 }
0657 
0658                 var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
0659                 log('isXml='+isXml);
0660                 if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {
0661                     if (--domCheckCount) {
0662                         // in some browsers (Opera) the iframe DOM is not always traversable when
0663                         // the onload callback fires, so we loop a bit to accommodate
0664                         log('requeing onLoad callback, DOM not available');
0665                         setTimeout(cb, 250);
0666                         return;
0667                     }
0668                     // let this fall through because server response could be an empty document
0669                     //log('Could not access iframe DOM after mutiple tries.');
0670                     //throw 'DOMException: not available';
0671                 }
0672 
0673                 //log('response detected');
0674                 var docRoot = doc.body ? doc.body : doc.documentElement;
0675                 xhr.responseText = docRoot ? docRoot.innerHTML : null;
0676                 xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
0677                 if (isXml) {
0678                     s.dataType = 'xml';
0679                 }
0680                 xhr.getResponseHeader = function(header){
0681                     var headers = {'content-type': s.dataType};
0682                     return headers[header.toLowerCase()];
0683                 };
0684                 // support for XHR 'status' & 'statusText' emulation :
0685                 if (docRoot) {
0686                     xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
0687                     xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
0688                 }
0689 
0690                 var dt = (s.dataType || '').toLowerCase();
0691                 var scr = /(json|script|text)/.test(dt);
0692                 if (scr || s.textarea) {
0693                     // see if user embedded response in textarea
0694                     var ta = doc.getElementsByTagName('textarea')[0];
0695                     if (ta) {
0696                         xhr.responseText = ta.value;
0697                         // support for XHR 'status' & 'statusText' emulation :
0698                         xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
0699                         xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
0700                     }
0701                     else if (scr) {
0702                         // account for browsers injecting pre around json response
0703                         var pre = doc.getElementsByTagName('pre')[0];
0704                         var b = doc.getElementsByTagName('body')[0];
0705                         if (pre) {
0706                             xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;
0707                         }
0708                         else if (b) {
0709                             xhr.responseText = b.textContent ? b.textContent : b.innerText;
0710                         }
0711                     }
0712                 }
0713                 else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) {
0714                     xhr.responseXML = toXml(xhr.responseText);
0715                 }
0716 
0717                 try {
0718                     data = httpData(xhr, dt, s);
0719                 }
0720                 catch (err) {
0721                     status = 'parsererror';
0722                     xhr.error = errMsg = (err || status);
0723                 }
0724             }
0725             catch (err) {
0726                 log('error caught: ',err);
0727                 status = 'error';
0728                 xhr.error = errMsg = (err || status);
0729             }
0730 
0731             if (xhr.aborted) {
0732                 log('upload aborted');
0733                 status = null;
0734             }
0735 
0736             if (xhr.status) { // we've set xhr.status
0737                 status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
0738             }
0739 
0740             // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
0741             if (status === 'success') {
0742                 if (s.success) {
0743                     s.success.call(s.context, data, 'success', xhr);
0744                 }
0745                 deferred.resolve(xhr.responseText, 'success', xhr);
0746                 if (g) {
0747                     $.event.trigger("ajaxSuccess", [xhr, s]);
0748                 }
0749             }
0750             else if (status) {
0751                 if (errMsg === undefined) {
0752                     errMsg = xhr.statusText;
0753                 }
0754                 if (s.error) {
0755                     s.error.call(s.context, xhr, status, errMsg);
0756                 }
0757                 deferred.reject(xhr, 'error', errMsg);
0758                 if (g) {
0759                     $.event.trigger("ajaxError", [xhr, s, errMsg]);
0760                 }
0761             }
0762 
0763             if (g) {
0764                 $.event.trigger("ajaxComplete", [xhr, s]);
0765             }
0766 
0767             if (g && ! --$.active) {
0768                 $.event.trigger("ajaxStop");
0769             }
0770 
0771             if (s.complete) {
0772                 s.complete.call(s.context, xhr, status);
0773             }
0774 
0775             callbackProcessed = true;
0776             if (s.timeout) {
0777                 clearTimeout(timeoutHandle);
0778             }
0779 
0780             // clean up
0781             setTimeout(function() {
0782                 if (!s.iframeTarget) {
0783                     $io.remove();
0784                 }
0785                 else { //adding else to clean up existing iframe response.
0786                     $io.attr('src', s.iframeSrc);
0787                 }
0788                 xhr.responseXML = null;
0789             }, 100);
0790         }
0791 
0792         var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
0793             if (window.ActiveXObject) {
0794                 doc = new ActiveXObject('Microsoft.XMLDOM');
0795                 doc.async = 'false';
0796                 doc.loadXML(s);
0797             }
0798             else {
0799                 doc = (new DOMParser()).parseFromString(s, 'text/xml');
0800             }
0801             return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
0802         };
0803         var parseJSON = $.parseJSON || function(s) {
0804             /*jslint evil:true */
0805             return window['eval']('(' + s + ')');
0806         };
0807 
0808         var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
0809 
0810             var ct = xhr.getResponseHeader('content-type') || '',
0811                 xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
0812                 data = xml ? xhr.responseXML : xhr.responseText;
0813 
0814             if (xml && data.documentElement.nodeName === 'parsererror') {
0815                 if ($.error) {
0816                     $.error('parsererror');
0817                 }
0818             }
0819             if (s && s.dataFilter) {
0820                 data = s.dataFilter(data, type);
0821             }
0822             if (typeof data === 'string') {
0823                 if (type === 'json' || !type && ct.indexOf('json') >= 0) {
0824                     data = parseJSON(data);
0825                 } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
0826                     $.globalEval(data);
0827                 }
0828             }
0829             return data;
0830         };
0831 
0832         return deferred;
0833     }
0834 };
0835 
0836 /**
0837  * ajaxForm() provides a mechanism for fully automating form submission.
0838  *
0839  * The advantages of using this method instead of ajaxSubmit() are:
0840  *
0841  * 1: This method will include coordinates for <input type="image" /> elements (if the element
0842  *    is used to submit the form).
0843  * 2. This method will include the submit element's name/value data (for the element that was
0844  *    used to submit the form).
0845  * 3. This method binds the submit() method to the form for you.
0846  *
0847  * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
0848  * passes the options argument along after properly binding events for submit elements and
0849  * the form itself.
0850  */
0851 $.fn.ajaxForm = function(options) {
0852     options = options || {};
0853     options.delegation = options.delegation && $.isFunction($.fn.on);
0854 
0855     // in jQuery 1.3+ we can fix mistakes with the ready state
0856     if (!options.delegation && this.length === 0) {
0857         var o = { s: this.selector, c: this.context };
0858         if (!$.isReady && o.s) {
0859             log('DOM not ready, queuing ajaxForm');
0860             $(function() {
0861                 $(o.s,o.c).ajaxForm(options);
0862             });
0863             return this;
0864         }
0865         // is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
0866         log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
0867         return this;
0868     }
0869 
0870     if ( options.delegation ) {
0871         $(document)
0872             .off('submit.form-plugin', this.selector, doAjaxSubmit)
0873             .off('click.form-plugin', this.selector, captureSubmittingElement)
0874             .on('submit.form-plugin', this.selector, options, doAjaxSubmit)
0875             .on('click.form-plugin', this.selector, options, captureSubmittingElement);
0876         return this;
0877     }
0878 
0879     return this.ajaxFormUnbind()
0880         .bind('submit.form-plugin', options, doAjaxSubmit)
0881         .bind('click.form-plugin', options, captureSubmittingElement);
0882 };
0883 
0884 // private event handlers
0885 function doAjaxSubmit(e) {
0886     /*jshint validthis:true */
0887     var options = e.data;
0888     if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
0889         e.preventDefault();
0890         $(e.target).ajaxSubmit(options); // #365
0891     }
0892 }
0893 
0894 function captureSubmittingElement(e) {
0895     /*jshint validthis:true */
0896     var target = e.target;
0897     var $el = $(target);
0898     if (!($el.is("[type=submit],[type=image]"))) {
0899         // is this a child element of the submit el?  (ex: a span within a button)
0900         var t = $el.closest('[type=submit]');
0901         if (t.length === 0) {
0902             return;
0903         }
0904         target = t[0];
0905     }
0906     var form = this;
0907     form.clk = target;
0908     if (target.type == 'image') {
0909         if (e.offsetX !== undefined) {
0910             form.clk_x = e.offsetX;
0911             form.clk_y = e.offsetY;
0912         } else if (typeof $.fn.offset == 'function') {
0913             var offset = $el.offset();
0914             form.clk_x = e.pageX - offset.left;
0915             form.clk_y = e.pageY - offset.top;
0916         } else {
0917             form.clk_x = e.pageX - target.offsetLeft;
0918             form.clk_y = e.pageY - target.offsetTop;
0919         }
0920     }
0921     // clear form vars
0922     setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
0923 }
0924 
0925 
0926 // ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
0927 $.fn.ajaxFormUnbind = function() {
0928     return this.unbind('submit.form-plugin click.form-plugin');
0929 };
0930 
0931 /**
0932  * formToArray() gathers form element data into an array of objects that can
0933  * be passed to any of the following ajax functions: $.get, $.post, or load.
0934  * Each object in the array has both a 'name' and 'value' property.  An example of
0935  * an array for a simple login form might be:
0936  *
0937  * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
0938  *
0939  * It is this array that is passed to pre-submit callback functions provided to the
0940  * ajaxSubmit() and ajaxForm() methods.
0941  */
0942 $.fn.formToArray = function(semantic, elements) {
0943     var a = [];
0944     if (this.length === 0) {
0945         return a;
0946     }
0947 
0948     var form = this[0];
0949     var formId = this.attr('id');
0950     var els = semantic ? form.getElementsByTagName('*') : form.elements;
0951     var els2;
0952 
0953     if (els && !/MSIE [678]/.test(navigator.userAgent)) { // #390
0954         els = $(els).get();  // convert to standard array
0955     }
0956 
0957     // #386; account for inputs outside the form which use the 'form' attribute
0958     if ( formId ) {
0959         els2 = $(':input[form="' + formId + '"]').get(); // hat tip @thet
0960         if ( els2.length ) {
0961             els = (els || []).concat(els2);
0962         }
0963     }
0964 
0965     if (!els || !els.length) {
0966         return a;
0967     }
0968 
0969     var i,j,n,v,el,max,jmax;
0970     for(i=0, max=els.length; i < max; i++) {
0971         el = els[i];
0972         n = el.name;
0973         if (!n || el.disabled) {
0974             continue;
0975         }
0976 
0977         if (semantic && form.clk && el.type == "image") {
0978             // handle image inputs on the fly when semantic == true
0979             if(form.clk == el) {
0980                 a.push({name: n, value: $(el).val(), type: el.type });
0981                 a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
0982             }
0983             continue;
0984         }
0985 
0986         v = $.fieldValue(el, true);
0987         if (v && v.constructor == Array) {
0988             if (elements) {
0989                 elements.push(el);
0990             }
0991             for(j=0, jmax=v.length; j < jmax; j++) {
0992                 a.push({name: n, value: v[j]});
0993             }
0994         }
0995         else if (feature.fileapi && el.type == 'file') {
0996             if (elements) {
0997                 elements.push(el);
0998             }
0999             var files = el.files;
1000             if (files.length) {
1001                 for (j=0; j < files.length; j++) {
1002                     a.push({name: n, value: files[j], type: el.type});
1003                 }
1004             }
1005             else {
1006                 // #180
1007                 a.push({ name: n, value: '', type: el.type });
1008             }
1009         }
1010         else if (v !== null && typeof v != 'undefined') {
1011             if (elements) {
1012                 elements.push(el);
1013             }
1014             a.push({name: n, value: v, type: el.type, required: el.required});
1015         }
1016     }
1017 
1018     if (!semantic && form.clk) {
1019         // input type=='image' are not found in elements array! handle it here
1020         var $input = $(form.clk), input = $input[0];
1021         n = input.name;
1022         if (n && !input.disabled && input.type == 'image') {
1023             a.push({name: n, value: $input.val()});
1024             a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
1025         }
1026     }
1027     return a;
1028 };
1029 
1030 /**
1031  * Serializes form data into a 'submittable' string. This method will return a string
1032  * in the format: name1=value1&amp;name2=value2
1033  */
1034 $.fn.formSerialize = function(semantic) {
1035     //hand off to jQuery.param for proper encoding
1036     return $.param(this.formToArray(semantic));
1037 };
1038 
1039 /**
1040  * Serializes all field elements in the jQuery object into a query string.
1041  * This method will return a string in the format: name1=value1&amp;name2=value2
1042  */
1043 $.fn.fieldSerialize = function(successful) {
1044     var a = [];
1045     this.each(function() {
1046         var n = this.name;
1047         if (!n) {
1048             return;
1049         }
1050         var v = $.fieldValue(this, successful);
1051         if (v && v.constructor == Array) {
1052             for (var i=0,max=v.length; i < max; i++) {
1053                 a.push({name: n, value: v[i]});
1054             }
1055         }
1056         else if (v !== null && typeof v != 'undefined') {
1057             a.push({name: this.name, value: v});
1058         }
1059     });
1060     //hand off to jQuery.param for proper encoding
1061     return $.param(a);
1062 };
1063 
1064 /**
1065  * Returns the value(s) of the element in the matched set.  For example, consider the following form:
1066  *
1067  *  <form><fieldset>
1068  *      <input name="A" type="text" />
1069  *      <input name="A" type="text" />
1070  *      <input name="B" type="checkbox" value="B1" />
1071  *      <input name="B" type="checkbox" value="B2"/>
1072  *      <input name="C" type="radio" value="C1" />
1073  *      <input name="C" type="radio" value="C2" />
1074  *  </fieldset></form>
1075  *
1076  *  var v = $('input[type=text]').fieldValue();
1077  *  // if no values are entered into the text inputs
1078  *  v == ['','']
1079  *  // if values entered into the text inputs are 'foo' and 'bar'
1080  *  v == ['foo','bar']
1081  *
1082  *  var v = $('input[type=checkbox]').fieldValue();
1083  *  // if neither checkbox is checked
1084  *  v === undefined
1085  *  // if both checkboxes are checked
1086  *  v == ['B1', 'B2']
1087  *
1088  *  var v = $('input[type=radio]').fieldValue();
1089  *  // if neither radio is checked
1090  *  v === undefined
1091  *  // if first radio is checked
1092  *  v == ['C1']
1093  *
1094  * The successful argument controls whether or not the field element must be 'successful'
1095  * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
1096  * The default value of the successful argument is true.  If this value is false the value(s)
1097  * for each element is returned.
1098  *
1099  * Note: This method *always* returns an array.  If no valid value can be determined the
1100  *    array will be empty, otherwise it will contain one or more values.
1101  */
1102 $.fn.fieldValue = function(successful) {
1103     for (var val=[], i=0, max=this.length; i < max; i++) {
1104         var el = this[i];
1105         var v = $.fieldValue(el, successful);
1106         if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
1107             continue;
1108         }
1109         if (v.constructor == Array) {
1110             $.merge(val, v);
1111         }
1112         else {
1113             val.push(v);
1114         }
1115     }
1116     return val;
1117 };
1118 
1119 /**
1120  * Returns the value of the field element.
1121  */
1122 $.fieldValue = function(el, successful) {
1123     var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
1124     if (successful === undefined) {
1125         successful = true;
1126     }
1127 
1128     if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
1129         (t == 'checkbox' || t == 'radio') && !el.checked ||
1130         (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
1131         tag == 'select' && el.selectedIndex == -1)) {
1132             return null;
1133     }
1134 
1135     if (tag == 'select') {
1136         var index = el.selectedIndex;
1137         if (index < 0) {
1138             return null;
1139         }
1140         var a = [], ops = el.options;
1141         var one = (t == 'select-one');
1142         var max = (one ? index+1 : ops.length);
1143         for(var i=(one ? index : 0); i < max; i++) {
1144             var op = ops[i];
1145             if (op.selected) {
1146                 var v = op.value;
1147                 if (!v) { // extra pain for IE...
1148                     v = (op.attributes && op.attributes.value && !(op.attributes.value.specified)) ? op.text : op.value;
1149                 }
1150                 if (one) {
1151                     return v;
1152                 }
1153                 a.push(v);
1154             }
1155         }
1156         return a;
1157     }
1158     return $(el).val();
1159 };
1160 
1161 /**
1162  * Clears the form data.  Takes the following actions on the form's input fields:
1163  *  - input text fields will have their 'value' property set to the empty string
1164  *  - select elements will have their 'selectedIndex' property set to -1
1165  *  - checkbox and radio inputs will have their 'checked' property set to false
1166  *  - inputs of type submit, button, reset, and hidden will *not* be effected
1167  *  - button elements will *not* be effected
1168  */
1169 $.fn.clearForm = function(includeHidden) {
1170     return this.each(function() {
1171         $('input,select,textarea', this).clearFields(includeHidden);
1172     });
1173 };
1174 
1175 /**
1176  * Clears the selected form elements.
1177  */
1178 $.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
1179     var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
1180     return this.each(function() {
1181         var t = this.type, tag = this.tagName.toLowerCase();
1182         if (re.test(t) || tag == 'textarea') {
1183             this.value = '';
1184         }
1185         else if (t == 'checkbox' || t == 'radio') {
1186             this.checked = false;
1187         }
1188         else if (tag == 'select') {
1189             this.selectedIndex = -1;
1190         }
1191         else if (t == "file") {
1192             if (/MSIE/.test(navigator.userAgent)) {
1193                 $(this).replaceWith($(this).clone(true));
1194             } else {
1195                 $(this).val('');
1196             }
1197         }
1198         else if (includeHidden) {
1199             // includeHidden can be the value true, or it can be a selector string
1200             // indicating a special test; for example:
1201             //  $('#myForm').clearForm('.special:hidden')
1202             // the above would clean hidden inputs that have the class of 'special'
1203             if ( (includeHidden === true && /hidden/.test(t)) ||
1204                  (typeof includeHidden == 'string' && $(this).is(includeHidden)) ) {
1205                 this.value = '';
1206             }
1207         }
1208     });
1209 };
1210 
1211 /**
1212  * Resets the form data.  Causes all form elements to be reset to their original value.
1213  */
1214 $.fn.resetForm = function() {
1215     return this.each(function() {
1216         // guard against an input with the name of 'reset'
1217         // note that IE reports the reset function as an 'object'
1218         if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
1219             this.reset();
1220         }
1221     });
1222 };
1223 
1224 /**
1225  * Enables or disables any matching elements.
1226  */
1227 $.fn.enable = function(b) {
1228     if (b === undefined) {
1229         b = true;
1230     }
1231     return this.each(function() {
1232         this.disabled = !b;
1233     });
1234 };
1235 
1236 /**
1237  * Checks/unchecks any matching checkboxes or radio buttons and
1238  * selects/deselects and matching option elements.
1239  */
1240 $.fn.selected = function(select) {
1241     if (select === undefined) {
1242         select = true;
1243     }
1244     return this.each(function() {
1245         var t = this.type;
1246         if (t == 'checkbox' || t == 'radio') {
1247             this.checked = select;
1248         }
1249         else if (this.tagName.toLowerCase() == 'option') {
1250             var $sel = $(this).parent('select');
1251             if (select && $sel[0] && $sel[0].type == 'select-one') {
1252                 // deselect all other options
1253                 $sel.find('option').selected(false);
1254             }
1255             this.selected = select;
1256         }
1257     });
1258 };
1259 
1260 // expose debug var
1261 $.fn.ajaxSubmit.debug = false;
1262 
1263 // helper fn for console logging
1264 function log() {
1265     if (!$.fn.ajaxSubmit.debug) {
1266         return;
1267     }
1268     var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
1269     if (window.console && window.console.log) {
1270         window.console.log(msg);
1271     }
1272     else if (window.opera && window.opera.postError) {
1273         window.opera.postError(msg);
1274     }
1275 }
1276 
1277 }));