PageSourceSearch

https://membership.crn.com.au/Resource/Javascript/jquery.form.js

js crn.com.au collected 2026-10-02 02:20:56 UTC 41,656 bytes, 1,190 lines download raw bytes

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

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.