source: prototipo_portal_2018/WebContent/js/jquery.form.js @ 36a30d1

Last change on this file since 36a30d1 was 36a30d1, checked in by Pedro Buitrago <pbuitrago@…>, 9 years ago

se agraga los .js y css para la visualización de las tablas en la sección de verificar la firma electronica

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