PageSourceSearch

https://www.kasatria.com/script/jquery.form.js

js kasatria.com collected 2026-10-08 03:27:55 UTC 42,461 bytes, 1,217 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.