Blame | Last modification | View Log | RSS feed
/** jQuery UI Accordion 1.8.5** Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)* Dual licensed under the MIT or GPL Version 2 licenses.* http://jquery.org/license** http://docs.jquery.com/UI/Accordion** Depends:* jquery.ui.core.js* jquery.ui.widget.js*/(function( $, undefined ) {$.widget( "ui.accordion", {options: {active: 0,animated: "slide",autoHeight: true,clearStyle: false,collapsible: false,event: "click",fillSpace: false,header: "> li > :first-child,> :not(li):even",icons: {header: "ui-icon-triangle-1-e",headerSelected: "ui-icon-triangle-1-s"},navigation: false,navigationFilter: function() {return this.href.toLowerCase() === location.href.toLowerCase();}},_create: function() {var self = this,options = self.options;self.running = 0;self.element.addClass( "ui-accordion ui-widget ui-helper-reset" )// in lack of child-selectors in CSS// we need to mark top-LIs in a UL-accordion for some IE-fix.children( "li" ).addClass( "ui-accordion-li-fix" );self.headers = self.element.find( options.header ).addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ).bind( "mouseenter.accordion", function() {if ( options.disabled ) {return;}$( this ).addClass( "ui-state-hover" );}).bind( "mouseleave.accordion", function() {if ( options.disabled ) {return;}$( this ).removeClass( "ui-state-hover" );}).bind( "focus.accordion", function() {if ( options.disabled ) {return;}$( this ).addClass( "ui-state-focus" );}).bind( "blur.accordion", function() {if ( options.disabled ) {return;}$( this ).removeClass( "ui-state-focus" );});self.headers.next().addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" );if ( options.navigation ) {var current = self.element.find( "a" ).filter( options.navigationFilter ).eq( 0 );if ( current.length ) {var header = current.closest( ".ui-accordion-header" );if ( header.length ) {// anchor within headerself.active = header;} else {// anchor within contentself.active = current.closest( ".ui-accordion-content" ).prev();}}}self.active = self._findActive( self.active || options.active ).addClass( "ui-state-default ui-state-active" ).toggleClass( "ui-corner-all ui-corner-top" );self.active.next().addClass( "ui-accordion-content-active" );self._createIcons();self.resize();// ARIAself.element.attr( "role", "tablist" );self.headers.attr( "role", "tab" ).bind( "keydown.accordion", function( event ) {return self._keydown( event );}).next().attr( "role", "tabpanel" );self.headers.not( self.active || "" ).attr({"aria-expanded": "false",tabIndex: -1}).next().hide();// make sure at least one header is in the tab orderif ( !self.active.length ) {self.headers.eq( 0 ).attr( "tabIndex", 0 );} else {self.active.attr({"aria-expanded": "true",tabIndex: 0});}// only need links in tab order for Safariif ( !$.browser.safari ) {self.headers.find( "a" ).attr( "tabIndex", -1 );}if ( options.event ) {self.headers.bind( options.event.split(" ").join(".accordion ") + ".accordion", function(event) {self._clickHandler.call( self, event, this );event.preventDefault();});}},_createIcons: function() {var options = this.options;if ( options.icons ) {$( "<span></span>" ).addClass( "ui-icon " + options.icons.header ).prependTo( this.headers );this.active.children( ".ui-icon" ).toggleClass(options.icons.header).toggleClass(options.icons.headerSelected);this.element.addClass( "ui-accordion-icons" );}},_destroyIcons: function() {this.headers.children( ".ui-icon" ).remove();this.element.removeClass( "ui-accordion-icons" );},destroy: function() {var options = this.options;this.element.removeClass( "ui-accordion ui-widget ui-helper-reset" ).removeAttr( "role" );this.headers.unbind( ".accordion" ).removeClass( "ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ).removeAttr( "role" ).removeAttr( "aria-expanded" ).removeAttr( "tabIndex" );this.headers.find( "a" ).removeAttr( "tabIndex" );this._destroyIcons();var contents = this.headers.next().css( "display", "" ).removeAttr( "role" ).removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled" );if ( options.autoHeight || options.fillHeight ) {contents.css( "height", "" );}return $.Widget.prototype.destroy.call( this );},_setOption: function( key, value ) {$.Widget.prototype._setOption.apply( this, arguments );if ( key == "active" ) {this.activate( value );}if ( key == "icons" ) {this._destroyIcons();if ( value ) {this._createIcons();}}// #5332 - opacity doesn't cascade to positioned elements in IE// so we need to add the disabled class to the headers and panelsif ( key == "disabled" ) {this.headers.add(this.headers.next())[ value ? "addClass" : "removeClass" ]("ui-accordion-disabled ui-state-disabled" );}},_keydown: function( event ) {if ( this.options.disabled || event.altKey || event.ctrlKey ) {return;}var keyCode = $.ui.keyCode,length = this.headers.length,currentIndex = this.headers.index( event.target ),toFocus = false;switch ( event.keyCode ) {case keyCode.RIGHT:case keyCode.DOWN:toFocus = this.headers[ ( currentIndex + 1 ) % length ];break;case keyCode.LEFT:case keyCode.UP:toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];break;case keyCode.SPACE:case keyCode.ENTER:this._clickHandler( { target: event.target }, event.target );event.preventDefault();}if ( toFocus ) {$( event.target ).attr( "tabIndex", -1 );$( toFocus ).attr( "tabIndex", 0 );toFocus.focus();return false;}return true;},resize: function() {var options = this.options,maxHeight;if ( options.fillSpace ) {if ( $.browser.msie ) {var defOverflow = this.element.parent().css( "overflow" );this.element.parent().css( "overflow", "hidden");}maxHeight = this.element.parent().height();if ($.browser.msie) {this.element.parent().css( "overflow", defOverflow );}this.headers.each(function() {maxHeight -= $( this ).outerHeight( true );});this.headers.next().each(function() {$( this ).height( Math.max( 0, maxHeight -$( this ).innerHeight() + $( this ).height() ) );}).css( "overflow", "auto" );} else if ( options.autoHeight ) {maxHeight = 0;this.headers.next().each(function() {maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );}).height( maxHeight );}return this;},activate: function( index ) {// TODO this gets called on init, changing the option without an explicit call for thatthis.options.active = index;// call clickHandler with custom eventvar active = this._findActive( index )[ 0 ];this._clickHandler( { target: active }, active );return this;},_findActive: function( selector ) {return selector? typeof selector === "number"? this.headers.filter( ":eq(" + selector + ")" ): this.headers.not( this.headers.not( selector ) ): selector === false? $( [] ): this.headers.filter( ":eq(0)" );},// TODO isn't event.target enough? why the separate target argument?_clickHandler: function( event, target ) {var options = this.options;if ( options.disabled ) {return;}// called only when using activate(false) to close all parts programmaticallyif ( !event.target ) {if ( !options.collapsible ) {return;}this.active.removeClass( "ui-state-active ui-corner-top" ).addClass( "ui-state-default ui-corner-all" ).children( ".ui-icon" ).removeClass( options.icons.headerSelected ).addClass( options.icons.header );this.active.next().addClass( "ui-accordion-content-active" );var toHide = this.active.next(),data = {options: options,newHeader: $( [] ),oldHeader: options.active,newContent: $( [] ),oldContent: toHide},toShow = ( this.active = $( [] ) );this._toggle( toShow, toHide, data );return;}// get the click targetvar clicked = $( event.currentTarget || target ),clickedIsActive = clicked[0] === this.active[0];// TODO the option is changed, is that correct?// TODO if it is correct, shouldn't that happen after determining that the click is valid?options.active = options.collapsible && clickedIsActive ?false :this.headers.index( clicked );// if animations are still active, or the active header is the target, ignore clickif ( this.running || ( !options.collapsible && clickedIsActive ) ) {return;}// switch classesthis.active.removeClass( "ui-state-active ui-corner-top" ).addClass( "ui-state-default ui-corner-all" ).children( ".ui-icon" ).removeClass( options.icons.headerSelected ).addClass( options.icons.header );if ( !clickedIsActive ) {clicked.removeClass( "ui-state-default ui-corner-all" ).addClass( "ui-state-active ui-corner-top" ).children( ".ui-icon" ).removeClass( options.icons.header ).addClass( options.icons.headerSelected );clicked.next().addClass( "ui-accordion-content-active" );}// find elements to show and hidevar toShow = clicked.next(),toHide = this.active.next(),data = {options: options,newHeader: clickedIsActive && options.collapsible ? $([]) : clicked,oldHeader: this.active,newContent: clickedIsActive && options.collapsible ? $([]) : toShow,oldContent: toHide},down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] );this.active = clickedIsActive ? $([]) : clicked;this._toggle( toShow, toHide, data, clickedIsActive, down );return;},_toggle: function( toShow, toHide, data, clickedIsActive, down ) {var self = this,options = self.options;self.toShow = toShow;self.toHide = toHide;self.data = data;var complete = function() {if ( !self ) {return;}return self._completed.apply( self, arguments );};// trigger changestart eventself._trigger( "changestart", null, self.data );// count elements to animateself.running = toHide.size() === 0 ? toShow.size() : toHide.size();if ( options.animated ) {var animOptions = {};if ( options.collapsible && clickedIsActive ) {animOptions = {toShow: $( [] ),toHide: toHide,complete: complete,down: down,autoHeight: options.autoHeight || options.fillSpace};} else {animOptions = {toShow: toShow,toHide: toHide,complete: complete,down: down,autoHeight: options.autoHeight || options.fillSpace};}if ( !options.proxied ) {options.proxied = options.animated;}if ( !options.proxiedDuration ) {options.proxiedDuration = options.duration;}options.animated = $.isFunction( options.proxied ) ?options.proxied( animOptions ) :options.proxied;options.duration = $.isFunction( options.proxiedDuration ) ?options.proxiedDuration( animOptions ) :options.proxiedDuration;var animations = $.ui.accordion.animations,duration = options.duration,easing = options.animated;if ( easing && !animations[ easing ] && !$.easing[ easing ] ) {easing = "slide";}if ( !animations[ easing ] ) {animations[ easing ] = function( options ) {this.slide( options, {easing: easing,duration: duration || 700});};}animations[ easing ]( animOptions );} else {if ( options.collapsible && clickedIsActive ) {toShow.toggle();} else {toHide.hide();toShow.show();}complete( true );}// TODO assert that the blur and focus triggers are really necessary, remove otherwisetoHide.prev().attr({"aria-expanded": "false",tabIndex: -1}).blur();toShow.prev().attr({"aria-expanded": "true",tabIndex: 0}).focus();},_completed: function( cancel ) {this.running = cancel ? 0 : --this.running;if ( this.running ) {return;}if ( this.options.clearStyle ) {this.toShow.add( this.toHide ).css({height: "",overflow: ""});}// other classes are removed before the animation; this one needs to stay until completedthis.toHide.removeClass( "ui-accordion-content-active" );this._trigger( "change", null, this.data );}});$.extend( $.ui.accordion, {version: "1.8.5",animations: {slide: function( options, additions ) {options = $.extend({easing: "swing",duration: 300}, options, additions );if ( !options.toHide.size() ) {options.toShow.animate({height: "show",paddingTop: "show",paddingBottom: "show"}, options );return;}if ( !options.toShow.size() ) {options.toHide.animate({height: "hide",paddingTop: "hide",paddingBottom: "hide"}, options );return;}var overflow = options.toShow.css( "overflow" ),percentDone = 0,showProps = {},hideProps = {},fxAttrs = [ "height", "paddingTop", "paddingBottom" ],originalWidth;// fix width before calculating height of hidden elementvar s = options.toShow;originalWidth = s[0].style.width;s.width( parseInt( s.parent().width(), 10 )- parseInt( s.css( "paddingLeft" ), 10 )- parseInt( s.css( "paddingRight" ), 10 )- ( parseInt( s.css( "borderLeftWidth" ), 10 ) || 0 )- ( parseInt( s.css( "borderRightWidth" ), 10) || 0 ) );$.each( fxAttrs, function( i, prop ) {hideProps[ prop ] = "hide";var parts = ( "" + $.css( options.toShow[0], prop ) ).match( /^([\d+-.]+)(.*)$/ );showProps[ prop ] = {value: parts[ 1 ],unit: parts[ 2 ] || "px"};});options.toShow.css({ height: 0, overflow: "hidden" }).show();options.toHide.filter( ":hidden" ).each( options.complete ).end().filter( ":visible" ).animate( hideProps, {step: function( now, settings ) {// only calculate the percent when animating height// IE gets very inconsistent results when animating elements// with small values, which is common for paddingif ( settings.prop == "height" ) {percentDone = ( settings.end - settings.start === 0 ) ? 0 :( settings.now - settings.start ) / ( settings.end - settings.start );}options.toShow[ 0 ].style[ settings.prop ] =( percentDone * showProps[ settings.prop ].value )+ showProps[ settings.prop ].unit;},duration: options.duration,easing: options.easing,complete: function() {if ( !options.autoHeight ) {options.toShow.css( "height", "" );}options.toShow.css({width: originalWidth,overflow: overflow});options.complete();}});},bounceslide: function( options ) {this.slide( options, {easing: options.down ? "easeOutBounce" : "swing",duration: options.down ? 1000 : 200});}}});})( jQuery );