/**
 * Commonly used functions
 * based on jQuery
 *
 */

var KEY_PAGEUP   = 33;
var KEY_PAGEDOWN = 34;
var KEY_END      = 35;
var KEY_HOME     = 36;

var KEY_LEFT     = 37;
var KEY_UP       = 38;
var KEY_RIGHT    = 39;
var KEY_DOWN     = 40;

var KEY_SPACE    = 32;
var KEY_TAB      = 9;

var KEY_BACKSPACE = 8;
var KEY_DELETE    = 46;
var KEY_ENTER     = 13;
var KEY_INSERT    = 45;
var KEY_ESCAPE    = 27;

var KEY_F1        = 112;
var KEY_F2        = 113;
var KEY_F3        = 114;
var KEY_F4        = 115;
var KEY_F5        = 116;
var KEY_F6        = 117;
var KEY_F7        = 118;
var KEY_F8        = 119;
var KEY_F9        = 120;
var KEY_F10       = 121; 

var FOCUSABLE_ELEMENTS  = 'a,frame,iframe,label,input,select,textarea,button,*[tabindex]';

/**
 * Extends the jQuery element set to provide new methods (jQuery plugins)
 */
jQuery.fn.extend({

    /**
     */
    maxVal: function ( func ) {
        var maxVal = 0;
        $(this).each(function() {
            maxVal = Math.max(maxVal, eval('$(this).'+func));
        });
        return maxVal;
    },

    ancestor: function( selector ) {
        return matchingElement($(this), selector);
    },

    allFocusableElements: function () {
        return $(this).find(FOCUSABLE_ELEMENTS);
    },

    focusableElements: function () {
        return $(this).allFocusableElements()
                    .not('*[tabindex=-1]')
                    .filter(':visible,:enabled');
    },

    firstFocusableElement: function () {
        return $(this).focusableElements().slice(0,1);
    },

    lastFocusableElement: function () {
        return $(this).focusableElements().slice(-1);
    },

    // get the predecessing (in the code), focusable element
    preFocusableElement: function () {
        var prev = $(this).prevAll();
        $(this).log('prev.length='+prev.length);
        var elements = prev.focusableElements();
        if (elements.length > 0)
            return elements;
        else {
            var elements0 = false;
            prev.each( function () {
                if (!elements0)
                    elements0 = $(this).preFocusableElement();
            });
            if (elements0.length > 0)
                return elements0;
            else {
                return (this).parent().preFocusableElement();
            }
        }
    },

    // write to the FireBug Console
    // example: $(this).log("SOME INFO: " + SOME_VALUE);
    log: function (msg) {
        if (typeof(console)!='undefined')
            console.log("%s: %o", msg, this);
        return this;
    },

    // Convert pixel to em
    // example: $(PIXELVALUE).toEm(CONTAINER_OBJECT)
    toEm : function ( container ) {
        
        if (!container) 
            container = $('body');

        if (container.data('emVal')) 
            return container.data('emVal');

        else {
            var value = parseInt(this[0]);
            var testDiv = $('<div style="display: none; font-size: 1em; margin: 0; padding:0; height: auto; line-height: 1; border:0;">&nbsp;</div>').appendTo(container);
            var emSize = testDiv.height();
            testDiv.remove();
            
            var emValue;
            if (emSize)
                emValue = Math.ceil(value*110 / emSize)/100 + 'em';
            else
                emValue = 0;
            container.data('emVal', emValue);
            return emValue;
        }
    }

 });


function matchingElement (element, selector) {
    if(element.is(selector)) {
        return element;
    } else if (element.is("body")) {
        return null;
    } else {
        return matchingElement(element.parent(), selector);
    }
}

/**
 * Creates an object and sets the attribute 'value' to a passed value
 * (to enable passing by pointer)
 *
 * Arguments:
 *   - val: value
 */
function valueObject ( val ) {this.value = val;}

/**
 * Sets the width of grouped HTML-elements to the maximum width of the elements
 *
 * Use this function e.g. to unify the width of labels in a form.
 *
 * Usage:
 *  - in the HTML code
 *    - group the elements to by unified by setting the class of a parent
 *      element to 'f_unify'
 *    - set the class of the elements to by unified to 'f_unify-width'
 *
 *    E.g.:
 *      <form class="f_unify">
 *        <label class="f_unify-width" for="name">Name</label>
 *        <input type="text" id="name" name="name" />
 *        <label class="f_unify-width" for="name">Address</label>
 *        <input type="text" id="name" name="name" />
 *      </form>
 *  - call adjust_unifyElements()
 */
function adjust_unifyElements ( jqObj ) {

    var container;
    if (jqObj) container = jqObj;
    else container = $('.f_unify');

    container.each ( function () {
        var elementsW = $(this).find('.f_unify-width');
        var maxW = elementsW.maxVal('width()');
        var maxWem = (maxW) ? $(maxW).toEm($(this)) : 0;

        var elementsH = $(this).find('.f_unify-height');
        var maxH = elementsH.maxVal('height()');
        var maxHem = (maxH) ? $(maxH).toEm($(this)) : 0;

        if (maxWem || maxHem) {
            if (maxWem)
                elementsW.width(maxWem);
            if (maxHem)
                elementsH.height(maxHem);

            $(this).find('*[class*=f_unifyReposition_]').each(function () {
                var cssProp = get_variableClasses($(this),'f_unifyReposition_',false);
                $(this).css(cssProp,maxWem);
            });
            $(this).unbind('onshown');
        } else {
            $(this).bind('onshown', function() {
               adjust_unifyElements ( $(this) );
             });

        }
    });

 //   $('.f_unify .f_unify-width').maxVal(maxw,'width()').width(maxw.value);
}

/**
 * Initialise HTML elements to handle expansions
 *
 * ACCORDIONS!!!
 *
 * Use this function if you want elements on the page to be shown/hidden
 * dynamically by the user on click.
 *
 * Usage:
 *  An expansion-object
 *   - belongs to an expansion-group, and
 *   - consists of
 *     - a container: encapsulating the object
 *     - an expander (= the element to click)
 *     - a body: the area to be hidden/shown
 *  Expansion-objects can be nested
 *
 *  - in the HTML code
 *   - define the grouping container by setting the class to 'f_expandWrapper'
 *   - for every expansion-object:
 *    - define the expansion container by setting the class to 'f_expandContainer'
 *    - define the expander
 *      - define the expander buttons (to click for expansion and reduction):
 *        [ to maximise usability and accessibility, the contents for all expanders
 *        must be defined in a seperate element with the class 'f_expansionElements'
 *        and are inserted at the appropriate places at runtime (-> if javaScript is
 *        disabled, the expansion-functionalities are not displayed in the code);
 *        the element with the class 'f_expansionElements' will be removed from 
 *        the DOM at runtime ]
 *        - inside the element with the class 'f_expansionElements' create an
 *          element with the class 'SOME_CLASSNAME'; SOME_CLASSNAME should be 
 *          unique; the element will be referenced at runtime by SOME_CLASSNAME
 *          and inserted at the appropriate places
 *          - this element should have 2 div-childnodes with the classes set to
 *            - 'f_expand' for the expansion-button and
 *            - 'f_reduce' for the reduction-button respectively
 *          - within those child-nodes define your "buttons" (preferably using
 *            the a-tag)
 *          - you can define variables in the HTML code of the buttons, which
 *            will be replaced by some part of the content of the expansion
 *            container at runtime (this is usefull if e.g. the title-attribute
 *            has a value, dependant on the content; e.g. title="Open X" and X
 *            is the title, shown in the head):
 *            To insert an element:
 *            - define an element with the class 'f_expandVar_SOMETHING' within
 *              the button (this element will be replaced)
 *            - set the class of the replacement element to
 *              'f_expandVarSet_SOMETHING'
 *            To replace a value in the title or alt attribute:
 *            - insert 'f_expandVar_SOMETHING' in the value
 *            - set the class of the element, who's value should be used as
 *              replacement to 'f_expandVarSet_SOMETHING'
 *      - define an expander placeholder: add an empty element with the classes
 *        'f_expander' and 'SOME_CLASSNAME' to your layout where the expander
 *        should be; 'SOME_CLASSNAME' must be the last set class; the element
 *        '.f_expansionElements SOME_CLASSNAME' will be inserted here at runtime
 *    - define the body by setting the class to 'f_expandBody'
 *      - if the body should be hidden on start, set its class to
 *        'f_expandStartClosed'
 *
 * f_expandLabel
 *
 * E.g.
 *  <div class="f_expandWrapper">
 *      <div class="f_expandContainer">
 *          <div class="f_expandHead">
 *              <h2 class="f_expandVarSet_Title f_expandLabel">How to use this</h2>
 *              <div class="f_expander f_nodeExpand"></div>
 *          </div>
 *        <div class="f_expandBody f_expandStartClosed">
 *           <p>Some text</p>
 *          </div>
 *      </div>
 *  </div>
 *  <div class="f_expansionElements">
 *      <div class="f_nodeExpand">
 *          <div class="f_expand"><a href="#" title="Show f_expandVar_Title">expand</a></div>
 *          <div class="f_reduce"><a href="#" title="Hide f_expandVar_Title">reduce</a></div>
 *      </div>
 *  </div>
 *
 */
function init_expansion ( jqObj ) {

    if (jqObj)  
        expansionSet(jqObj);
    else    // manipulate all wrappers
        $('.f_expandWrapper')
            .each(function() {
                expansionSet($(this));
            });
}

function expansionSet ( jqObj ) {
    btnName = '';
    var expansionNum = 0;
    
    var wrapper = jqObj;
    var expanders = new Array();
    // initialise all expansion-objects of this wrapper
    jqObj.find('.f_expandContainer')
        .not($(this).find('.f_expandWrapper .f_expandContainer'))
        .each( function ( componentNum ) {

        expansionNum++;

        // get the elements of the expansion-objects
        var container = $(this);
        var head = container.find('.f_expandHead')
                            .not(container.find('.f_expandContainer .f_expandHead'));
        var body = container.find('.f_expandBody')
                            .not(container.find('.f_expandContainer .f_expandBody'));

        // set WAI ARIA attributes
        var label = head.find('.f_expandLabel');
        var labelID = label.attr('id');
        if (!labelID) {
            labelID = 'explb_'+expansionNum;
            label.attr('id', labelID);
        }
        body.attr('role', 'tabpanel');
        body.attr('aria-labelledby', labelID);

        // get the expander placeholder
        head.find('.f_expander')
            .each(function() {

                /* set the expansion buttons */

                // if expansion buttons are to load -> load
                var clone = $(this);
                var realClone = false;
                if ($(this).find('.f_expand').length == 0) {
                    // get the last classname (defines, which expander buttons to use)
                    btnName = $(this).attr('class').split(' ').slice(-1);
                    // clone the expander buttons
                    clone = $('.f_expansionElements .'+btnName).clone();
                    realClone = true;
                }

                // define which area is the tab
                var expander;
                if ($(this).hasClass('f_expandFunc2Head')) expander = head;
                else expander = $(this);
                expanders.push(expander);
                // set WAI ARIA attributes
                expander.attr('role' ,'tab');
                // only first tab is in tab-order
                if (!componentNum) expander.attr('tabindex', '0');
                else expander.attr('tabindex', '-1');

                // if the body is closed at start, show the expansion-button;
                // else show the reduction-button
                // set visibility of body and WAI ARIA attributes
                if (body.hasClass('f_expandStartClosed')) {
                    clone.find('.f_reduce').hide();
                    body.attr('aria-hidden', 'true').hide();
                    expander.attr('aria-expanded', 'false');
                } else {
                    clone.find('.f_expand').hide();
                    body.attr('aria-hidden', 'false');
                    expander.attr('aria-expanded', 'true');
                }


                // set the click functionalities

                var showSpeed = 'slow';
                if ($(this).hasClass('f_expandNoAnim'))
                    showSpeed = '';
                else if ($(this).hasClass('f_expandFast'))
                    showSpeed = 'fast';

                var reductionBtn = clone.find('.f_reduce');
                var reduceFunc = function () {
                    body.attr('aria-hidden', 'true').hide(showSpeed);
                    container.removeClass('f_expanded');
                    expander.attr('aria-expanded', 'false');
                    reductionBtn.hide();
                    expansionBtn.show();
                };

                defaultContentId = get_variableClasses(body.parent(),'f_expandDefaultContent_',false);
                var defaultContent = null;
                if (defaultContentId) defaultContent = $('#'+defaultContentId);

                var expansionBtn = clone.find('.f_expand');
                var expandFunc = function () {
                    if (defaultContent) defaultContent.hide();
                    body.attr('aria-hidden', 'false')
                        .show(showSpeed, function () {
                            $(this)
                                .find('.f_triggerShown')
                                .trigger('onshown');
                        });
                    container
                        .addClass('f_expanded');
                    expander.attr('aria-expanded', 'true');
                    expansionBtn.hide();
                    reductionBtn.show();

                }

                var preventUnfocusedTabindex = function () {};
                var resetUnfocusedTabindex = function () {};
                if (wrapper && wrapper.hasClass('f_expandPreventUnfocusedTabindex')) {
                    preventUnfocusedTabindex = function () {
                        body.focusableElements().each( function () {
                            $(this)
                                .addClass('f_expandTabindex_'+$(this).attr('tabindex'))
                                .attr('tabindex', '-1');
                        });
                    }
                    resetUnfocusedTabindex = function () {
                        body.find('*[class*=f_expandTabindex_]').each(function() {
                            var origTabindex = get_variableClasses($(this),'f_expandTabindex_',false);
                            $(this).log('RESET!: '+origTabindex);
                            $(this)
                                .removeClass('f_expandTabindex_'+origTabindex)
                                .attr('tabindex', origTabindex);
                        });
                    }
                }
                var focused = function () {
                        for (var i = 0; i < this.expanders.length; i++) {
                            if (this.expanders[i][0]!=$(this)[0]) {
                                this.expanders[i][0].preventUnfocusedTabindex();
                            }
                        }
                        resetUnfocusedTabindex();
                        $(this).attr('tabindex', '0');
                    }

                expander.each(function() {
                        if (body.hasClass('f_expandStartClosed')) $(this).data('visible', false);
                        else $(this).data('visible', true);

                        this.preventUnfocusedTabindex = preventUnfocusedTabindex;
                        this.resetUnfocusedTabindex = resetUnfocusedTabindex;
                        this.focused = focused;

                        $(this)
                            .css('cursor', 'pointer')
                            .mouseenter ( function () {
                                $(this).addClass('f_hasHover');
                            })
                            .mouseleave (function () {
                                $(this).removeClass('f_hasHover');
                            })
                            .click ( function () {
                                if ($(this).data('visible')) reduceFunc();
                                else expandFunc();
                                for (var i = 0; i < this.expanders.length; i++) {
                                    if (this.expanders[i][0]!=$(this)[0]) {
                                        this.expanders[i][0].preventUnfocusedTabindex();
                                        this.expanders[i].attr('tabindex', '-1')
                                                         .attr('aria-selected', 'false');
                                    }
                                }
                                resetUnfocusedTabindex();
                                $(this).attr('tabindex', '0')
                                       .attr('aria-selected', 'true');
                                $(this).data('visible', !$(this).data('visible'));
                            })
                            // set keyboard navigation for the tabs
                            .focus ( focused )
                            .keydown ( function (event) {
                                var code = (event.keyCode ? event.keyCode : event.which);
                                if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
                                    switch( code ) {
                                        // Up arrow - behaves the same as left arrow
                                         case KEY_UP:
                                             event.preventDefault();
                                        // Left arrow - press of up/left arrow keys moves focus to the previous logical accordion header.
                                        // When focus reaches the first header, further up/left arrow key presses wrap to the last header.
                                         case KEY_LEFT:
                                             if (!this.expanderNum) prev = this.expanders[this.expanders.length-1];
                                             else prev = this.expanders[this.expanderNum-1];
                                             prev.focus();
                                             $(this).attr('tabindex', '-1');
                                             break;
                                        // Down arrow - behaves the same as right arrow
                                         case KEY_DOWN:
                                             event.preventDefault();
                                        // Right arrow - press of down/right moves focus to the next logical accordion header.
                                        // When focus reaches the last header, further down/right arrow key presses wrap to the first header.
                                         case KEY_RIGHT:
                                             if (this.expanderNum==this.expanders.length-1) next = this.expanders[0];
                                             else next = this.expanders[this.expanderNum+1];
                                             next.focus();
                                             $(this).attr('tabindex', '-1');
                                             break;
                                         // Home - press of home key moves focus to the first accordian header.
                                         case KEY_HOME:
                                             this.expanders[0].focus();
                                             event.preventDefault();
                                             $(this).attr('tabindex', '-1');
                                             break;
                                         // End - press of end key moves focus to the last accordian header.
                                         case KEY_END:
                                             this.expanders[this.expanders.length-1].focus();
                                             event.preventDefault();
                                             $(this).attr('tabindex', '-1');
                                             break;
                                         case KEY_SPACE:
                                         // Enter - press of enter key opens/closes the accordion panel (click)
                                         case KEY_ENTER:
                                             $(this).click();
                                             event.preventDefault();
                                             break;
                                         case KEY_TAB:
                                             $(this).log("TAB ");
                                             var focusableElement = body.firstFocusableElement();
                                             if (focusableElement.length > 0) {
                                                 focusableElement.focus();
                                                 event.preventDefault();
                                                 event.stopPropagation();
                                             }
                                             break;
                                    }
/*                                    } else if (!event.ctrlKey && event.shiftKey && !event.altKey) {
                                    switch( code ) {
                                         case KEY_TAB:
                                             $(this).log("SHIFT TAB ON ACCORDEON HEAD");
                                             event.preventDefault();
                                             event.stopPropagation();
                                             wrapper.preFocusableElement().focus();
                                             break;
                                    }*/
                                }
                            })
                            .keypress(function (event) {
                                if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
                                    var code = (event.keyCode ? event.keyCode : event.which);
                                    switch( code ) {
                                         case KEY_ENTER:
                                             event.preventDefault();
                                             break;
                                    }
                                }
                            });


                    });

                if (container.hasClass('f_expandCloseOnBlur')) {
                    container.focusout(function() {
                            if (!container.data('focusin')) {
                                timerRegisterOut = window.setTimeout(function() {
                                    if (expander.data('visible'))
                                        expander.click();
                                }, 0);
                            }
                            container.data('focusin',false);
                            if (timerClearIn) window.clearTimeout(timerClearIn);
                        })
                        .focusin(function() {
                            container.data('focusin',true);
                            timerClearIn = window.setTimeout(function() {
                                container.data('focusin',false);
                            }, 50);
                            if (typeof(timerRegisterOut)!='undefined') window.clearTimeout(timerRegisterOut);
                        });
                }

                body.click(function () {
                        expander[0].focused();//resetUnfocusedTabindex();
                    })
                    .keydown(function (event) {
                        if (event.ctrlKey && !event.shiftKey && !event.altKey)
                            var code = (event.keyCode ? event.keyCode : event.which);
                        switch( code ) {
                            // Ctrl+Up Arrow - Moves focus from anywhere in the accordion content to its associated tab.
                             case KEY_UP:
                                 event.preventDefault();
                                 event.stopPropagation();
                                 expander.focus();
                                 break;
                            // Ctrl+PageUp - When focus is inside of an accordion pane, pressing Ctrl-PageUp moves focus to the header of the previous accordion pane.
                            // When focus is in the first accordion header content, pressing Ctrl-PageUp moves focus to the last accordion header.
                             case KEY_PAGEUP:
                                 event.preventDefault();
                                 event.stopPropagation();
                                 if (!expander[0].expanderNum) prev = expander[0].expanders[expander[0].expanders.length-1];
                                 else prev = expander[0].expanders[expander[0].expanderNum-1];
                                 prev.focus();
                                 break;
                            // Ctrl+PageDown - When focus is inside of an accordion pane, pressing Ctrl-PageDown moves focus to the header of the next accordion pane.
                            // When focus is in the last accordion header content, pressing Ctrl-PageDown moves focus to the first accordion header.
                             case KEY_PAGEDOWN:
                                 event.preventDefault();
                                 event.stopPropagation();
                                 if (expander[0].expanderNum==expander[0].expanders.length-1) next = expander[0].expanders[0];
                                 else next = expander[0].expanders[expander[0].expanderNum+1];
                                 next.focus();
                                 break;
                        }
                    });

                clone.find('a')
                    .attr('tabindex', '-1')
                    .click(function (event) {
                        event.preventDefault();
                    });

                /* replace the content variables in the expansion buttons */

                // replace all elements with the class 'f_expandVar_SOMETHING'
                // by a copy of the element with the class 'f_expandVarSet_SOMETHING'
                clone.find('*[class*=f_expandVar_]').each(function() {
                    $(this).replaceWith(
                        container.find('.f_expandVarSet_'+$(this).attr('class').substr(12))
                            .not(container.find('.f_expandContainer *[class*=f_expandVarSet_]'))
                        .clone());
                });

                // replace 'f_expandVar_SOMETHING' in attribute-values by the
                // values of the element with the class 'f_expandVarSet_SOMETHING'

                // set the attributes to check
                var atbAr = new Array("title", "alt");
                for (var i = 0; i < atbAr.length; ++i) {

                    clone.find('*['+atbAr[i]+'*=f_expandVar_]').each(function() {
                        // get the variable name
                        var aval = $(this).attr(atbAr[i]);
                        var vars = aval.match(/f_expandVar_[a-zA-Z0-9_-]*/);

                        // get the value
                        var aval0 = container.find('.f_expandVarSet_'+vars[0].substr(12))
                                            .not(container.find('.f_expandContainer *[class*=f_expandVarSet_]'))
                                        .text();

                        // replace the variable by the value
                        var reg = new RegExp(vars[0],"g");
                        aval = aval.replace(reg, aval0);

                        $(this).attr(atbAr[i], aval);
                    });
                }


                // add the expansion buttons to the expander placeholder
                if (realClone)
                    $(this).append(clone);
            });

    });

    for (var i = 0; i < expanders.length; i++) {
        expanders[i][0].expanders = expanders;
        expanders[i][0].expanderNum = i;
    }

    // set WAI ARIA attributes
    if (wrapper) {
        wrapper.attr('role', 'tablist');
        wrapper.attr('aria-multiselectable', 'true');
    }

}




function init_removeElements() {
    $('.f_remove').remove();
}


/**
 * TAB PANELS!!
 *
 */
function init_anchorExpansion () {
    var anchorLinksNum = 0;

    $('.f_expandAnchorList').each(function() {
        
        $(this).attr('role', 'tablist');
        var list = $(this);

        $(this).find('li')
                .attr('role', 'tab')
                .attr('tabindex', '-1')
                .each(function() {

            var anchorLinkElement = $(this);

            anchorLinksNum++;

            var a = $(this).find('a').attr('tabindex', '-1');
            a.click(function (event) {
                anchorLinkElement.focus();
                event.preventDefault();
            });
            var href = a.attr('href');

            var anchorDiv = $(href);
            var body;
            if (list.hasClass('f_expandAnchorListPreventDefault'))
                body = anchorDiv;
            else {
                body = anchorDiv.parent();    // necessary for opera if default is not prevented (bug with jumping to anchors on divs with anim) <div><div id=href></div>...</div> !!!
            }
            defaultContentId = get_variableClasses(body.parent(),'f_expandDefaultContent_',false);
            var defaultContent = null;
            if (defaultContentId) defaultContent = $('#'+defaultContentId);

            // set WAI ARIA attributes
            var label;
            if ($(this).hasClass('f_expandAnchorListLabel'))
                label = $(this);
            else label = $(this).find('.f_expandAnchorListLabel');
            var labelID = label.attr('id');
            if (!labelID) {
                labelID = 'anllb_'+anchorLinksNum;
                label.attr('id', labelID);
            }
            body.attr('role', 'tabpanel');
            body.attr('aria-labelledby', labelID);

            var listGroup = get_variableClasses($(this),'f_expandAnchorListGroup_',false);
            if (listGroup) listGroup = 'f_expandAnchorListGroup_'+listGroup;

            var hideVisibility = false;
            if ($(this).hasClass('f_expandAnchorListHideVisibility'))
                hideVisibility = true;
            this.hideTab = function () {
                    body.stop(true,true)
                        .hide()
                        .attr('aria-hidden', 'true')
                        .removeClass('f_expanded');
                    $(this).removeClass('f_expanded')
                        .attr('aria-selected', 'false')
                        .attr('aria-expanded', 'false');
                        
                };

            var showSpeed = 'slow';
            if (list.hasClass('f_expandAnchorListNoAnim'))
                showSpeed = '';


            this.focusTmp = function ( event ) {
                this.showTab(event);
//                event.preventDefault();
                event.stopPropagation();
            }
            this.showTab = function ( event ) {
                // remove unfocus
                var origTabindex = get_variableClasses($(this),'f_expandTabindex_',false);
                if (origTabindex)
                    $(this).removeClass('f_expandTabindex_'+origTabindex);
                $(this).attr('tabindex', '0');

                if (!$(this).hasClass('f_expanded')) {
                    if (listGroup)
                        $('.'+listGroup).not($(this)).each(function() {
                            this.hideTab();
                        });
                    else
                        $(this).siblings('li')
                                .each(function() {
                                    this.hideTab();
                                });
                    $(this).siblings('li').each ( function () {
                        var origTabindex = get_variableClasses($(this),'f_expandTabindex_',false);
                        if (origTabindex)
                            $(this).removeClass('f_expandTabindex_'+origTabindex);
                        $(this).attr('tabindex', '-1');
                    });


                    if (defaultContent) defaultContent.hide();
                    body.show(showSpeed) // show('slow')
                        .attr('aria-hidden', 'false')
                        .addClass('f_expanded');
                    $(this).addClass('f_expanded')
                        .attr('aria-selected', 'true')
                        .attr('aria-expanded', 'true');
//                        .siblings('li')
//                            .attr('tabindex', '-1');
                    if (!list.hasClass('f_expandAnchorListPreventDefault')) {
                        window.location.hash = href;
             //           $(this).focus(); // del for opera
                    }
                    event.stopPropagation();
                }
            };

            if (!$(this).hasClass('f_expandAnchorListShow')) {
                body.hide();
                $(this).attr('aria-selected', 'false')
                        .attr('aria-expanded', 'false');
                body.attr('aria-hidden', 'true');
            } else {
                $(this).addClass('f_expanded');
                $(this).attr('aria-selected', 'true')
                        .attr('aria-expanded', 'true');
                body.attr('aria-hidden', 'false');
            }

            // set keyboard navigation for bodies
            var tab = $(this);
            body.keydown(function (event) {
                    var code = (event.keyCode ? event.keyCode : event.which);
                    if (event.ctrlKey && !event.shiftKey && !event.altKey) {
                        switch( code ) {
                            // Ctrl+Up Arrow - with focus anywhere within the tab panel, pressing Ctrl+Up Arrow will move focus to the tab for that panel.
                             case KEY_UP:
                                 event.preventDefault();
                                 event.stopPropagation();
                                 tab.focus();
                                 break;
                            // Ctrl+PageUp - When focus is inside of a tab panel, pressing Ctrl+PageUp moves focus to the tab of the previous tab in the tab list and activates that tab.
                            // When focus is in the first tab panel in the tab list, pressing Ctrl+PageUp will move focus to the last tab in the tab list and activate that tab.
                             case KEY_PAGEUP:
                                 event.preventDefault();
                                 event.stopPropagation();
                                 prev = tab.prev();
                                 if (prev[0]) prev.focus();
                                 else tab.nextAll('li:last').focus();
                                 break;
                            // Ctrl+PageDown When focus is inside of a tab panel, pressing Ctrl+PageDown moves focus to the tab of the next tab in the tab list and activates that tab.
                            // When focus is in the last tab panel in the tab list, pressing Ctrl+PageDown will move focus to the first tab in the tab list and activate that tab.
                             case KEY_PAGEDOWN:
                                 event.preventDefault();
                                 event.stopPropagation();
                                 next = tab.next();
                                 if (next[0]) next.focus();
                                 else tab.prevAll('li:last').focus();
                                 break;
                        }
                    } else if (!event.ctrlKey && event.shiftKey && !event.altKey) {
                        $(this).log("SHIFT TAB BODY");
                        switch( code ) {
                            case KEY_TAB:
                                if (shiftTabElement && $(this).has(shiftTabElement)) {
                                    $(this).log("SHIFT TAB BODY "+href);
                                    event.preventDefault();
                                    event.stopPropagation();
                                    tab.focus();
                                }
                                shiftTabElement = "";
                                break;
                        }

                    }
                });

            
            $(this)
                .click(this.showTab)
                .focus(this.focusTmp)
                // set keyboard navigation for the tabs
                .keydown(function (event) {
                    var code = (event.keyCode ? event.keyCode : event.which);
                    if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
                        switch( code ) {
                            // Up arrow - behaves the same as left arrow in order to support vertical tabs
                             case KEY_UP:
                            // Left Arrow - with focus on a tab, pressing the left arrow will move focus to the previous tab in the tab list and activate that tab.
                            // Pressing the left arrow when the focus is on the first tab in the tab list will move focus and activate the last tab in the list.
                             case KEY_LEFT:
                                 event.preventDefault();
                                 event.stopPropagation();
                                 prev = $(this).prev();
                                 if (prev[0]) prev.focus();
                                 else $(this).nextAll('li:last').focus();
                                 break;
                            // Down arrow - behaves the same as right arrow in order to support vertical tabs
                             case KEY_DOWN:
                            // Right Arrow - with focus on a tab, pressing the right arrow will move focus to the next tab in the tab list and activate that tab.
                            // Pressing the right arrow when the focus is on the last tab in the tab list will move focus to and activate the first tab in the list.
                             case KEY_RIGHT:
                                 event.preventDefault();
                                 event.stopPropagation();
                                 next = $(this).next();
                                 if (next[0]) next.focus();
                                 else $(this).prevAll('li:last').focus();
                                 break;
                             case KEY_HOME:
                                 event.preventDefault();
                                 event.stopPropagation();
                                 $(this).prevAll('li:last').focus();
                                 break;
                             case KEY_END:
                                 event.preventDefault();
                                 event.stopPropagation();
                                 $(this).nextAll('li:last').focus();
                                 break;
                             case KEY_TAB:
                                $(this).log("TAB "+href);
                                 var focusableElement = body.firstFocusableElement();
                                 if (focusableElement.length > 0) {
                                     focusableElement.focus();
                                     event.preventDefault();
                                     event.stopPropagation();
                                 }
                                 break;
                        }
                    } else if (!event.ctrlKey && event.shiftKey && !event.altKey) {
                        $(this).log("SHIFT TAB ");
                        switch( code ) {
                            case KEY_TAB:
                                $(this).log("SHIFT TAB "+href);
                                shiftTabElement = $(this);
                            //    body.data('leavePanel', true);
                            //    tab.focus();
                            //    event.preventDefault();
                            //    event.stopPropagation();
                                break;
                        }

                    }
                });
        })
        .slice(0,1)
        .attr('tabindex', '0');
    });

}


function init_jumps () {
    $('*[class*=f_jumpTo_]').each(function () {
        var jumpto = get_variableClasses($(this),'f_jumpTo_',false);
        if (!$(this).attr('tabindex')) $(this).attr('tabindex','0');
        $(this).focus(function () {
            alert("FOCUS FROM JUMP");
            $('#'+jumpto).firstFocusableElement().focus();
        });
    });

}

/* <input type="radio|checkbox" class="f_checkedExtension_EXTENSION_ID" ...>
 * shows the element with id EXTENSION_ID if the input element is checked
 * hides the element, if the input is unchecked
 *
*/
function init_checkedExtension () {
    $('*[class*=f_checkedExtension_]').each(function () {
        var extensionID = get_variableClasses($(this),'f_checkedExtension_',false);
        var extension = $('#'+extensionID);
        $(this).change( function () {
                wasChecked = $(this).data('checked');
                isChecked = $(this).is(':checked');
                if (wasChecked!=isChecked) {
                    if (wasChecked)
                        extension.hide();
                    else
                        extension.show();
                    $(this).data('checked', isChecked);
                }
            })
            .data('checked', true);
        if (!$(this).is(':checked'))
            $(this).change();

        // for radio buttons the change has to be detected by the radio-button-group
        if ($(this).is(':radio')) {
            var subject = $(this);
            $('*[name='+subject.attr('name')+']').not(subject)
                .change (function () {
                    subject.change();
                });
        }
    });

}

function init_checkboxes () {

    $('.f_checkbox')
        .each( function () {
            var onCheckCheck = get_variableClasses($(this),'f_checkbox_c_c_',true);
            var onCheckUncheck = get_variableClasses($(this),'f_checkbox_c_uc_',true);
            var onUncheckCheck = get_variableClasses($(this),'f_checkbox_uc_c_',true);
            var onUncheckUncheck = get_variableClasses($(this),'f_checkbox_uc_uc_',true);
            this.checkbox = $(this).find('input:checkbox')
                                    .attr('tabindex','-1')
                                    .click( function () {
                                        this.isClicked = true;
                                    });
            this.uncheck = function () {
                this.checkbox.attr('checked','');
            };
            this.check = function () {
                this.checkbox.attr('checked','checked');
            };
            this.onuncheck = function () {
                for (var i = 0; i < onUncheckCheck.length; ++i)
                    $('#'+onUncheckCheck[i]+'.f_checkbox,#'+onUncheckCheck[i]+' .f_checkbox')
                        .each( function () {this.check();});
                for (i = 0; i < onUncheckUncheck.length; ++i)
                    $('#'+onUncheckUncheck[i]+'.f_checkbox,#'+onUncheckUncheck[i]+' .f_checkbox')
                        .each( function () {this.uncheck();});
            };
            this.oncheck = function () {
                for (i = 0; i < onCheckCheck.length; ++i)
                    $('#'+onCheckCheck[i]+'.f_checkbox,#'+onCheckCheck[i]+' .f_checkbox')
                        .each( function () {this.check();});
                for (i = 0; i < onCheckUncheck.length; ++i)
                    $('#'+onCheckUncheck[i]+'.f_checkbox,#'+onCheckUncheck[i]+' .f_checkbox')
                        .each( function () {this.uncheck();});
            };

            $(this)
                .attr('tabindex','0')
                .click( function (event) {
                    fromcheckbox = this.checkbox[0].isClicked;
                    if (this.checkbox.is(':checked')) {
                        if (fromcheckbox) this.oncheck();
                        else {
                            this.uncheck();
                            this.onuncheck();
                        }
                    } else {
                        if (fromcheckbox) this.onuncheck();
                        else {
                            this.check();
                            this.oncheck();
                        }
                    }
                    this.checkbox[0].isClicked = false;
                    if (!fromcheckbox) event.preventDefault();
                })
                .keydown(function (event) {
                    if (!event.ctrlKey && !event.shiftKey && !event.altKey)
                        var code = (event.keyCode ? event.keyCode : event.which);
                        switch( code ) {
                             case KEY_SPACE:
                                 $(this).click();
                                 break;
                        }
                });

        });


    $('*[class*=f_checkbox_ac_c_]').each(function () {
        this.check = get_variableClasses($(this),'f_checkbox_ac_c_',true);
        $(this).click( function () {
            if (!$(this).find('input:checkbox').not(':checked')[0]) {
                for (var i = 0; i < this.check.length; ++i)
                    $('#'+this.check[i]+'.f_checkbox,#'+this.check[i]+' .f_checkbox')
                        .each( function () {this.check();});
            }
        });
    });
}

/**
 * Extends the href to a parent region.
 *
 * Usage:
 *  - in the HTML code
 *    - set the class of the element to trigger the link to 'f_expandHref'
 *    - set the class of the a-element to take the href from to 'f_expandHrefUrl'
 *
 *    E.g.:
 *      <div class="f_expandHref">
 *        <h3><a href="SOMELINK" class="f_expandHrefUrl">Some Titel</a></h3>
 *        <p>Some text</p>
 *      </div>
 *  - call init_expandHref()
 */


function init_expandHref () {
    $('.f_expandHref').each ( function () {
        var link = $(this).find('.f_expandHrefUrl');
        var href = link.attr('href');
        var title = link.attr('title');
        $(this)
            .attr('title', title)
            .css('cursor', 'pointer')
            .click( function () {
                window.location.href = href;
            })
            .mouseenter( function () {
                $(this).addClass('f_hasHover');
            })
            .mouseleave( function () {
                $(this).removeClass('f_hasHover');
            });
    });
}

function init_tooltips () {

    $('.f_tooltip').each( function () {

        var preventDefault = !$(this).hasClass("f_tooltipAllowLink");
        var tooltipContent = $(this).find('.f_tooltipContent');
        var tooltipTrigger = $(this).find('.f_tooltipTrigger');

        if (tooltipContent.length == 0) { // tooltips are defined once in a dl
            tooltipContent = $('<div class="f_tooltipContent"></div>');
            var href = $(this).find('a').attr('href');
            // only remove tooltips that are not needed
            $('dt'+href).removeClass('f_remove');
            $('dt'+href+' + dd').removeClass('f_remove');
            tooltipContent
                .append($('dt'+href+' + dd').contents()
                                            .clone());
            $(this).append(tooltipContent);
        }
        
        tooltipContent
            .attr('role', 'tooltip')
            .attr('aria-hidden', 'true')
            .hide();
        tooltipTrigger
            .attr('aria-describedby', tooltipContent.attr('id'));

        var show = function () {
            tooltipContent
                .attr('aria-hidden', 'false')
                .show();
     //       alert($(this).position().top);
        }
        var hide = function () {
            tooltipContent
                .attr('aria-hidden', 'true')
                .hide();
        }

        $(this).mouseover(show)
            .focusinside(show)
            .mouseout(function(event) {
                if (!$(this).has($(event.relatedTarget)).length > 0)
                    hide();
            })
            .focusoutside(hide);
            
        if (preventDefault)
            $(this).find('.f_tooltipTrigger')
                .click(function(event) {
                    event.preventDefault();
                });
    });
    $(document).keydown(function (event) {
        if (!event.ctrlKey && !event.shiftKey && !event.altKey)
            var code = (event.keyCode ? event.keyCode : event.which);
        if (code == KEY_ESCAPE)
            $('.f_tooltip').focusoutside();
    });
}

function init_dialogTooltip () {

    $('.f_dialogTooltip').each( function () {

        var container = $(this);

        var dialogId = $(this).find('a')
                                .click( function (event) {
                                    event.preventDefault();
                                })
                                .attr('tabindex', '-1')
                                .attr('href');
        var dialog = $(dialogId);
        dialog
            .attr('role', 'dialog')
            .attr('aria-expanded', 'false')
            .attr('aria-labelledby', $(this).attr('id'))
            .hide();

        var trigger = $('.f_dialogTooltipTrigger', this);

        var show = function () {
            trigger.addClass('f_expanded');
            dialog
                .attr('aria-expanded', 'true')
                .attr('tabindex', '0')
                .show()
                .find('.f_triggerShown')
                    .trigger('onshown');
        }
        var hide = function () {
            trigger.removeClass('f_expanded');
            dialog
                .attr('aria-expanded', 'false')
                .attr('tabindex', '-1')
                .hide();
        }

        var firstFocusableDialogElement = dialog.firstFocusableElement();

        firstFocusableDialogElement
            .keydown(function (event) {
                var code = (event.keyCode ? event.keyCode : event.which);
                if (!event.ctrlKey && event.shiftKey && !event.altKey) {
                    switch( code ) {
                        case KEY_TAB:
                            trigger.focus();
                            event.preventDefault();
                            event.stopPropagation();
                            break;
                    }
                }
            });

        trigger
            .attr('aria-controls', dialogId.substr(1))
            .attr('tabindex', '0')
            .click( function () {
                if (dialog.attr('aria-expanded')=='false') {
                    show();
                } else {
                    hide();
                }
            })
            .keydown(function (event) {
                var code = (event.keyCode ? event.keyCode : event.which);
                if (!event.ctrlKey && !event.shiftKey && !event.altKey) {
                    switch( code ) {
                        case KEY_ENTER:
                            $(this).click();
                            break;
                        case KEY_TAB:
                            if (dialog.attr('aria-expanded')=='true'
                                && firstFocusableDialogElement.length > 0) {
                                firstFocusableDialogElement.focus();
                                event.preventDefault();
                                event.stopPropagation();
                            }
                            break;
                    }
                }
            });


        container
            .append(dialog)
            .focusout( function ( event ) {
                $(event.target).log('FOCS OUT');
                if (!container.data('focusin')) {
                    container.data('timerRegisterOut', window.setTimeout(function() {
                            hide();
                        }, 0));
                }
                container.data('focusin',false);
                if (typeof(container.data('timerClearIn'))!='undefined')
                    window.clearTimeout(container.data('timerClearIn'));
            })
            .focusin( function ( event ) {
//                event.stopPropagation();
                $(event.target).log('FOCS IN');
                container.data('focusin',true);
                container.data('timerClearIn', window.setTimeout(function() {
                        container.data('focusin',false);
                    }, 50));
                if (typeof(container.data('timerRegisterOut'))!='undefined')
                    window.clearTimeout(container.data('timerRegisterOut'));
            });
            
        if (dialog.hasClass('f_dialogTooltipContentShow'))
            show();
    });

    $(document).keydown(function (event) {
        if (!event.ctrlKey && !event.shiftKey && !event.altKey)
            var code = (event.keyCode ? event.keyCode : event.which);
        if (code == KEY_ESCAPE)
            $('.f_dialogTooltip').focusout();

    });

}

// select the contents of the input field when field gets focus
function init_inputSelect () {
    $('.f_inputSelect')
        .click( function () {
            this.select();
        })
        .focus( function () {
            $(this).click();
        });

}

function init_textSelect () {
    $('.f_textSelect')
        .click ( function () {
            if ($.browser.msie) {
                var range = document.body.createTextRange();
                range.moveToElementText(this);
                range.select();
            } else if ($.browser.mozilla || $.browser.opera) {
                var selection = window.getSelection();
                var range = document.createRange();
                range.selectNodeContents(this);
                selection.removeAllRanges();
                selection.addRange(range);
            } else if ($.browser.safari) {
                var selection = window.getSelection();
                selection.setBaseAndExtent(this, 0, this, 1);
            }
        });
}


function init_tableHighlight () {
    $('.f_tableHighlight').each( function () {
        var cells = new Array();

        var rowOnly = false;
        if ($(this).hasClass('f_tableHighlightRowOnly'))
            rowOnly = true;

        $('tr', this).each( function () {
            var row = $('td', this);
            if (!rowOnly) row.add($('th', this));
            cells.push(row);
        });

        for (var row0 in cells) {

            cells[row0]
                .data('rowOnly', rowOnly)
                .data('row', cells[row0])
                .mouseover( function () {
                    var row = $(this).data('row');
                    row.addClass('f_highlight');
                    if (!$(this).data('rowOnly')) {
                        var index = row.index($(this));
                        for (var row1 in cells) {
                            cells[row1].slice(index,index+1).addClass('f_highlight');
                        }
                    }
                })
                .mouseout( function () {
                    var row = $(this).data('row');
                    row.removeClass('f_highlight');
                    if (!$(this).data('rowOnly')) {
                        var index = row.index($(this));
                        for (var row1 in cells) {
                            cells[row1].slice(index,index+1).removeClass('f_highlight');
                        }
                    }
                })
        }

    });

}


function init_gallery ( jqObj ) {

    var container;
    if (jqObj) container = jqObj;
    else container = $('body');

    // hide gallery if it is empty
    if (!jqObj && !$('#f_galleryimageContainer').has('#f_galleryimage').length)
        $('#f_galleryimageWrapper').hide();

    var showImage = false;

    container.find('.f_gallerytrigger')
        .each ( function () {

            var href = $(this).attr('href');

            // get imageid
            var reg = new RegExp('[a-zA-Z0-9_-]*.html','g');
            var match0 = href.match(reg)[0];
            match0 = match0.split('.');
            var imgid = '';
            for (var i = 0; i < match0.length-1; ++i)
                imgid = imgid + match0[i];

            // set image to load on start if set by the hash
            if ('#'+imgid == window.location.hash)
                showImage = $(this);

            $(this).click( function ( event ) {
                
                var trigger = $(this);
                trigger.attr('style', 'cursor: wait');
                $('body').attr('style', 'cursor: wait');

                $('#f_galleryloader').show();   // show loading animation

                if (!$('#f_galleryimageWrapper').is(":visible")) 
                    $('#f_galleryPosition').css({position: "absolute",
                                    top: $(window).scrollTop()});
                            
                $('#f_galleryimageWrapper').show('slow', function() {   // if first fill of gallery -> show gallery
                                // jump to the exact position (changes during show) of the gallery in the document
                                window.location.hash = '#f_galleryAnchor';
                                window.location.hash = imgid;   // set address
                            });
                // jump to the gallery in the document
                window.location.hash = '#f_galleryAnchor';
                window.location.hash = imgid;   // set address
                
                $('#f_galleryimageContainer')
                    .load( href+' #f_galleryimage' , 'co=1', function( response, status, xhr ) {

                        $(this).find('#f_galleryloader').hide();    // hide loading animation

                        if (status == "error") {
                            var msg = "Sorry but there was an error: ";
                            $(this).html(msg + xhr.status + " " + xhr.statusText);
                            alert(msg + xhr.status + " " + xhr.statusText);
                        }

                        init_gallery($(this));  // set clickfunctionalities for loaded gallerycontent (next, prev, etc)

                        $('body').attr('style', 'cursor: default');
                        trigger.attr('style', 'cursor: pointer');
                    });

                event.preventDefault();
                event.stopPropagation();
            });
        })
        .end()
        .find('.f_galleryCloser').click( function (event) {
            $('#f_galleryimageWrapper').hide('slow');
        })
        .end()
        .find('.f_galleryStopClose').click( function (event) {
            event.stopPropagation();
        });
        
    // show the image on start if set by the hash
    if (showImage)
        showImage.click();
}


function init_jumps () {
    $('*[class*=f_jumpTo_]').each(function() {
        var jumpId = get_variableClasses($(this),'f_jumpTo_',false);
        $(this).click( function () {
            window.location.hash = jumpId;
        });
    });
}

function init_hoverBlock () {
    $('.f_hoverBlock').each ( function () {
        var block = $(this);

        block
            .find('.f_hoverElement')
            .each( function () {
                this.mEnter = function () {
                    $(this).addClass('f_hovered');
                    block.find('.f_hoverElement').not($(this)).removeClass('f_hovered');
                };
                $(this).mouseenter(this.mEnter);
            });
    });
    $('.f_hoverStart').each( function () {
        this.mEnter();
    });
}

function init_showOnHover () {
    $('*[class*=f_showOnHover_subClass_]').each(function() {
        var hoverClass = get_variableClasses($(this),'f_showOnHover_subClass_',false);
        var elements = $(this).find('.'+hoverClass);
        $(this)
            .mouseenter( function () {
                elements.show('fast');
            })
            .mouseleave( function () {
                elements.hide('fast');
            });
    });
}

function set_classes () {
    $('*[class*=f_classSet_]').each(function() {
        var setClasses = $(this).attr('class').match(/f_classSet_[a-zA-Z0-9_-]*/g);
        for (var i = 0; i < setClasses.length; ++i) {
            $(this).addClass(setClasses[i].substr(11)).removeClass(setClasses[i]);
        }
        
    });
}

function set_aria () {
    $('*[class*=f_ariaSet_]').each(function() {
        var setAria = get_variableClasses($(this),'f_ariaSet_',false).split("_");
        $(this).attr(setAria[0], setAria[1]);
    });
}

function  set_untabJSHidden () {
    $('.f_hideIfJS').allFocusableElements()
        .attr('tabindex','-1')
        .end()
        .filter(FOCUSABLE_ELEMENTS)
        .attr('tabindex','-1');
}

function adjust_reallocate () {
    $('*[class*=f_reallocateTo_]').each(function() {
        var reallocateTo = get_variableClasses($(this),'f_reallocateTo_',false);
        if ($(this).hasClass('f_reallocateShow')) $(this).show();
        $('#'+reallocateTo).append($(this));

    });
    
}


function get_variableClasses (obj, varname, findall) {
    if (obj.length > 0) {
        var reg = new RegExp(varname+"[a-zA-Z0-9_-]*","g");
        var variableClasses = obj.attr('class').match(reg);
        if (variableClasses) {
            for (var i = 0; i < variableClasses.length; ++i) {
                variableClasses[i] = variableClasses[i].substr(varname.length);
            }
            if (findall) return variableClasses;
            else return variableClasses[0];
        }
    }
    return false;
}

function loadCSS (fname, base) {
    if (!base) base = "/";
    var fileref=document.createElement("link");
    fileref.setAttribute("rel", "stylesheet");
    fileref.setAttribute("type", "text/css");
    fileref.setAttribute("href", base+'styles/'+fname+'.css');
    document.getElementsByTagName("head")[0].appendChild(fileref);

/*
    var head = document.getElementsByTagName('head')[0];
    $(document.createElement('link'))
        .attr({type: 'text/css', href: '/styles/'+fname+'.css', rel: 'stylesheet', media:'screen'})
        .appendTo(head);
        */
}

function loadTemplate (obj, template, articleId, queryString, templateElement, fnOnSuccess) {
    obj.load("/showTemplate.php?template="+template+"&catID="+articleId+"&"+queryString+" "+templateElement,
             function(response, status, xhr) {
                if (status == "error") {
                    var msg = "Sorry but there was an error: ";
                    $("#error").html(msg + xhr.status + " " + xhr.statusText);
                } else if (fnOnSuccess)
                    fnOnSuccess();
             });
}


