/* * jQuery UI Accordion 1.5 * * 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: jquery.accordion.js 4529 2008-01-24 18:41:30Z joern.zaefferer $ * */ ;(function($) { // If the UI scope is not available, add it $.ui = $.ui || {}; $.fn.extend({ accordion: function(options, data) { var args = Array.prototype.slice.call(arguments, 1); return this.each(function() { if (typeof options == "string") { var accordion = $.data(this, "ui-accordion"); accordion[options].apply(accordion, args); // INIT with optional options } else if (!$(this).is(".ui-accordion")) $.data(this, "ui-accordion", new $.ui.accordion(this, options)); }); }, // deprecated, use accordion("activate", index) instead activate: function(index) { return this.accordion("activate", index); } }); $.ui.accordion = function(container, options) { // setup configuration this.options = options = $.extend({}, $.ui.accordion.defaults, options); this.element = container; $(container).addClass("ui-accordion"); if ( options.navigation ) { var current = $(container).find("a").filter(options.navigationFilter); if ( current.length ) { if ( current.filter(options.header).length ) { options.active = current; } else { options.active = current.parent().parent().prev(); current.addClass("current"); } } } // calculate active if not specified, using the first header options.headers = $(container).find(options.header); options.active = findActive(options.headers, options.active); if ( options.fillSpace ) { var maxHeight = $(container).parent().height(); options.headers.each(function() { maxHeight -= $(this).outerHeight(); }); var maxPadding = 0; options.headers.next().each(function() { maxPadding = Math.max(maxPadding, $(this).innerHeight() - $(this).height()); }).height(maxHeight - maxPadding); } else if ( options.autoheight ) { var maxHeight = 0; options.headers.next().each(function() { maxHeight = Math.max(maxHeight, $(this).outerHeight()); }).height(maxHeight); } options.headers .not(options.active || "") .next() .hide(); options.active.parent().andSelf().addClass(options.selectedClass); if (options.event) $(container).bind((options.event || "") + ".ui-accordion", clickHandler); }; $.ui.accordion.prototype = { activate: function(index) { // call clickHandler with custom event clickHandler.call(this.element, { target: findActive( this.options.headers, index )[0] }); }, enable: function() { this.options.disabled = false; }, disable: function() { this.options.disabled = true; }, destroy: function() { this.options.headers.next().css("display", ""); if ( this.options.fillSpace || this.options.autoheight ) { this.options.headers.next().css("height", ""); } $.removeData(this.element, "ui-accordion"); $(this.element).removeClass("ui-accordion").unbind(".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 instance = $.data(this, "ui-accordion"); var options = instance.options; options.running = cancel ? 0 : --options.running; if ( options.running ) return; if ( options.clearStyle ) { options.toShow.add(options.toHide).css({ height: "", overflow: "" }); } $(this).triggerHandler("change.ui-accordion", [options.data], options.change); } function toggle(toShow, toHide, data, clickedActive, down) { var options = $.data(this, "ui-accordion").options; options.toShow = toShow; options.toHide = toHide; options.data = data; var complete = scopeCallback(completed, this); // count elements to animate options.running = toHide.size() == 0 ? toShow.size() : toHide.size(); if ( options.animated ) { if ( !options.alwaysOpen && clickedActive ) { $.ui.accordion.animations[options.animated]({ toShow: jQuery([]), toHide: toHide, complete: complete, down: down, autoheight: options.autoheight }); } else { $.ui.accordion.animations[options.animated]({ toShow: toShow, toHide: toHide, complete: complete, down: down, autoheight: options.autoheight }); } } else { if ( !options.alwaysOpen && clickedActive ) { toShow.toggle(); } else { toHide.hide(); toShow.show(); } complete(true); } } function clickHandler(event) { var options = $.data(this, "ui-accordion").options; if (options.disabled) return false; // called only when using activate(false) to close all parts programmatically if ( !event.target && !options.alwaysOpen ) { options.active.parent().andSelf().toggleClass(options.selectedClass); var toHide = options.active.next(), data = { instance: this, options: options, newHeader: jQuery([]), oldHeader: options.active, newContent: jQuery([]), oldContent: toHide }, toShow = options.active = $([]); toggle.call(this, toShow, toHide, data ); 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(options.header).length ) while ( !clicked.is(options.header) ) clicked = clicked.parent(); var clickedActive = clicked[0] == options.active[0]; // if animations are still active, or the active header is the target, ignore click if (options.running || (options.alwaysOpen && clickedActive)) return false; if (!clicked.is(options.header)) return; // switch classes options.active.parent().andSelf().toggleClass(options.selectedClass); if ( !clickedActive ) { clicked.parent().andSelf().addClass(options.selectedClass); } // find elements to show and hide var toShow = clicked.next(), toHide = options.active.next(), //data = [clicked, options.active, toShow, toHide], data = { instance: this, options: options, newHeader: clicked, oldHeader: options.active, newContent: toShow, oldContent: toHide }, down = options.headers.index( options.active[0] ) > options.headers.index( clicked[0] ); options.active = clickedActive ? $([]) : clicked; toggle.call(this, toShow, toHide, data, clickedActive, down ); return false; }; 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(options, additions) { options = $.extend({ easing: "swing", duration: 300 }, options, additions); if ( !options.toHide.size() ) { options.toShow.animate({height: "show"}, options); return; } var hideHeight = options.toHide.height(), showHeight = options.toShow.height(), difference = showHeight / hideHeight; options.toShow.css({ height: 0, overflow: 'hidden' }).show(); options.toHide.filter(":hidden").each(options.complete).end().filter(":visible").animate({height:"hide"},{ step: function(now) { var current = (hideHeight - now) * difference; if ($.browser.msie || $.browser.opera) { current = Math.ceil(current); } options.toShow.height( current ); }, duration: options.duration, easing: options.easing, complete: function() { if ( !options.autoheight ) { options.toShow.css("height", "auto"); } options.complete(); } }); }, bounceslide: function(options) { this.slide(options, { easing: options.down ? "bounceout" : "swing", duration: options.down ? 1000 : 200 }); }, easeslide: function(options) { this.slide(options, { easing: "easeinout", duration: 700 }); } } }); })(jQuery);