From 517dff6e459d9b148246a1ba928da457b738a4a8 Mon Sep 17 00:00:00 2001 From: Pawel Kozlowski Date: Wed, 13 Nov 2013 19:59:30 +0100 Subject: [PATCH] feat(collapse): make collapse work with bootstrap3 Closes #1240 If starting out collapsed, the expand animation would jump since the `initialAnimSkip` was still `true`. --- src/collapse/collapse.js | 136 +++++++++++++++++++-------------------- 1 file changed, 67 insertions(+), 69 deletions(-) diff --git a/src/collapse/collapse.js b/src/collapse/collapse.js index 05a5b92943..bb40a92576 100644 --- a/src/collapse/collapse.js +++ b/src/collapse/collapse.js @@ -1,83 +1,81 @@ -angular.module('ui.bootstrap.collapse',['ui.bootstrap.transition']) +angular.module('ui.bootstrap.collapse', ['ui.bootstrap.transition']) -// The collapsible directive indicates a block of html that will expand and collapse -.directive('collapse', ['$transition', function($transition) { - // CSS transitions don't work with height: auto, so we have to manually change the height to a - // specific value and then once the animation completes, we can reset the height to auto. - // Unfortunately if you do this while the CSS transitions are specified (i.e. in the CSS class - // "collapse") then you trigger a change to height 0 in between. - // The fix is to remove the "collapse" CSS class while changing the height back to auto - phew! - var fixUpHeight = function(scope, element, height) { - // We remove the collapse CSS class to prevent a transition when we change to height: auto - element.removeClass('collapse'); - element.css({ height: height }); - // It appears that reading offsetWidth makes the browser realise that we have changed the - // height already :-/ - var x = element[0].offsetWidth; - element.addClass('collapse'); - }; + .directive('collapse', ['$transition', function ($transition, $timeout) { - return { - link: function(scope, element, attrs) { + return { + link: function (scope, element, attrs) { - var isCollapsed; - var initialAnimSkip = true; + var initialAnimSkip = true; + var currentTransition; - scope.$watch(attrs.collapse, function(value) { - if (value) { - collapse(); - } else { - expand(); + function doTransition(change) { + var newTransition = $transition(element, change); + if (currentTransition) { + currentTransition.cancel(); + } + currentTransition = newTransition; + newTransition.then(newTransitionDone, newTransitionDone); + return newTransition; + + function newTransitionDone() { + // Make sure it's this transition, otherwise, leave it alone. + if (currentTransition === newTransition) { + currentTransition = undefined; + } + } + } + + function expand() { + if (initialAnimSkip) { + initialAnimSkip = false; + expandDone(); + } else { + var targetElHeight = element[0].scrollHeight; + if (targetElHeight) { + element.removeClass('collapse').addClass('collapsing'); + doTransition({ height: element[0].scrollHeight + 'px' }).then(expandDone); + } else { + expandDone(); + } + } } - }); - - var currentTransition; - var doTransition = function(change) { - if ( currentTransition ) { - currentTransition.cancel(); + function expandDone() { + element.removeClass('collapsing'); + element.addClass('collapse in'); + element.css({height: 'auto'}); } - currentTransition = $transition(element,change); - currentTransition.then( - function() { currentTransition = undefined; }, - function() { currentTransition = undefined; } - ); - return currentTransition; - }; - var expand = function () { - isCollapsed = false; - if (initialAnimSkip) { - initialAnimSkip = false; - expandDone(); - } else { - var targetElHeight = element[0].scrollHeight; - if (targetElHeight) { - doTransition({ height: targetElHeight + 'px' }).then(expandDone); + function collapse() { + if (initialAnimSkip) { + initialAnimSkip = false; + collapseDone(); + element.css({height: 0}); } else { - expandDone(); + // CSS transitions don't work with height: auto, so we have to manually change the height to a specific value + element.css({ height: element[0].scrollHeight + 'px' }); + //trigger reflow so a browser relaizes that height was updated from auto to a specific value + var x = element[0].offsetWidth; + + element.removeClass('collapse in').addClass('collapsing'); + + doTransition({ height: 0 }).then(collapseDone); } } - }; - function expandDone() { - if ( !isCollapsed ) { - fixUpHeight(scope, element, 'auto'); - element.addClass('in'); + function collapseDone() { + element.removeClass('collapsing'); + element.addClass('collapse'); } + + scope.$watch(attrs.collapse, function (shouldCollapse) { + if (shouldCollapse) { + collapse(); + } else { + expand(); + } + }); + } - - var collapse = function() { - isCollapsed = true; - element.removeClass('in'); - if (initialAnimSkip) { - initialAnimSkip = false; - fixUpHeight(scope, element, 0); - } else { - fixUpHeight(scope, element, element[0].scrollHeight + 'px'); - doTransition({'height':'0'}); - } - }; - } - }; -}]); + }; + }]);