| /* |
| * jQuery UI Accordion 1.8.16 |
| * |
| * Copyright 2011, 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 header |
| self.active = header; |
| } else { |
| // anchor within content |
| self.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" ) |
| .toggleClass( "ui-corner-top" ); |
| self.active.next().addClass( "ui-accordion-content-active" ); |
| |
| self._createIcons(); |
| self.resize(); |
| |
| // ARIA |
| self.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", |
| "aria-selected": "false", |
| tabIndex: -1 |
| }) |
| .next() |
| .hide(); |
| |
| // make sure at least one header is in the tab order |
| if ( !self.active.length ) { |
| self.headers.eq( 0 ).attr( "tabIndex", 0 ); |
| } else { |
| self.active |
| .attr({ |
| "aria-expanded": "true", |
| "aria-selected": "true", |
| tabIndex: 0 |
| }); |
| } |
| |
| // only need links in tab order for Safari |
| if ( !$.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( "aria-selected" ) |
| .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 panels |
| if ( 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 that |
| this.options.active = index; |
| // call clickHandler with custom event |
| var 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 programmatically |
| if ( !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 target |
| var 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 click |
| if ( this.running || ( !options.collapsible && clickedIsActive ) ) { |
| return; |
| } |
| |
| // find elements to show and hide |
| var active = this.active, |
| 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] ); |
| |
| // when the call to ._toggle() comes after the class changes |
| // it causes a very odd bug in IE 8 (see #6720) |
| this.active = clickedIsActive ? $([]) : clicked; |
| this._toggle( toShow, toHide, data, clickedIsActive, down ); |
| |
| // switch classes |
| 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" ); |
| } |
| |
| 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 event |
| self._trigger( "changestart", null, self.data ); |
| |
| // count elements to animate |
| self.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 otherwise |
| toHide.prev() |
| .attr({ |
| "aria-expanded": "false", |
| "aria-selected": "false", |
| tabIndex: -1 |
| }) |
| .blur(); |
| toShow.prev() |
| .attr({ |
| "aria-expanded": "true", |
| "aria-selected": "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 completed |
| this.toHide.removeClass( "ui-accordion-content-active" ); |
| // Work around for rendering bug in IE (#5421) |
| if ( this.toHide.length ) { |
| this.toHide.parent()[0].className = this.toHide.parent()[0].className; |
| } |
| |
| this._trigger( "change", null, this.data ); |
| } |
| }); |
| |
| $.extend( $.ui.accordion, { |
| version: "1.8.16", |
| 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 element |
| var 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 padding |
| if ( 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 ); |