PageSourceSearch

https://www.tarragona.cat/portal_javascripts/Tarragona%20Theme/res….jquerytools.overlayhelpers-cachekey3983.js

js tarragona.cat collected 2026-09-24 08:52:25 UTC 75,423 bytes, 2,236 lines download raw bytes

1
2/* Merged Plone Javascript file
3 * This file is dynamically assembled from separate parts.
4 * Some of these parts have 3rd party licenses or copyright information attached
5 * Such information is valid for that section,
6 * not for the entire composite file
7 * originating files are separated by - filename.js -
8 */
9
10/* - ++resource++plone.app.jquerytools.overlayhelpers.js - */
11/*****************
12
13   jQuery Tools overlay helpers.
14
15   Copyright © 2010, The Plone Foundation
16   Licensed under the GPL, see LICENSE.txt for details.
17
18*****************/
19
20/*jslint browser: true */
21/*global jQuery, ajax_noresponse_message, close_box_message, window */
22
23// Name space object for pipbox
24var pb = {spinner: {}, overlay_counter: 1};
25
26jQuery.tools.overlay.conf.oneInstance = false;
27
28(function($) {
29    // override jqt default effect to take account of position
30    // of parent elements
31    jQuery.tools.overlay.addEffect('default',
32        function(pos, onLoad) {
33            var conf = this.getConf(),
34                 w = $(window),
35                 ovl = this.getOverlay(),
36                 op = ovl.parent().offsetParent().offset();
37
38            if (!conf.fixed)  {
39                pos.top += w.scrollTop() - op.top;
40                pos.left += w.scrollLeft() - op.left;
41            }
42
43            pos.position = conf.fixed ? 'fixed' : 'absolute';
44            ovl.css(pos).fadeIn(conf.speed, onLoad);
45
46        }, function(onClose) {
47            this.getOverlay().fadeOut(this.getConf().closeSpeed, onClose);
48        }
49    );
50
51    pb.spinner.show = function () {
52        $('body').css('cursor', 'wait');
53    };
54    pb.spinner.hide = function () {
55        $('body').css('cursor', '');
56    };
57}(jQuery));
58
59
60jQuery(function ($) {
61
62    /******
63        $.fn.prepOverlay jQuery plugin to inject overlay target into DOM and
64        annotate it with the data we'll need in order to display it.
65    ******/
66    $.fn.prepOverlay = function (pba) {
67        return this.each(function () {
68            var o, pbo, config, onBeforeLoad, onLoad, src, parts;
69
70            o = $(this);
71
72            // copy options so that it's not just a reference
73            // to the parameter.
74            pbo = $.extend(true, {'width':'60%'}, pba);
75
76            // set overlay configuration
77            config = pbo.config || {};
78
79            // set onBeforeLoad handler
80            onBeforeLoad = pb[pbo.subtype];
81            if (onBeforeLoad) {
82                config.onBeforeLoad = onBeforeLoad;
83            }
84            onLoad = config.onLoad;
85            config.onLoad = function () {
86                if (onLoad) {
87                    onLoad.apply(this, arguments);
88                }
89                pb.fi_focus(this.getOverlay());
90            };
91
92            // be promiscuous, pick up the url from
93            // href, src or action attributes
94            src = o.attr('href') || o.attr('src') || o.attr('action');
95
96            // translate url with config specifications
97            if (pbo.urlmatch) {
98                src = src.replace(new RegExp(pbo.urlmatch), pbo.urlreplace);
99            }
100
101            if (pbo.subtype === 'inline') {
102                // we're going to let tools' overlay do all the real
103                // work. Just get the markers in place.
104                src = src.replace(/^.+#/, '#');
105                $("[id='" + src.replace('#', '') + "']").addClass('overlay');
106                o.removeAttr('href').attr('rel', src);
107                // use overlay on the source (clickable) element
108                o.overlay();
109            } else {
110                // save various bits of information from the pbo options,
111                // and enable the overlay.
112
113                // this is not inline, so in one fashion or another
114                // we'll be loading it via the beforeLoad callback.
115                // create a unique id for a target element
116                pbo.nt = 'pb_' + pb.overlay_counter;
117                pb.overlay_counter += 1;
118
119                pbo.selector = pbo.filter || pbo.selector;
120                if (!pbo.selector) {
121                    // see if one's been supplied in the src
122                    parts = src.split(' ');
123                    src = parts.shift();
124                    pbo.selector = parts.join(' ');
125                }
126
127                pbo.src = src;
128                pbo.config = config;
129                pbo.source = o;
130
131                // remove any existing overlay and overlay handler
132                pb.remove_overlay(o);
133
134                // save options on trigger element
135                o.data('pbo', pbo);
136
137                // mark the source with a rel attribute so we can find
138                // the overlay, and a special class for styling
139                o.attr('rel', '#' + pbo.nt);
140                o.addClass('link-overlay');
141
142                // for some subtypes, we're setting click handlers
143                // and attaching overlay to the target element. That's
144                // so we'll know the dimensions early.
145                // Others, like iframe, just use overlay.
146                switch (pbo.subtype) {
147                case 'image':
148                    o.click(pb.image_click);
149                    break;
150                case 'ajax':
151                    o.click(pb.ajax_click);
152                    break;
153                case 'iframe':
154                    pb.create_content_div(pbo);
155                    o.overlay(config);
156                    break;
157                default:
158                    throw "Unsupported overlay type";
159                }
160
161                // in case the click source wasn't
162                // already a link.
163                o.css('cursor', 'pointer');
164            }
165        });
166    };
167
168
169    /******
170        pb.remove_overlay
171        Remove the overlay and handler associated with a jquery wrapped
172        trigger object
173    ******/
174    pb.remove_overlay = function (o) {
175        var old_data = o.data('pbo');
176        if (old_data) {
177            switch (old_data.subtype) {
178                case 'image':
179                    o.unbind('click', pb.image_click);
180                    break;
181                case 'ajax':
182                    o.unbind('click', pb.ajax_click);
183                    break;
184                default:
185                    // it's probably the jqt overlay click handler,
186                    // but we don't know the handler and are forced
187                    // to do a generic unbind of click handlers.
188                    o.unbind('click');
189                    break;
190            }
191            if (old_data.nt) {
192                $('#' + old_data.nt).remove();
193            }
194        }
195    };
196
197
198    /******
199        pb.create_content_div
200        create a div to act as an overlay; append it to
201        the body; return it
202    ******/
203    pb.create_content_div = function (pbo, trigger) {
204        var content,
205            close_message,
206            pbw = pbo.width;
207
208        if (typeof close_box_message === 'undefined') {
209            close_message = 'Close this box.';
210        } else {
211            close_message = close_box_message;
212        }
213
214        content = $(
215            '<div id="' + pbo.nt +
216            '" class="overlay overlay-' + pbo.subtype +
217            ' ' + (pbo.cssclass || '') +
218            '"><div class="close"><a href="#" class="hiddenStructure" title="Close this box">' +
219            close_message +
220            '</a></div></div>');
221
222        content.data('pbo', pbo);
223
224        // if a width option is specified, set it on the overlay div,
225        // computing against the window width if a % was specified.
226        if (pbw) {
227            if (pbw.indexOf('%') > 0) {
228                content.width(parseInt(pbw, 10) / 100 * $(window).width());
229            } else {
230                content.width(pbw);
231            }
232        }
233
234        // add the target element at the end of the body.
235        content.appendTo($("body"));
236
237        return content;
238    };
239
240
241    /******
242        pb.image_click
243        click handler for image loads
244    ******/
245    pb.image_click = function (event) {
246        var ethis, content, api, img, el, pbo;
247
248        ethis = $(this);
249        pbo = ethis.data('pbo');
250
251        // find target container
252        content = $(ethis.attr('rel'));
253        if (!content.length) {
254            content = pb.create_content_div(pbo);
255            content.overlay(pbo.config);
256        }
257        api = content.overlay();
258
259        // is the image loaded yet?
260        if (content.find('img').length === 0) {
261            // load the image.
262            if (pbo.src) {
263                pb.spinner.show();
264
265                // create the image and stuff it
266                // into our target
267                img = new Image();
268                img.src = pbo.src;
269                el = $(img);
270                content.append(el.addClass('pb-image'));
271
272                // Now, we'll cause the overlay to
273                // load when the image is loaded.
274                el.load(function () {
275                    pb.spinner.hide();
276                    api.load();
277                });
278
279            }
280        } else {
281            api.load();
282        }
283
284        return false;
285    };
286
287
288    /******
289        pb.fi_focus
290        First-input focus inside $ selection.
291    ******/
292    pb.fi_focus = function (jqo) {
293        if (! jqo.find("form div.error :input:first").focus().length) {
294            jqo.find("form :input:visible:first").focus();
295        }
296    };
297
298
299    /******
300        pb.ajax_error_recover
301        jQuery's ajax load function does not load error responses.
302        This routine returns the cooked error response.
303    ******/
304    pb.ajax_error_recover = function (responseText, selector) {
305        var tcontent = $('<div/>').append(
306                responseText.replace(/<script(.|\s)*?\/script>/gi, ""));
307        return selector ? tcontent.find(selector) : tcontent;
308    };
309
310
311    /******
312        pb.add_ajax_load
313        Adds a hidden ajax_load input to form
314    ******/
315    pb.add_ajax_load = function (form) {
316        if (form.find('input[name=ajax_load]').length === 0) {
317            form.prepend($('<input type="hidden" name="ajax_load" value="' +
318                (new Date().getTime()) +
319                '" />'));
320        }
321    };
322
323    /******
324        pb.prep_ajax_form
325        Set up form with ajaxForm, including success and error handlers.
326    ******/
327    pb.prep_ajax_form = function (form) {
328        var ajax_parent = form.closest('.pb-ajax'),
329            data_parent = ajax_parent.closest('.overlay-ajax'),
330            pbo = data_parent.data('pbo'),
331            formtarget = pbo.formselector,
332            closeselector = pbo.closeselector,
333            beforepost = pbo.beforepost,
334            afterpost = pbo.afterpost,
335            noform = pbo.noform,
336            api = data_parent.overlay(),
337            selector = pbo.selector,
338            options = {};
339
340        options.beforeSerialize = function () {
341            pb.spinner.show();
342        };
343
344        if (beforepost) {
345            options.beforeSubmit = function (arr, form, options) {
346                return beforepost(form, arr, options);
347            };
348        }
349        options.success = function (responseText, statusText, xhr, form) {
350            $(document).trigger('formOverlayStart', [this, responseText, statusText, xhr, form]);
351            // success comes in many forms, some of which are errors;
352            //
353
354            var el, myform, success, target, scripts = [], filteredResponseText;
355
356            success = statusText === "success" || statusText === "notmodified";
357
358            if (! success) {
359                // The responseText parameter is actually xhr
360                responseText = responseText.responseText;
361            }
362            // strip inline script tags
363            filteredResponseText = responseText.replace(/<script(.|\s)*?\/script>/gi, "");
364
365            // create a div containing the optionally filtered response
366            el = $('<div />').append(
367                selector ?
368                    // a lesson learned from the jQuery source: $(responseText)
369                    // will not work well unless responseText is well-formed;
370                    // appending to a div is more robust, and automagically
371                    // removes the html/head/body outer tagging.
372                    $('<div />').append(filteredResponseText).find(selector)
373                    :
374                    filteredResponseText
375                );
376
377            // afterpost callback
378            if (success && afterpost) {
379                afterpost(el, data_parent);
380            }
381
382            myform = el.find(formtarget);
383            if (success && myform.length) {
384                ajax_parent.empty().append(el);
385
386                // execute inline scripts
387                try {
388                    // jQuery 1.7
389                    $.buildFragment([responseText], [document], scripts);
390                } catch (e) {
391                    // jQuery 1.9
392                    $.buildFragment([responseText], document, scripts);
393                }
394                if (scripts.length) {
395                    $.each(scripts, function() {
396                        $.globalEval( this.text || this.textContent || this.innerHTML || "" );
397                    });
398                }
399
400                // This may be a complex form.
401                if ($.fn.ploneTabInit) {
402                    el.ploneTabInit();
403                }
404                pb.fi_focus(ajax_parent);
405
406                pb.add_ajax_load(myform);
407                // attach submit handler with the same options
408                myform.ajaxForm(options);
409
410                // attach close to element id'd by closeselector
411                if (closeselector) {
412                    el.find(closeselector).click(function (event) {
413                        api.close();
414                        return false;
415                    });
416                }
417                $(document).trigger('formOverlayLoadSuccess', [this, myform, api, pb, ajax_parent]);
418            } else {
419                // there's no form in our new content or there's been an error
420                if (success) {
421                    if (typeof noform === "function") {
422                        // get action from callback
423                        noform = noform(el, pbo);
424                    }
425                } else {
426                    noform = statusText;
427                }
428
429
430                switch (noform) {
431                case 'close':
432                    api.close();
433                    break;
434                case 'reload':
435                    api.close();
436                    pb.spinner.show();
437                    // location.reload results in a repost
438                    // dialog in some browsers; very unlikely to
439                    // be what we want.
440                    location.replace(location.href);
441                    break;
442                case 'redirect':
443                    api.close();
444                    pb.spinner.show();
445                    target = pbo.redirect;
446                    if (typeof target === "function") {
447                        // get target from callback
448                        target = target(el, responseText, pbo);
449                    }
450                    location.replace(target);
451                    break;
452                default:
453                    if (el.children()) {
454                        // show what we've got
455                        ajax_parent.empty().append(el);
456                    } else {
457                        api.close();
458                    }
459                    break;
460                }
461                $(document).trigger('formOverlayLoadFailure', [this, myform, api, pb, ajax_parent, noform]);
462            }
463            pb.spinner.hide();
464        };
465        // error and success callbacks are the same
466        options.error = options.success;
467
468        pb.add_ajax_load(form);
469        form.ajaxForm(options);
470    };
471
472
473    /******
474        pb.ajax_click
475        Click handler for ajax sources. The job of this routine
476        is to do the ajax load of the overlay element, then
477        call the JQT overlay loader.
478    ******/
479    pb.ajax_click = function (event) {
480        var ethis = $(this),
481            pbo,
482            content,
483            api,
484            src,
485            el,
486            selector,
487            formtarget,
488            closeselector,
489            sep,
490            scripts = [],
491            e;
492
493        e = $.Event();
494        e.type = "beforeAjaxClickHandled";
495        $(document).trigger(e, [this, event]);
496        if (e.isDefaultPrevented()) { return false; }
497
498        pbo = ethis.data('pbo');
499
500        content = pb.create_content_div(pbo, ethis);
501        // pbo.config.top = $(window).height() * 0.1 - ethis.offsetParent().offset().top;
502        content.overlay(pbo.config, ethis);
503        api = content.overlay();
504        src = pbo.src;
505        selector = pbo.selector;
506        formtarget = pbo.formselector;
507        closeselector = pbo.closeselector;
508
509        pb.spinner.show();
510
511        // prevent double click warning for this form
512        $(this).find("input.submitting").removeClass('submitting');
513
514        el = $('div.pb-ajax', content);
515        if (el.length === 0) {
516            el = $('<div class="pb-ajax" />');
517            content.append(el);
518        }
519        if (api.getConf().fixed) {
520            // don't let it be over 75% of the viewport's height
521            el.css('max-height', Math.floor($(window).height() * 0.75));
522        }
523
524        // affix a random query argument to prevent
525        // loading from browser cache
526        sep = (src.indexOf('?') >= 0) ? '&': '?';
527        src += sep + "ajax_load=" + (new Date().getTime());
528
529        // add selector, if any
530        if (selector) {
531            src += ' ' + selector;
532        }
533
534        // set up callback to be used whenever new contents are loaded
535        // into the overlay, to prepare links and forms to stay within
536        // the overlay
537        el[0].handle_load_inside_overlay = function(responseText, errorText) {
538            var ele, target;
539            ele = $(this);
540
541            if (errorText === 'error') {
542                ele.append(pb.ajax_error_recover(responseText, selector));
543            } else if (!responseText.length) {
544                ele.append(ajax_noresponse_message || 'No response from server.');
545            }
546
547            // a non-semantic div here will make sure we can
548            // do enough formatting.
549            ele.wrapInner('<div />');
550
551            // add the submit handler if we've a formtarget
552            if (formtarget) {
553                target = ele.find(formtarget);
554                if (target.length > 0) {
555                    pb.prep_ajax_form(target);
556                }
557            }
558
559            // if a closeselector has been specified, tie it to the overlay's
560            // close method via closure
561            if (closeselector) {
562                ele.find(closeselector).click(function (event) {
563                    api.close();
564                    return false;
565                });
566            }
567
568            // execute inline scripts
569            try {
570                // jQuery 1.7
571                $.buildFragment([responseText], [document], scripts);
572            } catch (e) {
573                // jQuery 1.9
574                $.buildFragment([responseText], document, scripts);
575            }
576            if (scripts.length) {
577                $.each(scripts, function() {
578                    $.globalEval( this.text || this.textContent || this.innerHTML || "" );
579                });
580            }
581
582            // This may be a complex form.
583            if ($.fn.ploneTabInit) {
584                ele.ploneTabInit();
585            }
586
587            // remove element on close so that it doesn't congest the DOM
588            api.onClose = function () {
589                content.remove();
590            };
591            $(document).trigger('loadInsideOverlay', [this, responseText, errorText, api]);
592        };
593
594        // and load the div
595        el.load(src, null, function (responseText, errorText) {
596            // post-process the overlay contents
597            el[0].handle_load_inside_overlay.apply(this, [responseText, errorText]);
598
599            // Now, it's all ready to display; hide the
600            // spinner and call JQT overlay load.
601            pb.spinner.hide();
602            api.load();
603
604            return true;
605        });
606
607        // don't do the default action
608        return false;
609    };
610
611
612    /******
613        pb.iframe
614        onBeforeLoad handler for iframe overlays.
615
616        Note that the spinner is handled a little differently
617        so that we can keep it displayed while the iframe's
618        content is loading.
619    ******/
620    pb.iframe = function () {
621        var content, pbo;
622
623        pb.spinner.show();
624
625        content = this.getOverlay();
626        pbo = this.getTrigger().data('pbo');
627
628        if (content.find('iframe').length === 0 && pbo.src) {
629            content.append(
630                '<iframe src="' + pbo.src + '" width="' +
631                 content.width() + '" height="' + content.height() +
632                 '" onload="pb.spinner.hide()"/>');
633        } else {
634            pb.spinner.hide();
635        }
636        return true;
637    };
638
639});
640
641
642/* - ++resource++plone.app.jquerytools.form.js - */
643/*!
644 * jQuery Form Plugin
645 * version: 3.51.0-2014.06.20
646 * Requires jQuery v1.5 or later
647 * Copyright (c) 2014 M. Alsup
648 * Examples and documentation at: http://malsup.com/jquery/form/
649 * Project repository: https://github.com/malsup/form
650 * Dual licensed under the MIT and GPL licenses.
651 * https://github.com/malsup/form#copyright-and-license
652 */
653/*global ActiveXObject */
654
655
656
657/*
658    Usage Note:
659    -----------
660    Do not use both ajaxSubmit and ajaxForm on the same form.  These
661    functions are mutually exclusive.  Use ajaxSubmit if you want
662    to bind your own submit handler to the form.  For example,
663
664    $(document).ready(function() {
665        $('#myForm').on('submit', function(e) {
666            e.preventDefault(); // <-- important
667            $(this).ajaxSubmit({
668                target: '#output'
669            });
670        });
671    });
672
673    Use ajaxForm when you want the plugin to manage all the event binding
674    for you.  For example,
675
676    $(document).ready(function() {
677        $('#myForm').ajaxForm({
678            target: '#output'
679        });
680    });
681
682    You can also use ajaxForm with delegation (requires jQuery v1.7+), so the
683    form does not have to exist when you invoke ajaxForm:
684
685    $('#myForm').ajaxForm({
686        delegation: true,
687        target: '#output'
688    });
689
690    When using ajaxForm, the ajaxSubmit function will be invoked for you
691    at the appropriate time.
692*/
693
694jQuery( document ).ready(function( $ ) {
695
696/**
697 * Feature detection
698 */
699var feature = {};
700feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
701feature.formdata = window.FormData !== undefined;
702
703var hasProp = !!$.fn.prop;
704
705// attr2 uses prop when it can but checks the return type for
706// an expected string.  this accounts for the case where a form 
707// contains inputs with names like "action" or "method"; in those
708// cases "prop" returns the element
709$.fn.attr2 = function() {
710    if ( ! hasProp ) {
711        return this.attr.apply(this, arguments);
712    }
713    var val = this.prop.apply(this, arguments);
714    if ( ( val && val.jquery ) || typeof val === 'string' ) {
715        return val;
716    }
717    return this.attr.apply(this, arguments);
718};
719
720/**
721 * ajaxSubmit() provides a mechanism for immediately submitting
722 * an HTML form using AJAX.
723 */
724$.fn.ajaxSubmit = function(options) {
725    /*jshint scripturl:true */
726
727    // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
728    if (!this.length) {
729        log('ajaxSubmit: skipping submit process - no element selected');
730        return this;
731    }
732
733    var method, action, url, $form = this;
734
735    if (typeof options == 'function') {
736        options = { success: options };
737    }
738    else if ( options === undefined ) {
739        options = {};
740    }
741
742    method = options.type || this.attr2('method');
743    action = options.url  || this.attr2('action');
744
745    url = (typeof action === 'string') ? $.trim(action) : '';
746    url = url || window.location.href || '';
747    if (url) {
748        // clean url (don't include hash vaue)
749        url = (url.match(/^([^#]+)/)||[])[1];
750    }
751
752    options = $.extend(true, {
753        url:  url,
754        success: $.ajaxSettings.success,
755        type: method || $.ajaxSettings.type,
756        iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
757    }, options);
758
759    // hook for manipulating the form data before it is extracted;
760    // convenient for use with rich editors like tinyMCE or FCKEditor
761    var veto = {};
762    this.trigger('form-pre-serialize', [this, options, veto]);
763    if (veto.veto) {
764        log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
765        return this;
766    }
767
768    // provide opportunity to alter form data before it is serialized
769    if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
770        log('ajaxSubmit: submit aborted via beforeSerialize callback');
771        return this;
772    }
773
774    var traditional = options.traditional;
775    if ( traditional === undefined ) {
776        traditional = $.ajaxSettings.traditional;
777    }
778
779    var elements = [];
780    var qx, a = this.formToArray(options.semantic, elements);
781    if (options.data) {
782        options.extraData = options.data;
783        qx = $.param(options.data, traditional);
784    }
785
786    // give pre-submit callback an opportunity to abort the submit
787    if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
788        log('ajaxSubmit: submit aborted via beforeSubmit callback');
789        return this;
790    }
791
792    // fire vetoable 'validate' event
793    this.trigger('form-submit-validate', [a, this, options, veto]);
794    if (veto.veto) {
795        log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
796        return this;
797    }
798
799    var q = $.param(a, traditional);
800    if (qx) {
801        q = ( q ? (q + '&' + qx) : qx );
802    }
803    if (options.type.toUpperCase() == 'GET') {
804        options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
805        options.data = null;  // data is null for 'get'
806    }
807    else {
808        options.data = q; // data is the query string for 'post'
809    }
810
811    var callbacks = [];
812    if (options.resetForm) {
813        callbacks.push(function() { $form.resetForm(); });
814    }
815    if (options.clearForm) {
816        callbacks.push(function() { $form.clearForm(options.includeHidden); });
817    }
818
819    // perform a load on the target only if dataType is not provided
820    if (!options.dataType && options.target) {
821        var oldSuccess = options.success || function(){};
822        callbacks.push(function(data) {
823            var fn = options.replaceTarget ? 'replaceWith' : 'html';
824            $(options.target)[fn](data).each(oldSuccess, arguments);
825        });
826    }
827    else if (options.success) {
828        callbacks.push(options.success);
829    }
830
831    options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
832        var context = options.context || this ;    // jQuery 1.4+ supports scope context
833        for (var i=0, max=callbacks.length; i < max; i++) {
834            callbacks[i].apply(context, [data, status, xhr || $form, $form]);
835        }
836    };
837
838    if (options.error) {
839        var oldError = options.error;
840        options.error = function(xhr, status, error) {
841            var context = options.context || this;
842            oldError.apply(context, [xhr, status, error, $form]);
843        };
844    }
845
846     if (options.complete) {
847        var oldComplete = options.complete;
848        options.complete = function(xhr, status) {
849            var context = options.context || this;
850            oldComplete.apply(context, [xhr, status, $form]);
851        };
852    }
853
854    // are there files to upload?
855
856    // [value] (issue #113), also see comment:
857    // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219
858    var fileInputs = $('input[type=file]:enabled', this).filter(function() { return $(this).val() !== ''; });
859
860    var hasFileInputs = fileInputs.length > 0;
861    var mp = 'multipart/form-data';
862    var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
863
864    var fileAPI = feature.fileapi && feature.formdata;
865    log("fileAPI :" + fileAPI);
866    var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;
867
868    var jqxhr;
869
870    // options.iframe allows user to force iframe mode
871    // 06-NOV-09: now defaulting to iframe mode if file input is detected
872    if (options.iframe !== false && (options.iframe || shouldUseFrame)) {
873        // hack to fix Safari hang (thanks to Tim Molendijk for this)
874        // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
875        if (options.closeKeepAlive) {
876            $.get(options.closeKeepAlive, function() {
877                jqxhr = fileUploadIframe(a);
878            });
879        }
880        else {
881            jqxhr = fileUploadIframe(a);
882        }
883    }
884    else if ((hasFileInputs || multipart) && fileAPI) {
885        jqxhr = fileUploadXhr(a);
886    }
887    else {
888        jqxhr = $.ajax(options);
889    }
890
891    $form.removeData('jqxhr').data('jqxhr', jqxhr);
892
893    // clear element array
894    for (var k=0; k < elements.length; k++) {
895        elements[k] = null;
896    }
897
898    // fire 'notify' event
899    this.trigger('form-submit-notify', [this, options]);
900    return this;
901
902    // utility fn for deep serialization
903    function deepSerialize(extraData){
904        var serialized = $.param(extraData, options.traditional).split('&');
905        var len = serialized.length;
906        var result = [];
907        var i, part;
908        for (i=0; i < len; i++) {
909            // #252; undo param space replacement
910            serialized[i] = serialized[i].replace(/\+/g,' ');
911            part = serialized[i].split('=');
912            // #278; use array instead of object storage, favoring array serializations
913            result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]);
914        }
915        return result;
916    }
917
918     // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
919    function fileUploadXhr(a) {
920        var formdata = new FormData();
921
922        for (var i=0; i < a.length; i++) {
923            formdata.append(a[i].name, a[i].value);
924        }
925
926        if (options.extraData) {
927            var serializedData = deepSerialize(options.extraData);
928            for (i=0; i < serializedData.length; i++) {
929                if (serializedData[i]) {
930                    formdata.append(serializedData[i][0], serializedData[i][1]);
931                }
932            }
933        }
934
935        options.data = null;
936
937        var s = $.extend(true, {}, $.ajaxSettings, options, {
938            contentType: false,
939            processData: false,
940            cache: false,
941            type: method || 'POST'
942        });
943
944        if (options.uploadProgress) {
945            // workaround because jqXHR does not expose upload property
946            s.xhr = function() {
947                var xhr = $.ajaxSettings.xhr();
948                if (xhr.upload) {
949                    xhr.upload.addEventListener('progress', function(event) {
950                        var percent = 0;
951                        var position = event.loaded || event.position; /*event.position is deprecated*/
952                        var total = event.total;
953                        if (event.lengthComputable) {
954                            percent = Math.ceil(position / total * 100);
955                        }
956                        options.uploadProgress(event, position, total, percent);
957                    }, false);
958                }
959                return xhr;
960            };
961        }
962
963        s.data = null;
964        var beforeSend = s.beforeSend;
965        s.beforeSend = function(xhr, o) {
966            //Send FormData() provided by user
967            if (options.formData) {
968                o.data = options.formData;
969            }
970            else {
971                o.data = formdata;
972            }
973            if(beforeSend) {
974                beforeSend.call(this, xhr, o);
975            }
976        };
977        return $.ajax(s);
978    }
979
980    // private function for handling file uploads (hat tip to YAHOO!)
981    function fileUploadIframe(a) {
982        var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
983        var deferred = $.Deferred();
984
985        // #341
986        deferred.abort = function(status) {
987            xhr.abort(status);
988        };
989
990        if (a) {
991            // ensure that every serialized input is still enabled
992            for (i=0; i < elements.length; i++) {
993                el = $(elements[i]);
994                if ( hasProp ) {
995                    el.prop('disabled', false);
996                }
997                else {
998                    el.removeAttr('disabled');
999                }
1000            }
1001        }
1002
1003        s = $.extend(true, {}, $.ajaxSettings, options);
1004        s.context = s.context || s;
1005        id = 'jqFormIO' + (new Date().getTime());
1006        if (s.iframeTarget) {
1007            $io = $(s.iframeTarget);
1008            n = $io.attr2('name');
1009            if (!n) {
1010                $io.attr2('name', id);
1011            }
1012            else {
1013                id = n;
1014            }
1015        }
1016        else {
1017            $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
1018            $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
1019        }
1020        io = $io[0];
1021
1022
1023        xhr = { // mock object
1024            aborted: 0,
1025            responseText: null,
1026            responseXML: null,
1027            status: 0,
1028            statusText: 'n/a',
1029            getAllResponseHeaders: function() {},
1030            getResponseHeader: function() {},
1031            setRequestHeader: function() {},
1032            abort: function(status) {
1033                var e = (status === 'timeout' ? 'timeout' : 'aborted');
1034                log('aborting upload... ' + e);
1035                this.aborted = 1;
1036
1037                try { // #214, #257
1038                    if (io.contentWindow.document.execCommand) {
1039                        io.contentWindow.document.execCommand('Stop');
1040                    }
1041                }
1042                catch(ignore) {}
1043
1044                $io.attr('src', s.iframeSrc); // abort op in progress
1045                xhr.error = e;
1046                if (s.error) {
1047                    s.error.call(s.context, xhr, e, status);
1048                }
1049                if (g) {
1050                    $.event.trigger("ajaxError", [xhr, s, e]);
1051                }
1052                if (s.complete) {
1053                    s.complete.call(s.context, xhr, e);
1054                }
1055            }
1056        };
1057
1058        g = s.global;
1059        // trigger ajax global events so that activity/block indicators work like normal
1060        if (g && 0 === $.active++) {
1061            $.event.trigger("ajaxStart");
1062        }
1063        if (g) {
1064            $.event.trigger("ajaxSend", [xhr, s]);
1065        }
1066
1067        if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
1068            if (s.global) {
1069                $.active--;
1070            }
1071            deferred.reject();
1072            return deferred;
1073        }
1074        if (xhr.aborted) {
1075            deferred.reject();
1076            return deferred;
1077        }
1078
1079        // add submitting element to data if we know it
1080        sub = form.clk;
1081        if (sub) {
1082            n = sub.name;
1083            if (n && !sub.disabled) {
1084                s.extraData = s.extraData || {};
1085                s.extraData[n] = sub.value;
1086                if (sub.type == "image") {
1087                    s.extraData[n+'.x'] = form.clk_x;
1088                    s.extraData[n+'.y'] = form.clk_y;
1089                }
1090            }
1091        }
1092
1093        var CLIENT_TIMEOUT_ABORT = 1;
1094        var SERVER_ABORT = 2;
1095                
1096        function getDoc(frame) {
1097            /* it looks like contentWindow or contentDocument do not
1098             * carry the protocol property in ie8, when running under ssl
1099             * frame.document is the only valid response document, since
1100             * the protocol is know but not on the other two objects. strange?
1101             * "Same origin policy" http://en.wikipedia.org/wiki/Same_origin_policy
1102             */
1103            
1104            var doc = null;
1105            
1106            // IE8 cascading access check
1107            try {
1108                if (frame.contentWindow) {
1109                    doc = frame.contentWindow.document;
1110                }
1111            } catch(err) {
1112                // IE8 access denied under ssl & missing protocol
1113                log('cannot get iframe.contentWindow document: ' + err);
1114            }
1115
1116            if (doc) { // successful getting content
1117                return doc;
1118            }
1119
1120            try { // simply checking may throw in ie8 under ssl or mismatched protocol
1121                doc = frame.contentDocument ? frame.contentDocument : frame.document;
1122            } catch(err) {
1123                // last attempt
1124                log('cannot get iframe.contentDocument: ' + err);
1125                doc = frame.document;
1126            }
1127            return doc;
1128        }
1129
1130        // Rails CSRF hack (thanks to Yvan Barthelemy)
1131        var csrf_token = $('meta[name=csrf-token]').attr('content');
1132        var csrf_param = $('meta[name=csrf-param]').attr('content');
1133        if (csrf_param && csrf_token) {
1134            s.extraData = s.extraData || {};
1135            s.extraData[csrf_param] = csrf_token;
1136        }
1137
1138        // take a breath so that pending repaints get some cpu time before the upload starts
1139        function doSubmit() {
1140            // make sure form attrs are set
1141            var t = $form.attr2('target'), 
1142                a = $form.attr2('action'), 
1143                mp = 'multipart/form-data',
1144                et = $form.attr('enctype') || $form.attr('encoding') || mp;
1145
1146            // update form attrs in IE friendly way
1147            form.setAttribute('target',id);
1148            if (!method || /post/i.test(method) ) {
1149                form.setAttribute('method', 'POST');
1150            }
1151            if (a != s.url) {
1152                form.setAttribute('action', s.url);
1153            }
1154
1155            // ie borks in some cases when setting encoding
1156            if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
1157                $form.attr({
1158                    encoding: 'multipart/form-data',
1159                    enctype:  'multipart/form-data'
1160                });
1161            }
1162
1163            // support timout
1164            if (s.timeout) {
1165                timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
1166            }
1167
1168            // look for server aborts
1169            function checkState() {
1170                try {
1171                    var state = getDoc(io).readyState;
1172                    log('state = ' + state);
1173                    if (state && state.toLowerCase() == 'uninitialized') {
1174                        setTimeout(checkState,50);
1175                    }
1176                }
1177                catch(e) {
1178                    log('Server abort: ' , e, ' (', e.name, ')');
1179                    cb(SERVER_ABORT);
1180                    if (timeoutHandle) {
1181                        clearTimeout(timeoutHandle);
1182                    }
1183                    timeoutHandle = undefined;
1184                }
1185            }
1186
1187            // add "extra" data to form if provided in options
1188            var extraInputs = [];
1189            try {
1190                if (s.extraData) {
1191                    for (var n in s.extraData) {
1192                        if (s.extraData.hasOwnProperty(n)) {
1193                           // if using the $.param format that allows for multiple values with the same name
1194                           if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {
1195                               extraInputs.push(
1196                               $('<input type="hidden" name="'+s.extraData[n].name+'">').val(s.extraData[n].value)
1197                                   .appendTo(form)[0]);
1198                           } else {
1199                               extraInputs.push(
1200                               $('<input type="hidden" name="'+n+'">').val(s.extraData[n])
1201                                   .appendTo(form)[0]);
1202                           }
1203                        }
1204                    }
1205                }
1206
1207                if (!s.iframeTarget) {
1208                    // add iframe to doc and submit the form
1209                    $io.appendTo('body');
1210                }
1211                if (io.attachEvent) {
1212                    io.attachEvent('onload', cb);
1213                }
1214                else {
1215                    io.addEventListener('load', cb, false);
1216                }
1217                setTimeout(checkState,15);
1218
1219                try {
1220                    form.submit();
1221                } catch(err) {
1222                    // just in case form has element with name/id of 'submit'
1223                    var submitFn = document.createElement('form').submit;
1224                    submitFn.apply(form);
1225                }
1226            }
1227            finally {
1228                // reset attrs and remove "extra" input elements
1229                form.setAttribute('action',a);
1230                form.setAttribute('enctype', et); // #380
1231                if(t) {
1232                    form.setAttribute('target', t);
1233                } else {
1234                    $form.removeAttr('target');
1235                }
1236                $(extraInputs).remove();
1237            }
1238        }
1239
1240        if (s.forceSync) {
1241            doSubmit();
1242        }
1243        else {
1244            setTimeout(doSubmit, 10); // this lets dom updates render
1245        }
1246
1247        var data, doc, domCheckCount = 50, callbackProcessed;
1248
1249        function cb(e) {
1250            if (xhr.aborted || callbackProcessed) {
1251                return;
1252            }
1253            
1254            doc = getDoc(io);
1255            if(!doc) {
1256                log('cannot access response document');
1257                e = SERVER_ABORT;
1258            }
1259            if (e === CLIENT_TIMEOUT_ABORT && xhr) {
1260                xhr.abort('timeout');
1261                deferred.reject(xhr, 'timeout');
1262                return;
1263            }
1264            else if (e == SERVER_ABORT && xhr) {
1265                xhr.abort('server abort');
1266                deferred.reject(xhr, 'error', 'server abort');
1267                return;
1268            }
1269
1270            if (!doc || doc.location.href == s.iframeSrc) {
1271                // response not received yet
1272                if (!timedOut) {
1273                    return;
1274                }
1275            }
1276            if (io.detachEvent) {
1277                io.detachEvent('onload', cb);
1278            }
1279            else {
1280                io.removeEventListener('load', cb, false);
1281            }
1282
1283            var status = 'success', errMsg;
1284            try {
1285                if (timedOut) {
1286                    throw 'timeout';
1287                }
1288
1289                var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
1290                log('isXml='+isXml);
1291                if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {
1292                    if (--domCheckCount) {
1293                        // in some browsers (Opera) the iframe DOM is not always traversable when
1294                        // the onload callback fires, so we loop a bit to accommodate
1295                        log('requeing onLoad callback, DOM not available');
1296                        setTimeout(cb, 250);
1297                        return;
1298                    }
1299                    // let this fall through because server response could be an empty document
1300                    //log('Could not access iframe DOM after mutiple tries.');
1301                    //throw 'DOMException: not available';
1302                }
1303
1304                //log('response detected');
1305                var docRoot = doc.body ? doc.body : doc.documentElement;
1306                xhr.responseText = docRoot ? docRoot.innerHTML : null;
1307                xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
1308                if (isXml) {
1309                    s.dataType = 'xml';
1310                }
1311                xhr.getResponseHeader = function(header){
1312                    var headers = {'content-type': s.dataType};
1313                    return headers[header.toLowerCase()];
1314                };
1315                // support for XHR 'status' & 'statusText' emulation :
1316                if (docRoot) {
1317                    xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
1318                    xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
1319                }
1320
1321                var dt = (s.dataType || '').toLowerCase();
1322                var scr = /(json|script|text)/.test(dt);
1323                if (scr || s.textarea) {
1324                    // see if user embedded response in textarea
1325                    var ta = doc.getElementsByTagName('textarea')[0];
1326                    if (ta) {
1327                        xhr.responseText = ta.value;
1328                        // support for XHR 'status' & 'statusText' emulation :
1329                        xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
1330                        xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
1331                    }
1332                    else if (scr) {
1333                        // account for browsers injecting pre around json response
1334                        var pre = doc.getElementsByTagName('pre')[0];
1335                        var b = doc.getElementsByTagName('body')[0];
1336                        if (pre) {
1337                            xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;
1338                        }
1339                        else if (b) {
1340                            xhr.responseText = b.textContent ? b.textContent : b.innerText;
1341                        }
1342                    }
1343                }
1344                else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) {
1345                    xhr.responseXML = toXml(xhr.responseText);
1346                }
1347
1348                try {
1349                    data = httpData(xhr, dt, s);
1350                }
1351                catch (err) {
1352                    status = 'parsererror';
1353                    xhr.error = errMsg = (err || status);
1354                }
1355            }
1356            catch (err) {
1357                log('error caught: ',err);
1358                status = 'error';
1359                xhr.error = errMsg = (err || status);
1360            }
1361
1362            if (xhr.aborted) {
1363                log('upload aborted');
1364                status = null;
1365            }
1366
1367            if (xhr.status) { // we've set xhr.status
1368                status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
1369            }
1370
1371            // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
1372            if (status === 'success') {
1373                if (s.success) {
1374                    s.success.call(s.context, data, 'success', xhr);
1375                }
1376                deferred.resolve(xhr.responseText, 'success', xhr);
1377                if (g) {
1378                    $.event.trigger("ajaxSuccess", [xhr, s]);
1379                }
1380            }
1381            else if (status) {
1382                if (errMsg === undefined) {
1383                    errMsg = xhr.statusText;
1384                }
1385                if (s.error) {
1386                    s.error.call(s.context, xhr, status, errMsg);
1387                }
1388                deferred.reject(xhr, 'error', errMsg);
1389                if (g) {
1390                    $.event.trigger("ajaxError", [xhr, s, errMsg]);
1391                }
1392            }
1393
1394            if (g) {
1395                $.event.trigger("ajaxComplete", [xhr, s]);
1396            }
1397
1398            if (g && ! --$.active) {
1399                $.event.trigger("ajaxStop");
1400            }
1401
1402            if (s.complete) {
1403                s.complete.call(s.context, xhr, status);
1404            }
1405
1406            callbackProcessed = true;
1407            if (s.timeout) {
1408                clearTimeout(timeoutHandle);
1409            }
1410
1411            // clean up
1412            setTimeout(function() {
1413                if (!s.iframeTarget) {
1414                    $io.remove();
1415                }
1416                else { //adding else to clean up existing iframe response.
1417                    $io.attr('src', s.iframeSrc);
1418                }
1419                xhr.responseXML = null;
1420            }, 100);
1421        }
1422
1423        var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
1424            if (window.ActiveXObject) {
1425                doc = new ActiveXObject('Microsoft.XMLDOM');
1426                doc.async = 'false';
1427                doc.loadXML(s);
1428            }
1429            else {
1430                doc = (new DOMParser()).parseFromString(s, 'text/xml');
1431            }
1432            return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
1433        };
1434        var parseJSON = $.parseJSON || function(s) {
1435            /*jslint evil:true */
1436            return window['eval']('(' + s + ')');
1437        };
1438
1439        var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
1440
1441            var ct = xhr.getResponseHeader('content-type') || '',
1442                xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
1443                data = xml ? xhr.responseXML : xhr.responseText;
1444
1445            if (xml && data.documentElement.nodeName === 'parsererror') {
1446                if ($.error) {
1447                    $.error('parsererror');
1448                }
1449            }
1450            if (s && s.dataFilter) {
1451                data = s.dataFilter(data, type);
1452            }
1453            if (typeof data === 'string') {
1454                if (type === 'json' || !type && ct.indexOf('json') >= 0) {
1455                    data = parseJSON(data);
1456                } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
1457                    $.globalEval(data);
1458                }
1459            }
1460            return data;
1461        };
1462
1463        return deferred;
1464    }
1465};
1466
1467/**
1468 * ajaxForm() provides a mechanism for fully automating form submission.
1469 *
1470 * The advantages of using this method instead of ajaxSubmit() are:
1471 *
1472 * 1: This method will include coordinates for <input type="image" /> elements (if the element
1473 *    is used to submit the form).
1474 * 2. This method will include the submit element's name/value data (for the element that was
1475 *    used to submit the form).
1476 * 3. This method binds the submit() method to the form for you.
1477 *
1478 * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
1479 * passes the options argument along after properly binding events for submit elements and
1480 * the form itself.
1481 */
1482$.fn.ajaxForm = function(options) {
1483    options = options || {};
1484    options.delegation = options.delegation && $.isFunction($.fn.on);
1485
1486    // in jQuery 1.3+ we can fix mistakes with the ready state
1487    if (!options.delegation && this.length === 0) {
1488        var o = { s: this.selector, c: this.context };
1489        if (!$.isReady && o.s) {
1490            log('DOM not ready, queuing ajaxForm');
1491            $(function() {
1492                $(o.s,o.c).ajaxForm(options);
1493            });
1494            return this;
1495        }
1496        // is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
1497        log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
1498        return this;
1499    }
1500
1501    if ( options.delegation ) {
1502        $(document)
1503            .off('submit.form-plugin', this.selector, doAjaxSubmit)
1504            .off('click.form-plugin', this.selector, captureSubmittingElement)
1505            .on('submit.form-plugin', this.selector, options, doAjaxSubmit)
1506            .on('click.form-plugin', this.selector, options, captureSubmittingElement);
1507        return this;
1508    }
1509
1510    return this.ajaxFormUnbind()
1511        .bind('submit.form-plugin', options, doAjaxSubmit)
1512        .bind('click.form-plugin', options, captureSubmittingElement);
1513};
1514
1515// private event handlers
1516function doAjaxSubmit(e) {
1517    /*jshint validthis:true */
1518    var options = e.data;
1519    if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
1520        e.preventDefault();
1521        $(e.target).ajaxSubmit(options); // #365
1522    }
1523}
1524
1525function captureSubmittingElement(e) {
1526    /*jshint validthis:true */
1527    var target = e.target;
1528    var $el = $(target);
1529    if (!($el.is("[type=submit],[type=image]"))) {
1530        // is this a child element of the submit el?  (ex: a span within a button)
1531        var t = $el.closest('[type=submit]');
1532        if (t.length === 0) {
1533            return;
1534        }
1535        target = t[0];
1536    }
1537    var form = this;
1538    form.clk = target;
1539    if (target.type == 'image') {
1540        if (e.offsetX !== undefined) {
1541            form.clk_x = e.offsetX;
1542            form.clk_y = e.offsetY;
1543        } else if (typeof $.fn.offset == 'function') {
1544            var offset = $el.offset();
1545            form.clk_x = e.pageX - offset.left;
1546            form.clk_y = e.pageY - offset.top;
1547        } else {
1548            form.clk_x = e.pageX - target.offsetLeft;
1549            form.clk_y = e.pageY - target.offsetTop;
1550        }
1551    }
1552    // clear form vars
1553    setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
1554}
1555
1556
1557// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
1558$.fn.ajaxFormUnbind = function() {
1559    return this.unbind('submit.form-plugin click.form-plugin');
1560};
1561
1562/**
1563 * formToArray() gathers form element data into an array of objects that can
1564 * be passed to any of the following ajax functions: $.get, $.post, or load.
1565 * Each object in the array has both a 'name' and 'value' property.  An example of
1566 * an array for a simple login form might be:
1567 *
1568 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
1569 *
1570 * It is this array that is passed to pre-submit callback functions provided to the
1571 * ajaxSubmit() and ajaxForm() methods.
1572 */
1573$.fn.formToArray = function(semantic, elements) {
1574    var a = [];
1575    if (this.length === 0) {
1576        return a;
1577    }
1578
1579    var form = this[0];
1580    var formId = this.attr('id');
1581    var els = semantic ? form.getElementsByTagName('*') : form.elements;
1582    var els2;
1583
1584    if (els && !/MSIE [678]/.test(navigator.userAgent)) { // #390
1585        els = $(els).get();  // convert to standard array
1586    }
1587
1588    // #386; account for inputs outside the form which use the 'form' attribute
1589    if ( formId ) {
1590        els2 = $(':input[form="' + formId + '"]').get(); // hat tip @thet
1591        if ( els2.length ) {
1592            els = (els || []).concat(els2);
1593        }
1594    }
1595
1596    if (!els || !els.length) {
1597        return a;
1598    }
1599
1600    var i,j,n,v,el,max,jmax;
1601    for(i=0, max=els.length; i < max; i++) {
1602        el = els[i];
1603        n = el.name;
1604        if (!n || el.disabled) {
1605            continue;
1606        }
1607
1608        if (semantic && form.clk && el.type == "image") {
1609            // handle image inputs on the fly when semantic == true
1610            if(form.clk == el) {
1611                a.push({name: n, value: $(el).val(), type: el.type });
1612                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
1613            }
1614            continue;
1615        }
1616
1617        v = $.fieldValue(el, true);
1618        if (v && v.constructor == Array) {
1619            if (elements) {
1620                elements.push(el);
1621            }
1622            for(j=0, jmax=v.length; j < jmax; j++) {
1623                a.push({name: n, value: v[j]});
1624            }
1625        }
1626        else if (feature.fileapi && el.type == 'file') {
1627            if (elements) {
1628                elements.push(el);
1629            }
1630            var files = el.files;
1631            if (files.length) {
1632                for (j=0; j < files.length; j++) {
1633                    a.push({name: n, value: files[j], type: el.type});
1634                }
1635            }
1636            else {
1637                // #180
1638                a.push({ name: n, value: '', type: el.type });
1639            }
1640        }
1641        else if (v !== null && typeof v != 'undefined') {
1642            if (elements) {
1643                elements.push(el);
1644            }
1645            a.push({name: n, value: v, type: el.type, required: el.required});
1646        }
1647    }
1648
1649    if (!semantic && form.clk) {
1650        // input type=='image' are not found in elements array! handle it here
1651        var $input = $(form.clk), input = $input[0];
1652        n = input.name;
1653        if (n && !input.disabled && input.type == 'image') {
1654            a.push({name: n, value: $input.val()});
1655            a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
1656        }
1657    }
1658    return a;
1659};
1660
1661/**
1662 * Serializes form data into a 'submittable' string. This method will return a string
1663 * in the format: name1=value1&amp;name2=value2
1664 */
1665$.fn.formSerialize = function(semantic) {
1666    //hand off to jQuery.param for proper encoding
1667    return $.param(this.formToArray(semantic));
1668};
1669
1670/**
1671 * Serializes all field elements in the jQuery object into a query string.
1672 * This method will return a string in the format: name1=value1&amp;name2=value2
1673 */
1674$.fn.fieldSerialize = function(successful) {
1675    var a = [];
1676    this.each(function() {
1677        var n = this.name;
1678        if (!n) {
1679            return;
1680        }
1681        var v = $.fieldValue(this, successful);
1682        if (v && v.constructor == Array) {
1683            for (var i=0,max=v.length; i < max; i++) {
1684                a.push({name: n, value: v[i]});
1685            }
1686        }
1687        else if (v !== null && typeof v != 'undefined') {
1688            a.push({name: this.name, value: v});
1689        }
1690    });
1691    //hand off to jQuery.param for proper encoding
1692    return $.param(a);
1693};
1694
1695/**
1696 * Returns the value(s) of the element in the matched set.  For example, consider the following form:
1697 *
1698 *  <form><fieldset>
1699 *      <input name="A" type="text" />
1700 *      <input name="A" type="text" />
1701 *      <input name="B" type="checkbox" value="B1" />
1702 *      <input name="B" type="checkbox" value="B2"/>
1703 *      <input name="C" type="radio" value="C1" />
1704 *      <input name="C" type="radio" value="C2" />
1705 *  </fieldset></form>
1706 *
1707 *  var v = $('input[type=text]').fieldValue();
1708 *  // if no values are entered into the text inputs
1709 *  v == ['','']
1710 *  // if values entered into the text inputs are 'foo' and 'bar'
1711 *  v == ['foo','bar']
1712 *
1713 *  var v = $('input[type=checkbox]').fieldValue();
1714 *  // if neither checkbox is checked
1715 *  v === undefined
1716 *  // if both checkboxes are checked
1717 *  v == ['B1', 'B2']
1718 *
1719 *  var v = $('input[type=radio]').fieldValue();
1720 *  // if neither radio is checked
1721 *  v === undefined
1722 *  // if first radio is checked
1723 *  v == ['C1']
1724 *
1725 * The successful argument controls whether or not the field element must be 'successful'
1726 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
1727 * The default value of the successful argument is true.  If this value is false the value(s)
1728 * for each element is returned.
1729 *
1730 * Note: This method *always* returns an array.  If no valid value can be determined the
1731 *    array will be empty, otherwise it will contain one or more values.
1732 */
1733$.fn.fieldValue = function(successful) {
1734    for (var val=[], i=0, max=this.length; i < max; i++) {
1735        var el = this[i];
1736        var v = $.fieldValue(el, successful);
1737        if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
1738            continue;
1739        }
1740        if (v.constructor == Array) {
1741            $.merge(val, v);
1742        }
1743        else {
1744            val.push(v);
1745        }
1746    }
1747    return val;
1748};
1749
1750/**
1751 * Returns the value of the field element.
1752 */
1753$.fieldValue = function(el, successful) {
1754    var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
1755    if (successful === undefined) {
1756        successful = true;
1757    }
1758
1759    if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
1760        (t == 'checkbox' || t == 'radio') && !el.checked ||
1761        (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
1762        tag == 'select' && el.selectedIndex == -1)) {
1763            return null;
1764    }
1765
1766    if (tag == 'select') {
1767        var index = el.selectedIndex;
1768        if (index < 0) {
1769            return null;
1770        }
1771        var a = [], ops = el.options;
1772        var one = (t == 'select-one');
1773        var max = (one ? index+1 : ops.length);
1774        for(var i=(one ? index : 0); i < max; i++) {
1775            var op = ops[i];
1776            if (op.selected) {
1777                var v = op.value;
1778                if (!v) { // extra pain for IE...
1779                    v = (op.attributes && op.attributes.value && !(op.attributes.value.specified)) ? op.text : op.value;
1780                }
1781                if (one) {
1782                    return v;
1783                }
1784                a.push(v);
1785            }
1786        }
1787        return a;
1788    }
1789    return $(el).val();
1790};
1791
1792/**
1793 * Clears the form data.  Takes the following actions on the form's input fields:
1794 *  - input text fields will have their 'value' property set to the empty string
1795 *  - select elements will have their 'selectedIndex' property set to -1
1796 *  - checkbox and radio inputs will have their 'checked' property set to false
1797 *  - inputs of type submit, button, reset, and hidden will *not* be effected
1798 *  - button elements will *not* be effected
1799 */
1800$.fn.clearForm = function(includeHidden) {
1801    return this.each(function() {
1802        $('input,select,textarea', this).clearFields(includeHidden);
1803    });
1804};
1805
1806/**
1807 * Clears the selected form elements.
1808 */
1809$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
1810    var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
1811    return this.each(function() {
1812        var t = this.type, tag = this.tagName.toLowerCase();
1813        if (re.test(t) || tag == 'textarea') {
1814            this.value = '';
1815        }
1816        else if (t == 'checkbox' || t == 'radio') {
1817            this.checked = false;
1818        }
1819        else if (tag == 'select') {
1820            this.selectedIndex = -1;
1821        }
1822        else if (t == "file") {
1823            if (/MSIE/.test(navigator.userAgent)) {
1824                $(this).replaceWith($(this).clone(true));
1825            } else {
1826                $(this).val('');
1827            }
1828        }
1829        else if (includeHidden) {
1830            // includeHidden can be the value true, or it can be a selector string
1831            // indicating a special test; for example:
1832            //  $('#myForm').clearForm('.special:hidden')
1833            // the above would clean hidden inputs that have the class of 'special'
1834            if ( (includeHidden === true && /hidden/.test(t)) ||
1835                 (typeof includeHidden == 'string' && $(this).is(includeHidden)) ) {
1836                this.value = '';
1837            }
1838        }
1839    });
1840};
1841
1842/**
1843 * Resets the form data.  Causes all form elements to be reset to their original value.
1844 */
1845$.fn.resetForm = function() {
1846    return this.each(function() {
1847        // guard against an input with the name of 'reset'
1848        // note that IE reports the reset function as an 'object'
1849        if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
1850            this.reset();
1851        }
1852    });
1853};
1854
1855/**
1856 * Enables or disables any matching elements.
1857 */
1858$.fn.enable = function(b) {
1859    if (b === undefined) {
1860        b = true;
1861    }
1862    return this.each(function() {
1863        this.disabled = !b;
1864    });
1865};
1866
1867/**
1868 * Checks/unchecks any matching checkboxes or radio buttons and
1869 * selects/deselects and matching option elements.
1870 */
1871$.fn.selected = function(select) {
1872    if (select === undefined) {
1873        select = true;
1874    }
1875    return this.each(function() {
1876        var t = this.type;
1877        if (t == 'checkbox' || t == 'radio') {
1878            this.checked = select;
1879        }
1880        else if (this.tagName.toLowerCase() == 'option') {
1881            var $sel = $(this).parent('select');
1882            if (select && $sel[0] && $sel[0].type == 'select-one') {
1883                // deselect all other options
1884                $sel.find('option').selected(false);
1885            }
1886            this.selected = select;
1887        }
1888    });
1889};
1890
1891// expose debug var
1892$.fn.ajaxSubmit.debug = false;
1893
1894// helper fn for console logging
1895function log() {
1896    if (!$.fn.ajaxSubmit.debug) {
1897        return;
1898    }
1899    var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
1900    if (window.console && window.console.log) {
1901        window.console.log(msg);
1902    }
1903    else if (window.opera && window.opera.postError) {
1904        window.opera.postError(msg);
1905    }
1906}
1907}); // JAC: bug javascript_resgistries
1908
1909/* - register_function.js - */
1910/* 
1911  Deprecated utility functions - Use jQuery directly instead.
1912  These will be gone in Plone 5.
1913*/
1914
1915/*
1916  Provides globals:
1917  W3CDOM, bugRiddenCrashPronePieceOfJunk, getContentArea, 
1918  registerEventListener, registerPloneFunction, unRegisterEventListener
1919*/  
1920
1921/*global navigator */
1922
1923
1924// check for ie5 mac
1925var bugRiddenCrashPronePieceOfJunk = (
1926    navigator.userAgent.indexOf('MSIE 5') !== -1 && navigator.userAgent.indexOf('Mac') !== -1
1927);
1928
1929// check for W3CDOM compatibility
1930var W3CDOM = (!bugRiddenCrashPronePieceOfJunk &&
1931               typeof document.getElementsByTagName !== 'undefined' &&
1932               typeof document.createElement !== 'undefined' );
1933
1934// cross browser function for registering event handlers
1935var registerEventListener = function(elem, event, func) {
1936    jQuery(elem).bind(event, func);
1937};
1938
1939// cross browser function for unregistering event handlers
1940var unRegisterEventListener = function(elem, event, func) {
1941    jQuery(elem).unbind(event, func);
1942};
1943
1944var registerPloneFunction = jQuery;
1945
1946function getContentArea() {
1947    // returns our content area element
1948    var node = jQuery('#region-content,#content');
1949    return node.length ? node[0] : null;
1950} 
1951
1952
1953/* - select_all.js - */
1954// Functions for selecting all/none checkboxes in folder_contents/search_form view
1955
1956/*
1957  Provides global toggleSelect; see search_form.pt for example usage.
1958*/
1959
1960/*global portal_url */
1961
1962function toggleSelect(selectbutton, id, initialState, formName) {
1963    /* required selectbutton: you can pass any object that will function as a toggle
1964     * optional id: id of the the group of checkboxes that needs to be toggled (default=ids:list
1965     * optional initialState: initial state of the group. (default=false)
1966     * e.g. folder_contents is false, search_form=true because the item boxes
1967     * are checked initially.
1968     * optional formName: name of the form in which the boxes reside, use this if there are more
1969     * forms on the page with boxes with the same name
1970     */
1971    var fid, state, base;
1972
1973    fid = id || 'ids:list';  // defaults to ids:list, this is the most common usage
1974    state = selectbutton.isSelected;
1975    if (state === undefined) {
1976        state = Boolean(initialState);
1977    }
1978
1979    // create and use a property on the button itself so you don't have to 
1980    // use a global variable and we can have as much groups on a page as we like.
1981    selectbutton.isSelected = !state;
1982    jQuery(selectbutton).attr('src', portal_url+'/select_'+(state?'all':'none')+'_icon.png');
1983    base = formName ? jQuery(document.forms[formName]) : jQuery(document);
1984    base.find('input[name=' + fid + ']:checkbox').attr('checked', !state);
1985}
1986
1987
1988/* - collapsiblesections.js - */
1989/*
1990 * This is the code for the collapsibles. It uses the following markup:
1991 *
1992 * <dl class="collapsible">
1993 *   <dt class="collapsibleHeader">
1994 *     A Title
1995 *   </dt>
1996 *   <dd class="collapsibleContent">
1997 *     <!-- Here can be any content you want -->
1998 *   </dd>
1999 * </dl>
2000 *
2001 * When the collapsible is toggled, then the dl will get an additional class
2002 * which switches between 'collapsedBlockCollapsible' and
2003 * 'expandedBlockCollapsible'. You can use this to style it accordingly, for
2004 * example:
2005 *
2006 * .expandedBlockCollapsible .collapsibleContent {
2007 *   display: block;
2008 * }
2009 *
2010 * .collapsedBlockCollapsible .collapsibleContent {
2011 *   display: none;
2012 * }
2013 *
2014 * If you add the 'collapsedOnLoad' class to the dl, then it will get
2015 * collapsed on page load, this is done, so the content is accessible even when
2016 * javascript is disabled.
2017 *
2018 * If you add the 'inline' class to the dl, then it will toggle between
2019 * 'collapsedInlineCollapsible' and 'expandedInlineCollapsible' instead of
2020 * 'collapsedBlockCollapsible' and 'expandedBlockCollapsible'.
2021 *
2022 */
2023
2024function activateCollapsibles() {
2025(function($) {
2026    $('dl.collapsible:not([class$=Collapsible])').find('dt.collapsibleHeader:first').click(function() {
2027        var $container = $(this).parents('dl.collapsible:first'),
2028            $type;
2029        if (!$container) {
2030            return true;
2031        }
2032
2033        $type = $container.hasClass('inline') ? 'Inline' :'Block';
2034        // toggle between collapsed and expanded classes
2035        $container.toggleClass('collapsed' + $type + 'Collapsible')
2036                  .toggleClass('expanded' + $type + 'Collapsible');
2037    }).end().each(function() {
2038        var $state = $(this).hasClass('collapsedOnLoad') ?
2039                     'collapsed' : 'expanded',
2040            $type = $(this).hasClass('inline') ? 'Inline' :'Block';
2041        $(this).removeClass('collapsedOnLoad')
2042               .addClass($state + $type + 'Collapsible');
2043    });
2044}(jQuery));
2045}
2046
2047jQuery(function($) {
2048$(activateCollapsibles);
2049});
2050
2051
2052/* - popupforms.js - */
2053/******
2054    Set up standard Plone popups
2055    
2056    Provides globals: common_content_filter
2057    
2058    Extends jQuery.tools.overlay.conf to set up common Plone effects and
2059    visuals.
2060******/
2061
2062
2063var common_content_filter = '#content>*:not(div.configlet),dl.portalMessage.error,dl.portalMessage.info';
2064
2065jQuery.extend(jQuery.tools.overlay.conf, 
2066    {
2067        fixed:false,
2068        speed:'fast',
2069        mask:{color:'#fff',opacity: 0.4,loadSpeed:0,closeSpeed:0}
2070    });
2071
2072
2073(function($) {
2074		
2075	// static constructs
2076	$.plonepopups = $.plonepopups || {};
2077    
2078    $.extend($.plonepopups,
2079        {
2080            // method to show error message in a noform
2081            // situation.
2082            noformerrorshow: function noformerrorshow(el, noform) {
2083                var o = $(el),
2084                    emsg = o.find('dl.portalMessage.error');
2085                if (emsg.length) {
2086                    o.children().replaceWith(emsg);
2087                    return false;
2088                } else {
2089                    return noform;
2090                }
2091            },
2092            // After deletes we need to redirect to the target page.
2093            redirectbasehref: function redirectbasehref(el, responseText) {
2094                var mo = responseText.match(/<base href="(\S+?)"/i);
2095                if (mo.length === 2) {
2096                    return mo[1];
2097                }
2098                return location;
2099            }
2100        })
2101})(jQuery);
2102
2103jQuery(function($){
2104
2105    if (jQuery.browser.msie && parseInt(jQuery.browser.version, 10) < 7) {
2106        // it's not realistic to think we can deal with all the bugs
2107        // of IE 6 and lower. Fortunately, all this is just progressive
2108        // enhancement.
2109        return;
2110    }
2111    
2112    // login form
2113    $('#portal-personaltools a[href$="/login"], #portal-personaltools a[href$="/login_form"], .discussion a[href$="/login"], .discussion a[href$="/login_form"]').prepOverlay(
2114        {
2115            subtype: 'ajax',
2116            filter: common_content_filter,
2117            formselector: 'form#login_form',
2118            noform: function () {
2119                if (location.href.search(/pwreset_finish$/) >= 0) {
2120                    return 'redirect';
2121                } else {
2122                    return 'reload';
2123                }
2124            },
2125            redirect: function () {
2126                var href = location.href;
2127                if (href.search(/pwreset_finish$/) >= 0) {
2128                    return href.slice(0, href.length-14) + 'logged_in';
2129                } else {
2130                    return href;
2131                }
2132            }
2133        }
2134    );
2135
2136    // contact form
2137    $('#siteaction-contact a').prepOverlay(
2138        {
2139            subtype: 'ajax',
2140            filter: common_content_filter,
2141            formselector: 'form[name="feedback_form"]',
2142            noform: function(el) {return $.plonepopups.noformerrorshow(el, 'close');}
2143        }
2144    );
2145
2146    // comment form
2147    $('form[name=reply]').prepOverlay(
2148        {
2149            subtype: 'ajax',
2150            filter: common_content_filter,
2151            formselector: 'form:has(input[name="discussion_reply:method"])',
2152            noform: function(el) {return $.plonepopups.noformerrorshow(el, 'redirect');},
2153            redirect: $.plonepopups.redirectbasehref
2154        }
2155    );
2156
2157
2158    // display: select content item / change content item
2159    // $('#contextSetDefaultPage, #folderChangeDefaultPage').prepOverlay(
2160    //    {
2161    //        subtype: 'ajax',
2162    //        filter: common_content_filter,
2163    //        formselector: 'form[name="default_page_form"]',
2164    //        noform: function(el) {return $.plonepopups.noformerrorshow(el, 'reload');},
2165    //        closeselector: '[name=form.button.Cancel]',
2166    //        width:'40%'
2167    //    }
2168    //);
2169
2170    // advanced state
2171    // This form needs additional JS and CSS for the calendar widget.
2172    // The AJAX form doesn't load it from the javascript_head_slot.
2173    // $('dl#plone-contentmenu-workflow a#advanced').prepOverlay(
2174    //     {
2175    //         subtype: 'ajax',
2176    //         filter: common_content_filter,
2177    //         formselector: 'form',
2178    //         noform: function(el) {return $.plonepopups.noformerrorshow(el, 'reload');},
2179    //         closeselector: '[name=form.button.Cancel]'
2180    //     }
2181    // );
2182
2183    // Delete dialog
2184    $('dl#plone-contentmenu-actions a#delete').prepOverlay(
2185        {
2186            subtype: 'ajax',
2187            filter: common_content_filter,
2188            formselector: '#delete_confirmation',
2189            noform: function(el) {return $.plonepopups.noformerrorshow(el, 'redirect');},
2190            redirect: $.plonepopups.redirectbasehref,
2191            closeselector: '[name=form.button.Cancel]',
2192            width:'50%'
2193        }
2194    );
2195
2196    // Rename dialog
2197    $('dl#plone-contentmenu-actions a#rename').prepOverlay(
2198        {
2199            subtype: 'ajax',
2200            filter: common_content_filter,
2201            closeselector: '[name=form.button.Cancel]',
2202            width:'40%'
2203        }
2204    );
2205
2206    // registration
2207    $('#portal-personaltools a[href$="/@@register"]').prepOverlay(
2208        {
2209            subtype: 'ajax',
2210            filter: common_content_filter,
2211            formselector: 'form.kssattr-formname-register'
2212        }
2213    );
2214
2215    // add new user, group
2216    $('form[name=users_add], form[name=groups_add]').prepOverlay(
2217        {
2218            subtype: 'ajax',
2219            filter: common_content_filter,
2220            formselector: 'form.kssattr-formname-new-user, form[name="groups"]',
2221            noform: function(el) {return $.plonepopups.noformerrorshow(el, 'redirect');},
2222            redirect: function () {return location.href;}
2223        }
2224    );
2225
2226    // Content history popup
2227    $('#content-history a').prepOverlay({
2228       subtype: 'ajax', 
2229       filter: 'h2, #content-history',
2230       urlmatch: '@@historyview',
2231       urlreplace: '@@contenthistorypopup'
2232    });
2233
2234});
2235
2236

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.