607 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			607 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|   | /* | ||
|  |  * jQuery UI Accordion 1.8.10 | ||
|  |  * | ||
|  |  * 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", | ||
|  | 				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", | ||
|  | 					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( "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", | ||
|  | 				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 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.10", | ||
|  | 	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 ); |