/* * jquery ui accordion 1.6 * * 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 4876 2008-03-08 11:49:04z 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);