Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accordion: Attempt at improving animation. #587

Closed
wants to merge 11 commits into from
234 changes: 75 additions & 159 deletions ui/jquery.ui.accordion.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ $.widget( "ui.accordion", {
version: "@VERSION",
options: {
active: 0,
// TODO: animation option
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually animate

animated: "slide",
collapsible: false,
event: "click",
Expand All @@ -35,7 +36,7 @@ $.widget( "ui.accordion", {
_create: function() {
var options = this.options;

this.lastToggle = {};
this.prevShow = this.prevHide = $();
this.element.addClass( "ui-accordion ui-widget ui-helper-reset" );

this.headers = this.element.find( options.header )
Expand All @@ -62,6 +63,7 @@ $.widget( "ui.accordion", {
this.active.next().addClass( "ui-accordion-content-active" );

this._createIcons();
this.originalHeight = this.element[0].style.height;
this.refresh();

// ARIA
Expand Down Expand Up @@ -156,6 +158,7 @@ $.widget( "ui.accordion", {
.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 ( this.options.heightStyle !== "content" ) {
this.element.css( "height", this.originalHeight );
contents.css( "height", "" );
}
},
Expand Down Expand Up @@ -229,12 +232,12 @@ $.widget( "ui.accordion", {
},

refresh: function() {
var options = this.options,
var heightStyle = this.options.heightStyle,
parent = this.element.parent(),
maxHeight,
overflow;

if ( options.heightStyle === "fill" ) {
if ( heightStyle === "fill" ) {
// IE 6 treats height like minHeight, so we need to turn off overflow
// in order to get a reliable height
// we use the minHeight support test because we assume that only
Expand Down Expand Up @@ -267,7 +270,7 @@ $.widget( "ui.accordion", {
$( this ).innerHeight() + $( this ).height() ) );
})
.css( "overflow", "auto" );
} else if ( options.heightStyle === "auto" ) {
} else if ( heightStyle === "auto" ) {
maxHeight = 0;
this.headers.next()
.each(function() {
Expand All @@ -276,7 +279,9 @@ $.widget( "ui.accordion", {
.height( maxHeight );
}

return this;
if ( heightStyle !== "content" ) {
this.element.height( this.element.height() );
}
},

_activate: function( index ) {
Expand Down Expand Up @@ -361,41 +366,22 @@ $.widget( "ui.accordion", {
},

_toggle: function( data ) {
var that = this,
options = this.options,
toShow = data.newContent,
toHide = data.oldContent;

function complete() {
that._completed( data );
}
var toShow = data.newContent,
toHide = this.prevShow.length ? this.prevShow : data.oldContent;

if ( options.animated ) {
var animations = $.ui.accordion.animations,
animation = options.animated,
additional;

if ( !animations[ animation ] ) {
additional = {
easing: $.easing[ animation ] ? animation : "slide",
duration: 700
};
animation = "slide";
}
// handle activating a panel during the animation for another activation
this.prevShow.add( this.prevHide ).stop( true, true );
this.prevShow = toShow;
this.prevHide = toHide;

animations[ animation ]({
widget: this,
toShow: toShow,
toHide: toHide,
prevShow: this.lastToggle.toShow,
prevHide: this.lastToggle.toHide,
complete: complete,
down: toShow.length && ( !toHide.length || ( toShow.index() < toHide.index() ) )
}, additional );
if ( this.options.animated ) {
// TODO: back compat for animated option
// TODO: back compat for bounceslide
this._animate( toShow, toHide, data );
} else {
toHide.hide();
toShow.show();
complete();
this._completed( data );
}

// TODO assert that the blur and focus triggers are really necessary, remove otherwise
Expand All @@ -415,17 +401,51 @@ $.widget( "ui.accordion", {
.focus();
},

_animate: function( toShow, toHide, data ) {
var total, easing, duration,
that = this,
down = toShow.length &&
( !toHide.length || ( toShow.index() < toHide.index() ) ),
animation = this.options.animation || {},
options = down && animation.down || animation,
complete = function() {
toShow.removeData( "accordionHeight" );
that._completed( data );
};

if ( typeof options === "number" ) {
duration = options;
}
if ( typeof options === "string" ) {
easing = options;
}
// fall back from options to animation in case of partial down settings
easing = easing || options.easing || animation.easing;
duration = duration || options.duration || animation.duration;

if ( !toHide.size() ) {
return toShow.animate( showProps, duration, easing, complete );
}
if ( !toShow.size() ) {
return toHide.animate( hideProps, duration, easing, complete );
}

total = toShow.show().outerHeight();
toHide.animate( hideProps, duration, easing );
toShow
.hide()
.data( "accordionHeight", {
total: total,
toHide: toHide
})
.animate( this.options.heightStyle === "content" ? showProps : showPropsAdjust,
duration, easing, complete );
},

_completed: function( data ) {
var toShow = data.newContent,
toHide = data.oldContent;

if ( this.options.heightStyle === "content" ) {
toShow.add( toHide ).css({
height: "",
overflow: ""
});
}

// other classes are removed before the animation; this one needs to stay until completed
toHide.removeClass( "ui-accordion-content-active" );
// Work around for rendering bug in IE (#5421)
Expand All @@ -437,123 +457,19 @@ $.widget( "ui.accordion", {
}
});

$.extend( $.ui.accordion, {
animations: {
slide: function( options, additions ) {
if ( options.prevShow || options.prevHide ) {
options.prevHide.stop( true, true );
options.toHide = options.prevShow;
}

var showOverflow = options.toShow.css( "overflow" ),
showOverflowX = options.toHide.css( "overflowX" ),
showOverflowY = options.toHide.css( "overflowY" ),
hideOverflow = options.toHide.css( "overflow" ),
hideOverflowX = options.toHide.css( "overflowX" ),
hideOverflowY = options.toHide.css( "overflowY" ),
percentDone = 0,
showProps = {},
hideProps = {},
fxAttrs = [ "height", "paddingTop", "paddingBottom" ],
originalWidth;
options = $.extend({
easing: "swing",
duration: 300
}, options, additions );

options.widget.lastToggle = options;

if ( !options.toHide.size() ) {
originalWidth = options.toShow[0].style.width;
options.toShow
.show()
.width( options.toShow.width() )
.hide()
.animate({
height: "show",
paddingTop: "show",
paddingBottom: "show"
}, {
duration: options.duration,
easing: options.easing,
complete: function() {
options.toShow.width( originalWidth );
options.complete();
}
});
return;
}
if ( !options.toShow.size() ) {
options.toHide.animate({
height: "hide",
paddingTop: "hide",
paddingBottom: "hide"
}, options );
return;
}
// fix width before calculating height of hidden element
var s = options.toShow;
originalWidth = s[0].style.width;
s.width( s.parent().width()
- parseFloat( s.css( "paddingLeft" ) )
- parseFloat( s.css( "paddingRight" ) )
- ( parseFloat( s.css( "borderLeftWidth" ) ) || 0 )
- ( parseFloat( s.css( "borderRightWidth" ) ) || 0 ) );

$.each( fxAttrs, function( i, prop ) {
hideProps[ prop ] = "hide";

var parts = ( "" + $.css( options.toShow[0], prop ) ).match( /^([\d+-.]+)(.*)$/ ),
// work around bug when a panel has no height - #7335
propVal = prop === "height" && parts[ 1 ] === "0" ? 1 : parts[ 1 ];
showProps[ prop ] = {
value: propVal,
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 ) {
if ( settings.prop == "height" || settings.prop == "paddingTop" || settings.prop == "paddingBottom" ) {
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() {
options.toShow.css({
width: originalWidth,
overflow: showOverflow,
overflowX: showOverflowX,
overflowY: showOverflowY
});
options.toHide.css({
overflow: hideOverflow,
overflowX: hideOverflowX,
overflowY: hideOverflowY
});
options.complete();
}
});
},
bounceslide: function( options ) {
this.slide( options, {
easing: options.down ? "easeOutBounce" : "swing",
duration: options.down ? 1000 : 200
});
}
}
});
$.fx.step.accordionHeight = function( fx ) {
var elem = $( fx.elem ),
data = elem.data( "accordionHeight" );
elem.height( data.total - elem.outerHeight() - data.toHide.outerHeight() + elem.height() );
};
var hideProps = {},
showProps = {},
showPropsAdjust = {};
hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
showProps.height = showProps.paddingTop = showProps.paddingBottom =
showProps.borderTopWidth = showProps.borderBottomWidth = "show";
$.extend( showPropsAdjust, showProps, { accordionHeight: "show" } );



Expand Down