﻿/*
* jQuery UI Accordion 1.1
* 
* Copyright (c) 2007 Jörn Zaefferer
*
* http://docs.jquery.com/UI/Accordion
*
* Dual licensed under the MIT and GPL licenses:
*   http://www.opensource.org/licenses/mit-license.php
*   http://www.gnu.org/licenses/gpl.html
*
* Revision: $Id$
*
*/

; (function($) {

    $.fn.extend({
        makeAccordion: function(settings) {
            return this.each(function() {
                $.data(this, "ui-accordion") || $.data(this, "ui-accordion", new $.ui.accordion(this, settings));
            });
        },
        changeAccordion: function(key, value) {
            return this.trigger(key + ".ui-accordion", [value]);
        },
        enableAccordion: function() {
            return this.trigger("enable.ui-accordion");
        },
        disableAccordion: function() {
            return this.trigger("disable.ui-accordion");
        },
        removeAccordion: function() {
            return this.trigger("remove.ui-accordion");
        },
        // deprecated, use changeAccordion("activate", index) instead
        activate: function(index) {
            return this.changeAccordion("activate", index);
        },
        // deprecated, use removeAccordion instead
        unaccordion: function() {
            return this.removeAccordion.apply(this, arguments);
        }
    });

    // If the UI scope is not available, add it
    $.ui = $.ui || {};

    $.ui.accordion = function(container, settings) {

        // setup configuration
        this.settings = settings = $.extend({}, $.ui.accordion.defaults, settings);

        if (settings.navigation) {
            var current = $(container).find("a").filter(settings.navigationFilter);
            if (current.length) {
                if (current.filter(settings.header).length) {
                    settings.active = current;
                } else {
                    settings.active = current.parent().parent().prev();
                    current.addClass("current");
                }
            }
        }

        // calculate active if not specified, using the first header
        settings.headers = $(container).find(settings.header);
        settings.active = findActive(settings.headers, settings.active);

        if (settings.fillSpace) {
            var maxHeight = $(container).parent().height();
            settings.headers.each(function() {
                maxHeight -= $(this).outerHeight();
            });
            var maxPadding = 0;
            settings.headers.next().each(function() {
                maxPadding = Math.max(maxPadding, $(this).innerHeight() - $(this).height());
            }).height(maxHeight - maxPadding);
        } else if (settings.autoheight) {
            var maxHeight = 0;
            settings.headers.next().each(function() {
                maxHeight = Math.max(maxHeight, $(this).outerHeight());
            }).height(maxHeight);
        }

        settings.headers
		.not(settings.active || "")
		.next()
		.hide();
        settings.active.parent().andSelf().addClass(settings.selectedClass);

        $(container)
	.bind((settings.event || "") + ".ui-accordion", clickHandler)
	.bind("activate.ui-accordion", activateHandler)
	.bind("enable.ui-accordion", function() {
	    $.data(this, "ui-accordion").settings.disabled = false;
	})
	.bind("disable.ui-accordion", function() {
	    $.data(this, "ui-accordion").settings.disabled = true;
	})
	.one("remove.ui-accordion", function() {
	    var settings = $.data(this, "ui-accordion").settings;
	    $(this)
		.unbind(settings.event + ".ui-accordion")
		.unbind("activate.ui-accordion")
		.unbind("enable.ui-accordion")
		.unbind("disable.ui-accordion");
	    settings.headers.next().css("display", "");
	    if (settings.fillSpace || settings.autoheight) {
	        settings.headers.next().css("height", "");
	    }
	    $.removeData(this, "ui-accordion");
	});
    };

    function scopeCallback(callback, scope) {
        return function() {
            return callback.apply(scope, arguments);
        };
    }

    function completed(cancel) {
        // if removed while animated data can be empty
        if (!$.data(this, "ui-accordion"))
            return;
        var settings = $.data(this, "ui-accordion").settings;
        settings.running = cancel ? 0 : --settings.running;
        if (settings.running)
            return;
        if (settings.clearStyle) {
            settings.toShow.add(settings.toHide).css({
                height: "",
                overflow: ""
            });
        }
        $(this).trigger("changed.ui-accordion", settings.data);
    }

    function toggle(toShow, toHide, data, clickedActive, down) {
        var settings = $.data(this, "ui-accordion").settings;
        settings.toShow = toShow;
        settings.toHide = toHide;
        settings.data = data;
        var complete = scopeCallback(completed, this);

        // count elements to animate
        settings.running = toHide.size() == 0 ? toShow.size() : toHide.size();

        if (settings.animated) {
            if (!settings.alwaysOpen && clickedActive) {
                $.ui.accordion.animations[settings.animated]({
                    toShow: jQuery([]),
                    toHide: toHide,
                    complete: complete,
                    down: down,
                    autoheight: settings.autoheight
                });
            } else {
                $.ui.accordion.animations[settings.animated]({
                    toShow: toShow,
                    toHide: toHide,
                    complete: complete,
                    down: down,
                    autoheight: settings.autoheight
                });
            }
        } else {
            if (!settings.alwaysOpen && clickedActive) {
                toShow.toggle();
            } else {
                toHide.hide();
                toShow.show();
            }
            complete(true);
        }
    }

    function clickHandler(event) {
        var settings = $.data(this, "ui-accordion").settings;
        if (settings.disabled)
            return false;

        // called only when using activate(false) to close all parts programmatically
        if (!event.target && !settings.alwaysOpen) {
            settings.active.parent().andSelf().toggleClass(settings.selectedClass);
            var toHide = settings.active.next();
            var toShow = settings.active = $([]);
            toggle.call(this, toShow, toHide);
            return false;
        }
        // get the click target
        var clicked = $(event.target);

        // due to the event delegation model, we have to check if one
        // of the parent elements is our actual header, and find that
        if (clicked.parents(settings.header).length)
            while (!clicked.is(settings.header))
            clicked = clicked.parent();

        var clickedActive = clicked[0] == settings.active[0];

        // if animations are still active, or the active header is the target, ignore click
        if (settings.running || (settings.alwaysOpen && clickedActive))
            return false;
        if (!clicked.is(settings.header))
            return;

        // switch classes
        settings.active.parent().andSelf().toggleClass(settings.selectedClass);
        if (!clickedActive) {
            clicked.parent().andSelf().addClass(settings.selectedClass);
        }

        // find elements to show and hide
        var toShow = clicked.next(),
		toHide = settings.active.next(),
		data = [clicked, settings.active, toShow, toHide],
		down = settings.headers.index(settings.active[0]) > settings.headers.index(clicked[0]);

        settings.active = clickedActive ? $([]) : clicked;
        toggle.call(this, toShow, toHide, data, clickedActive, down);

        return false;
    };

    function activateHandler(event, index) {
        // IE manages to call activateHandler on normal clicks
        if (arguments.length == 1)
            return;
        // call clickHandler with custom event
        clickHandler.call(this, {
            target: findActive($.data(this, "ui-accordion").settings.headers, index)[0]
        });
    };

    function findActive(headers, selector) {
        return selector != undefined
		? typeof selector == "number"
			? headers.filter(":eq(" + selector + ")")
			: headers.not(headers.not(selector))
		: selector === false
			? $([])
			: headers.filter(":eq(0)");
    }

    $.extend($.ui.accordion, {
        defaults: {
            selectedClass: "selected",
            alwaysOpen: true,
            animated: 'slide',
            event: "click",
            header: "a",
            autoheight: true,
            running: 0,
            navigationFilter: function() {
                return this.href.toLowerCase() == location.href.toLowerCase();
            }
        },
        animations: {
            slide: function(settings, additions) {
                settings = $.extend({
                    easing: "swing",
                    duration: 300
                }, settings, additions);
                if (!settings.toHide.size()) {
                    settings.toShow.animate({ height: "show" }, settings);
                    return;
                }
                var hideHeight = settings.toHide.height(),
				showHeight = settings.toShow.height(),
				difference = showHeight / hideHeight;
                settings.toShow.css({ height: 0, overflow: 'hidden' }).show();
                settings.toHide.filter(":hidden").each(settings.complete).end().filter(":visible").animate({ height: "hide" }, {
                    step: function(now) {
                        var current = (hideHeight - now) * difference;
                        if ($.browser.msie || $.browser.opera) {
                            current = Math.ceil(current);
                        }
                        settings.toShow.height(current);
                    },
                    duration: settings.duration,
                    easing: settings.easing,
                    complete: function() {
                        if (!settings.autoheight) {
                            settings.toShow.css("height", "auto");
                        }
                        settings.complete();
                    }
                });
            },
            bounceslide: function(settings) {
                this.slide(settings, {
                    easing: settings.down ? "bounceout" : "swing",
                    duration: settings.down ? 1000 : 200
                });
            },
            easeslide: function(settings) {
                this.slide(settings, {
                    easing: "easeinout",
                    duration: 700
                })
            }
        }
    });

})(jQuery);

