
/* Merged Plone Javascript file
 * This file is dynamically assembled from separate parts.
 * Some of these parts have 3rd party licenses or copyright information attached
 * Such information is valid for that section,
 * not for the entire composite file
 * originating files are separated by - filename.js -
 */

/* - nodeutilities.js - */
// These methods have all been deprecated in favor of using jquery.

function wrapNode(node, wrappertype, wrapperclass){
    /* utility function to wrap a node in an arbitrary element of type "wrappertype"
     * with a class of "wrapperclass" */
    jQuery(node).wrap('<' + wrappertype + '>').parent().addClass(wrapperclass);
};

function nodeContained(innernode, outernode){
    // check if innernode is contained in outernode
    return jQuery(innernode).parents()
        .filter(function() { return this == outernode }).length > 0;
};

function findContainer(node, func) {
    // Starting with the given node, find the nearest containing element
    // for which the given function returns true.
    p = jQuery(node).parents().filter(func);
    return p.length ? p.get(0) : false;
};

function hasClassName(node, class_name) {
    return jQuery(node).hasClass(class_name);
};

function addClassName(node, class_name) {
    jQuery(node).addClass(class_name);
};

function removeClassName(node, class_name) {
    jQuery(node).removeClass(class_name);
};

function replaceClassName(node, old_class, new_class, ignore_missing) {
    if (ignore_missing || jQuery(node).hasClass(old_class))
        jQuery(node).removeClass(old_class).addClass(new_class);
};

function walkTextNodes(node, func, data) {
    // find all nodes, and call a function for all it's textnodes
    jQuery(node).find('*').andSelf().contents().each(function() {
        if (this.nodeType == 3) func(this, data);
    });
};

function getInnerTextCompatible(node) {
    return jQuery(node).text();
};

function getInnerTextFast(node) {
    return jQuery(node).text();
};

/* This function reorder nodes in the DOM.
 * fetch_func - the function which returns the value for comparison
 * cmp_func - the compare function, if not provided then the string of the
 * value returned by fetch_func is used.
 */
function sortNodes(nodes, fetch_func, cmp_func) {
    // wrapper for sorting
    var SortNodeWrapper = function(node) {
        this.value = fetch_func(node);
        this.cloned_node = node.cloneNode(true);
    }
    SortNodeWrapper.prototype.toString = function() {
        return this.value.toString ? this.value.toString() : this.value;
    }

    // wrap nodes
    var items = jQuery(nodes).map(function() { return new SortNodeWrapper(this); });

    //sort
    if (cmp_func) items.sort(cmp_func);
    else          items.sort();

    // reorder nodes
    jQuery.each(items, function(i) { jQuery(nodes[i]).replace(this.cloned_node); });
};

function copyChildNodes(srcNode, dstNode) {
    jQuery(srcNode).children().clone().appendTo(jQuery(dstNode));
}


/* - cookie_functions.js - */
function createCookie(name,value,days) {
    if (days) {
        var date = new Date();
        date.setTime(date.getTime()+(days*24*60*60*1000));
        var expires = "; expires="+date.toGMTString();
    } else {
        expires = "";
    }
    document.cookie = name+"="+escape(value)+expires+"; path=/;";
};

function readCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') {
            c = c.substring(1,c.length);
        }
        if (c.indexOf(nameEQ) == 0) {
            return unescape(c.substring(nameEQ.length,c.length));
        }
    }
    return null;
};


/* - select_all.js - */
// Functions for selecting all checkboxes in folder_contents/search_form view
function toggleSelect(selectbutton, id, initialState, formName) {
    /* required selectbutton: you can pass any object that will function as a toggle
     * optional id: id of the the group of checkboxes that needs to be toggled (default=ids:list
     * optional initialState: initial state of the group. (default=false)
     * e.g. folder_contents is false, search_form=true because the item boxes
     * are checked initially.
     * optional formName: name of the form in which the boxes reside, use this if there are more
     * forms on the page with boxes with the same name
     */
    id=id || 'ids:list'  // defaults to ids:list, this is the most common usage
    var state = selectbutton.isSelected;
    state = state == null ? Boolean(initialState) : state;

    // create and use a property on the button itself so you don't have to 
    // use a global variable and we can have as much groups on a page as we like.
    selectbutton.isSelected = !state;
    jQuery(selectbutton).attr('src', portal_url+'/select_'+(state?'all':'none')+'_icon.png');
    var base = formName ? jQuery(document.forms[formName]) : jQuery(document);
    base.find(':checkbox[name=' + id + ']').attr('checked', !state);
}


/* - dragdropreorder.js - */
var ploneDnDReorder = {};

ploneDnDReorder.dragging = null;
ploneDnDReorder.table = null;
ploneDnDReorder.rows = null;

(function($) {

ploneDnDReorder.doDown = function(e) {
    var dragging =  $(this).parents('.draggable:first');
    if (!dragging.length) return;
    ploneDnDReorder.rows.mousemove(ploneDnDReorder.doDrag);

    ploneDnDReorder.dragging = dragging;
    dragging._position = ploneDnDReorder.getPos(dragging);
    dragging.addClass("dragging");
    $(this).parents('tr').addClass('dragindicator');

    return false;
};

ploneDnDReorder.getPos = function(node) {
    var pos = node.parent().children('.draggable').index(node[0]);
    return pos == -1 ? null : pos;
};

ploneDnDReorder.doDrag = function(e) {
    var dragging = ploneDnDReorder.dragging;
    if (!dragging) return;
    var target = this;
    if (!target) return;

    if ($(target).attr('id') != dragging.attr('id')) {
        ploneDnDReorder.swapElements($(target), dragging);
    };
    return false;
};

ploneDnDReorder.swapElements = function(child1, child2) {
    var parent = child1.parent();
    var items = parent.children('[id]');
    items.removeClass('even').removeClass('odd');
    if (child1[0].swapNode) {
        // IE proprietary method
        child1[0].swapNode(child2[0]);
    } else {
        // swap the two elements, using a textnode as a position marker
        var t = parent[0].insertBefore(document.createTextNode(''),
                                       child1[0]);
        child1.insertBefore(child2);
        child2.insertBefore(t);
        $(t).remove();
    };
    // odd and even are 0-based, so we want them the other way around
    parent.children('[id]:odd').addClass('even');
    parent.children('[id]:even').addClass('odd');
};

ploneDnDReorder.doUp = function(e) {
    var dragging = ploneDnDReorder.dragging;
    if (!dragging) return;

    dragging.removeClass("dragging");
    ploneDnDReorder.updatePositionOnServer();
    dragging._position = null;
    try {
        delete dragging._position;
    } catch(e) {};
    dragging = null;
    ploneDnDReorder.rows.unbind('mousemove', ploneDnDReorder.doDrag);
    $(this).parents('tr').removeClass('dragindicator');
    return false;
};

ploneDnDReorder.updatePositionOnServer = function() {
    var dragging = ploneDnDReorder.dragging;
    if (!dragging) return;

    var delta = ploneDnDReorder.getPos(dragging) - dragging._position;

    if (delta == 0) {
        // nothing changed
        return;
    };
    // Strip off id prefix
    var args = {
        item_id: dragging.attr('id').substr('folder-contents-item-'.length)
    };
    args['delta:int'] = delta;
    jQuery.post('folder_moveitem', args)
};

})(jQuery);


/* - collapsiblesections.js - */
/*
 * This is the code for the collapsibles. It uses the following markup:
 *
 * <dl class="collapsible">
 *   <dt class="collapsibleHeader">
 *     A Title
 *   </dt>
 *   <dd class="collapsibleContent">
 *     <!-- Here can be any content you want -->
 *   </dd>
 * </dl>
 *
 * When the collapsible is toggled, then the dl will get an additional class
 * which switches between 'collapsedBlockCollapsible' and
 * 'expandedBlockCollapsible'. You can use this to style it accordingly, for
 * example:
 *
 * .expandedBlockCollapsible .collapsibleContent {
 *   display: block;
 * }
 *
 * .collapsedBlockCollapsible .collapsibleContent {
 *   display: none;
 * }
 *
 * If you add the 'collapsedOnLoad' class to the dl, then it will get
 * collapsed on page load, this is done, so the content is accessible even when
 * javascript is disabled.
 *
 * If you add the 'inline' class to the dl, then it will toggle between
 * 'collapsedInlineCollapsible' and 'expandedInlineCollapsible' instead of
 * 'collapsedBlockCollapsible' and 'expandedBlockCollapsible'.
 *
 */

function activateCollapsibles() {
(function($) {
    $('dl.collapsible:not([class$=Collapsible])').find('dt.collapsibleHeader:first').click(function() {
        var $container = $(this).parents('dl.collapsible:first');
        if (!$container) return true;

        var $type = $container.hasClass('inline') ? 'Inline' :'Block';
        // toggle between collapsed and expanded classes
        $container.toggleClass('collapsed' + $type + 'Collapsible')
                  .toggleClass('expanded' + $type + 'Collapsible');
    }).end().each(function() {
        var $state = $(this).hasClass('collapsedOnLoad') ?
                     'collapsed' : 'expanded';
        var $type = $(this).hasClass('inline') ? 'Inline' :'Block';
        $(this).removeClass('collapsedOnLoad')
               .addClass($state + $type + 'Collapsible');
    });
})(jQuery);
};

(function($) {
$(activateCollapsibles);
})(jQuery);


/* - collapsibleformfields.js - */
/* This code collapses fields in forms
 * It uses the following markup:
 * 
 * <div class="collapsible'>
 *   <label class="collapser"> label of the field </label>
 *   <div class="collapse"> block to collapse </div>
 *  </div>
 * 
 */

(function($) {

$.fn.do_search_collapse = function() 
{
    return this.each(
	function() {
	    function check_used(element)
	    {
		e = $(element);
		
		// is there a number of checkboxs with a toggle box
		if (e.find('input[id$=_toggle]:checkbox').length > 0)
		{
		    // and the toggle checkbox is not checked.
		    if (e.find('input[id$=_toggle]:checkbox:checked').length == 0)
		    {
			return true;
		    }
		};

		// is there a normal text input fields that is not empty (=has a value) 
		if(e.find(':text[value]').length > 0){
		    return true;
		};
		
		// drop downs
		// we have an option marked as the default option
		if(e.find('select .default_option').length > 0)
		{
		    // and this default option isn't selected
		    if(e.find('select .default_option:selected').length == 0)
		    {
			return true;
		    }
		}
		return false;
	    };

            var indicator =  $(this).find('.collapser:first');
            var collapse = $(this).find('.collapse:first');
            indicator.click(function()
		{
		    var container = $(this).parent();
		    target = container.find('.collapse:first');
		    target.slideToggle('normal');
		    $(this).toggleClass('expanded');
		    $(this).toggleClass('collapsed');
		});
	    
	    if(check_used(this)){
		indicator.addClass('expanded');
	    } else {
		collapse.hide();
		indicator.addClass('collapsed');
	    };
	}
    );
};


})(jQuery);


/* - form_tabbing.js - */
/*
 * This is the code for the tabbed forms. It assumes the following markup:
 *
 * <form class="enableFormTabbing">
 *   <fieldset id="fieldset-[unique-id]">
 *     <legend id="fieldsetlegend-[same-id-as-above]">Title</legend>
 *   </fieldset>
 * </form>
 *
 * or the following
 *
 * <dl class="enableFormTabbing">
 *   <dt id="fieldsetlegend-[unique-id]">Title</dt>
 *   <dd id="fieldset-[same-id-as-above]">
 *   </dd>
 * </dl>
 *
 */


var ploneFormTabbing = {
        // standard jQueryTools configuration options for all form tabs
        jqtConfig:{current:'selected'}
    };
    
    
(function($) {

ploneFormTabbing._buildTabs = function(container, legends) {
    var threshold = legends.length > 6;
    var panel_ids, tab_ids = [], tabs = '';

    for (var i=0; i < legends.length; i++) {
        var className, tab, legend = legends[i], lid = legend.id;
        tab_ids[i] = '#' + lid;

        switch (i) {
            case (0):
                className = 'class="formTab firstFormTab"';
                break;
            case (legends.length-1):
                className = 'class="formTab lastFormTab"';
                break;
            default:
                className = 'class="formTab"';
                break;
        }

        if (threshold) {
            tab = '<option '+className+' id="'+lid+'" value="'+lid+'">';
            tab += $(legend).text()+'</option>';
        } else {
            tab = '<li '+className+'><a href="#'+lid+'"><span>';
            tab += $(legend).text()+'</span></a></li>';
        }

        tabs += tab;
        $(legend).hide();
    }

    tab_ids = tab_ids.join(',');
    panel_ids = tab_ids.replace(/#fieldsetlegend-/g, "#fieldset-");

    if (threshold) {
        tabs = $('<select class="formTabs">'+tabs+'</select>');
    } else {
        tabs = $('<ul class="formTabs">'+tabs+'</ul>');
    }

    return tabs;
};


ploneFormTabbing.initializeDL = function() {
    var ftabs = $(ploneFormTabbing._buildTabs(this, $(this).children('dt')));
    var targets = $(this).children('dd');
    $(this).before(ftabs);
    targets.addClass('formPanel');
    ftabs.tabs(targets, ploneFormTabbing.jqtConfig);
};


ploneFormTabbing.initializeForm = function() {
    var jqForm = $(this);
    var fieldsets = jqForm.children('fieldset');

    if (!fieldsets.length) {return;}

    var ftabs = ploneFormTabbing._buildTabs(
        this, fieldsets.children('legend'));
    $(this).prepend(ftabs);
    fieldsets.addClass("formPanel");


    // The fieldset.current hidden may change, but is not content
    $(this).find('input[name=fieldset.current]').addClass('noUnloadProtection');

    $(this).find('.formPanel:has(div.field span.fieldRequired)').each(function() {
        var id = this.id.replace(/^fieldset-/, "#fieldsetlegend-");
        $(id).addClass('required');
    });

    // set the initial tab
    var initialIndex = 0;
    var count = 0;
    var found = false;
    $(this).find('.formPanel').each(function() {
        if (!found && $(this).find('div.field.error')) {
            initialIndex = count;
            found = true;
        }
        count += 1;
    });

    var tabSelector = 'ul.formTabs';
    if ($(ftabs).is('select.formTabs')) {
        tabSelector = 'select.formTabs';
    }
    jqForm.children(tabSelector).tabs(
        'form.enableFormTabbing fieldset.formPanel', 
        ploneFormTabbing.jqtConfig || {'initialIndex':initialIndex}
        );
    
    // save selected tab on submit
    jqForm.submit(function() {
        var selected = ftabs.find('a.selected').attr('href').replace(/^#fieldsetlegend-/, "#fieldset-");
        var fsInput = jqForm.find('input[name=fieldset.current]');
        if (selected && fsInput) {
            fsInput.val(selected);
        }
    });

    $("#archetypes-schemata-links").addClass('hiddenStructure');
    $("div.formControls input[name=form.button.previous]," +
      "div.formControls input[name=form.button.next]").remove();

};

$.fn.ploneTabInit = function(pbo) {
    return this.each(function() {
        var item = $(this);
        
        item.find("form.enableFormTabbing,div.enableFormTabbing").each(ploneFormTabbing.initializeForm);
        item.find("dl.enableFormTabbing").each(ploneFormTabbing.initializeDL);

        //Select tab if it's part of the URL or designated in a hidden input
        var targetPane = item.find('.enableFormTabbing input[name=fieldset.current]').val() || window.location.hash;
        if (targetPane) {
            item.find(".enableFormTabbing .formtab a[href='" +
             targetPane.replace("'", "").replace(/^#fieldset-/, "#fieldsetlegend-") +
             "']").click();
        }
    });
};

// initialize is a convenience function
ploneFormTabbing.initialize = function() {
    $('body').ploneTabInit();
};

})(jQuery);

jQuery(function(){ploneFormTabbing.initialize();});


/* - input-label.js - */
/* This looks for input fields with a title and the class "inputLabel". When
   the field is empty the title will be set as it's value and the class
   "inputLabel" will be replaced with the class "inputLabelActive" to make
   it styleable with css. When the field gets focus, the content is removed
   and the class "inputLabelActive" is removed. When the field looses focus,
   then the game starts again if the value is empty, if not then the field
   is left as is. When the form is submitted, the values are cleaned up
   before they are sent to the server.
*/

var ploneInputLabel = {
    focus: function() {
        var t = jQuery(this);
        if (t.hasClass('inputLabelActive') && t.val() == t.attr('title'))
            t.val('').removeClass('inputLabelActive');
        if (t.hasClass('inputLabelPassword'))
            ploneInputLabel._setInputType(t.removeClass('inputLabelPassword'), 
                'password').focus().bind('blur.ploneInputLabel', ploneInputLabel.blur);
    },

    blur: function(e) {
        var t = jQuery(this);
        if (t.is(':password[value=""]')) {
            t = ploneInputLabel._setInputType(this, 'text')
                .addClass('inputLabelPassword')
                .bind('focus.ploneInputLabel', ploneInputLabel.focus);
            if (e.originalEvent && e.originalEvent.explicitOriginalTarget)
                // Re-focus next element in Gecko browsers
                jQuery(e.originalEvent.explicitOriginalTarget).trigger('focus!');
        }
        if (!t.val())
            t.addClass('inputLabelActive').val(t.attr('title'));
    },

    submit: function() {
        jQuery('input[title].inputLabelActive').trigger('focus.ploneInputLabel');
    },

    _setInputType: function(elem, ntype) {
        var $ = jQuery;
        // You can't change the type on an <input> element, but you can 
        // replace the element itself. Following .replace dance is to make it
        // work correctly in IE, as usual.
        var otype = new RegExp('type="?' + $(elem).attr('type') + '"?')
        var nelem = $($('<div></div>').append($(elem).clone()).html()
                .replace(otype, '').replace(/\/?>/, 'type="' + ntype + '" />'));
        $(elem).replaceWith(nelem);
        return nelem;
    }
};

(function($) { $(function() {
    $('form:has(input[title].inputLabel)').submit(ploneInputLabel.submit);
    $('input[title].inputLabel')
        .bind('focus.ploneInputLabel', ploneInputLabel.focus)
        .bind('blur.ploneInputLabel', ploneInputLabel.blur)
        .trigger('blur.ploneInputLabel'); // Apply the title
}); })(jQuery);


/* - jquery.highlightsearchterms.js - */
(function($) {
    var Highlighter = function (options) { 
        $.extend(this, options);
        this.terms = this.cleanTerms(this.terms.length ? this.terms : this.getSearchTerms());
    };
    Highlighter.prototype = {
        highlight: function(startnode) {
            // Starting at startnode, highlight the terms in the tree
            if (!this.terms.length || !startnode.length) return;

            var self = this;
            $.each(this.terms, function(i, term) {
                startnode.find('*:not(textarea)').andSelf().contents().each(function() {
                    if (this.nodeType == 3) 
                        self.highlightTermInNode(this, term);
                });
            });
        },

        highlightTermInNode: function(node, word) {
            // wrap every occurance of word within node in a span with
            // options className.
            // word is a String, node a DOM TextNode
            var c = node.nodeValue, self = this;
            if ($(node).parent().hasClass(self.highlightClass)) return;

            // Internet Explorer cannot create simple <span> tags without content
            // otherwise it'd be $('<span>').addClass(...).text(content)
            var highlight = function(content) {
                return $('<span class="' + self.highlightClass + '">' + 
                    content + '</span>');
            };

            var ci = self.caseInsensitive;
            var index;
            while (c && (index = (ci ? c.toLowerCase() : c).indexOf(word)) > -1) {
                // replace the node with [before]<span>word</span>[after]
                $(node)
                    .before(document.createTextNode(c.substr(0, index)))
                    .before(highlight(c.substr(index, word.length)))
                    .before(document.createTextNode(c.substr(index+word.length)));
                var next = node.previousSibling; // text after the span
                $(node).remove(); 
                // wash, rinse and repeat
                node = next; c = node.nodeValue;
            }
        },
        
        queryStringValue: function(uri, regexp) {
            // Return the decoded value of the key=value pair in the query string
            // uri is the full URI including qs, regexp is a /key=(.*)/ pattern
            if (uri.indexOf('?') < 0) return '';
            uri = uri.substr(uri.indexOf('?') + 1);
            while (uri.indexOf('=') >= 0) {
                uri = uri.replace(/^\&*/, '');
                var pair = uri.split('&', 1)[0];
                uri = uri.substr(pair.length);
                var match = pair.match(regexp);
                if (match) 
                    return decodeURIComponent(
                        match[match.length-1].replace(/\+/g, ' '));
            }
            return '';
        },
        
        termsFromReferrer: function() {
            // Find search terms from the referrer, if a recognized search engine
            var ref = $.fn.highlightSearchTerms._test_referrer !== null ? 
                $.fn.highlightSearchTerms._test_referrer : 
                document.referrer;
            if (!ref) return '';

            for (var i = 0, se; se = this.referrers[i++];) {
                if (ref.match(se.address)) return this.queryStringValue(ref, se.key);
            }
            return '';
        },
        
        cleanTerms: function(terms) {
            var self = this;
            return $.unique($.map(terms, function(term) {
                term = $.trim(self.caseInsensitive ? term.toLowerCase() : term);
                return (!term || self.filterTerms.test(term)) ? null : term;
            }));
        },
        
        getSearchTerms: function() {
            var terms = [];
            var uri = $.fn.highlightSearchTerms._test_location !== null ? 
                $.fn.highlightSearchTerms._test_location : 
                location.href;
            if (this.useReferrer) 
                $.merge(terms, this.termsFromReferrer().split(/\s+/));
            if (this.useLocation) 
                $.merge(terms, this.queryStringValue(uri, this.searchKey).split(/\s+/));
            return terms;
        }
    };

    var makeSearchKey = function(key) {
        return (typeof key === 'string') ? new RegExp('^' + key + '=(.*)$', 'i') : key;
    };
    var makeAddress = function(addr) {
        return (typeof addr === 'string') ? new RegExp('^https?://(www\\.)?' + addr, 'i') : addr;
    };

    $.fn.highlightSearchTerms = function(options) {
        // Wrap terms in a span with class highlightedSearchTerm. 
        // See defaults for options
        options = $.extend({}, defaults, options);
        options = $.extend(options, {
            searchKey: makeSearchKey(options.searchKey),
            referrers: $.map(options.referrers, function(se) {
                return { 
                    address: makeAddress(se.address), 
                    key: makeSearchKey(se.key)
                };
            })
        });
        if (options.includeOwnDomain) {
            var hostname = $.fn.highlightSearchTerms._test_location !== null ?
                $.fn.highlightSearchTerms._test_location : location.hostname;
            options.referrers.push({
                address: makeAddress(hostname.replace(/\./g, '\\.')),
                key: options.searchKey
            });
        }
        new Highlighter(options).highlight(this);
        
        return this;
    };
    
    // defaults referrers is public for easy copying (for extending the 
    // list) or even inplace alteration if you are so inclined.
    $.fn.highlightSearchTerms.referrers = [ // List based on http://fucoder.com/code/se-hilite/
        { address: 'google\\.',         key: 'q' },         // Google
        { address: 'search\\.yahoo\\.', key: 'p' },         // Yahoo
        { address: 'search\\.msn\\.',   key: 'q' },         // MSN
        { address: 'search\\.live\\.',  key: 'query' },     // MSN
        { address: 'search\\.aol\\.',   key: 'userQuery' }, // AOL
        { address: 'ask\\.com',         key: 'q' },         // AOL
        { address: 'altavista\\.',      key: 'q' },         // AltaVista
        { address: 'feedster\\.',       key: 'q' }          // Feedster
    ];
    
    var defaults = {
        // array of terms to highlight; if empty we'll look up terms from the 
        // location and referrer
        terms: [],

        // Use the current location query string? If so, use searchKey to find
        // what query parameter to use; it's either a string or a regexp, the 
        // former will be turned into a regexp matching /^[searchKey]=(.*)$/i.
        // Note that the last group in a match *must* contain the terms.
        useLocation: true,
        searchKey: '(searchterm|SearchableText)',

        // Use the referrer to detect search engine queries? If so, use
        // referrers to detect these and their search keys. Is an 
        // array of {address, key} entries; key is treated as searchKey
        // above, with address turned into '^https?://(www\.)?[address]'
        // regular expressions, if not already a regexp.
        useReferrer: true,
        referrers: $.fn.highlightSearchTerms.referrers,
        
        // Should the current domain name and searchKey be included in
        // the referrers?
        includeOwnDomain: true,
        
        // Are terms matched case insensitive?
        caseInsensitive: true,
        // what terms are never to be highlighted (regexp)?
        filterTerms: /(not|and|or)/i,
        // What class is used to mark highlighted search terms?
        highlightClass: 'highlightedSearchTerm'
    };
    
    // Internal use only, test framework hooks.
    $.fn.highlightSearchTerms._test_location = null;
    $.fn.highlightSearchTerms._test_referrer = null;
    $.fn.highlightSearchTerms._highlighter = Highlighter;
})(jQuery);


/* - first_input_focus.js - */
// Focus on error or first element in a form with class="enableAutoFocus"
(function($) { $(function() {

    if ($("form div.error :input:first").focus().length) return;
    $("form.enableAutoFocus :input:not(.formTabs):visible:first").focus();

}); })(jQuery);


/* - accessibility.js - */
function setBaseFontSize($fontsize, $reset) {
    var $body = jQuery('body');
    if ($reset) {
        $body.removeClass('smallText').removeClass('largeText');
        createCookie("fontsize", $fontsize, 365);
    }
    $body.addClass($fontsize);
};

(function($) { $(function() {
        var $fontsize = readCookie("fontsize");
        if ($fontsize) setBaseFontSize($fontsize, 0);
}); })(jQuery);


/* - styleswitcher.js - */
// StyleSwitcher functions written by Paul Sowden
function setActiveStyleSheet(title, reset) {
    jQuery('link[rel*=style][title]').attr('disabled', true)
        .find('[title=' + title + ']').attr('disabled', false);
    if (reset) createCookie("wstyle", title, 365);
};

jQuery(function() {
    var style = readCookie("wstyle");
    if (style != null) setActiveStyleSheet(style, 0);
});


/* - toc.js - */
(function($) { $(function() {
    var dest = $('dl.toc dd.portletItem');
    var content = getContentArea();
    if (!content || !dest.length) return;
    
    dest.empty();

    var location = window.location.href;
    if (window.location.hash)
        location = location.substring(0, location.lastIndexOf(window.location.hash));

    var stack = [];
    // Get headers in document order
    $(content).find('*').not('.comment > h3').filter(function() { return /^h[1234]$/.test(this.tagName.toLowerCase()) })
        .not('.documentFirstHeading').each(function(i) {
        var level = this.nodeName.charAt(1);
        // size the stack to the current level
        while (stack.length < level) {
            var ol = $('<ol>');
            if (stack.length) {
                var li = $(stack[stack.length - 1]).children('li:last');
                if (!li.length)
                    // create a blank li for cases where, e.g., we have a subheading before any headings
                    li = $('<li>').appendTo($(stack[stack.length - 1]));
                li.append(ol);
            }
            stack.push(ol);
        }
        while (stack.length > level) stack.pop();
        
        $(this).before($('<a name="section-' + i + '" />'));
        $('<li>').append(
            $('<a />').attr('href', location + '#section-' + i)
                    .text($(this).text()))
            .appendTo($(stack[stack.length - 1]));
    });

    if (stack.length) {
        $('dl.toc').show();
        var oltoc = $(stack[0]);
        // first level is a level with at least two entries #11160
        var i = 1;
        while(oltoc.children('li').length == 1){
            oltoc = $(stack[i]);
            i += 1;
        }
        numdigits = oltoc.children().length.toString().length;
        //Use a clever class name to add margin that's MUCH easier to customize
        oltoc.addClass("TOC"+numdigits+"Digit");
        dest.append(oltoc);

        //scroll to element now.
        var wlh = window.location.hash;
        if (wlh) {
            var target = $(wlh);
            target = target.length && target
                || $('[name=' + wlh.slice(1) +']');
            var targetOffset = target.offset();
            if (targetOffset)
                $('html,body').animate({scrollTop: targetOffset.top}, 0);
        }
    }
}); })(jQuery);


