From 789486e980e9feb33c0772c8c264a92b61dded05 Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 28 Aug 2013 21:43:04 -0400 Subject: [PATCH 1/2] Bootstrap 3.0 Collapse Update Do not apply this, as it does not work yet, but I'm working to update to use the 'collapse', 'collapsing', and 'collapse in' CSS classes. Honestly, I'm guessing as to their order of use, especially the '.collapse .in' pair. I removed the FixUpHeight function as it no longer seemed efficient to have a generic function, due to the changing CSS classes. The major issue I'm having is that the promise resolves for expand and collapse are happening at the wrong time (e.g., when it collapses the expand .then function fires; nothing happens as isCollapsed is in the wrong state). Maybe I'm doing something dumb though. :P --- src/collapse/collapse.js | 60 ++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/src/collapse/collapse.js b/src/collapse/collapse.js index d0a33b454f..358ccc0f15 100644 --- a/src/collapse/collapse.js +++ b/src/collapse/collapse.js @@ -7,15 +7,9 @@ angular.module('ui.bootstrap.collapse',['ui.bootstrap.transition']) // 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'); - }; + + // NOTE: + // Removed the fixUpHeight function, for now, as more class manipulation was needed than before. return { link: function(scope, element, attrs) { @@ -31,9 +25,15 @@ angular.module('ui.bootstrap.collapse',['ui.bootstrap.transition']) if (element[0].scrollHeight !== 0) { if (!isCollapsed) { if (initialAnimSkip) { - fixUpHeight(scope, element, element[0].scrollHeight + 'px'); + element.css({height: element[0].scrollHeight + 'px'}); + element.removeClass('collapse in collapsing'); + var x = element[0].offsetWidth; + element.addClass('collapse in'); } else { - fixUpHeight(scope, element, 'auto'); + element.css({height: 'auto'}); + element.removeClass('collapse in collapsing'); + var x = element[0].offsetWidth; + element.addClass('collapse in'); } } } @@ -55,8 +55,8 @@ angular.module('ui.bootstrap.collapse',['ui.bootstrap.transition']) } currentTransition = $transition(element,change); currentTransition.then( - function() { currentTransition = undefined; }, - function() { currentTransition = undefined; } + function() { currentTransition = undefined;}, + function() { currentTransition = undefined;} ); return currentTransition; }; @@ -65,7 +65,10 @@ angular.module('ui.bootstrap.collapse',['ui.bootstrap.transition']) if (initialAnimSkip) { initialAnimSkip = false; if ( !isCollapsed ) { - fixUpHeight(scope, element, 'auto'); + element.removeClass('collapsing'); + var x = element[0].offsetWidth; + element.addClass('collapse in'); + element.css({height: 'auto'}); } } else { doTransition({ height : element[0].scrollHeight + 'px' }) @@ -73,8 +76,14 @@ angular.module('ui.bootstrap.collapse',['ui.bootstrap.transition']) // This check ensures that we don't accidentally update the height if the user has closed // the group while the animation was still running if ( !isCollapsed ) { - fixUpHeight(scope, element, 'auto'); + // Switch to post-transition display: block + element.removeClass('collapsing in'); + var x = element[0].offsetWidth; + element.addClass('collapse in'); + element.css({height: 'auto'}); } + // Promise testing purposes only + // console.log("Fired expand promise"); }); } isCollapsed = false; @@ -84,10 +93,25 @@ angular.module('ui.bootstrap.collapse',['ui.bootstrap.transition']) isCollapsed = true; if (initialAnimSkip) { initialAnimSkip = false; - fixUpHeight(scope, element, 0); + element.removeClass('collapsing in'); + var x = element[0].offsetWidth; + element.addClass('collapse'); + } else { - fixUpHeight(scope, element, element[0].scrollHeight + 'px'); - doTransition({'height':'0'}); + // Switch to collapsing for the transition + element.removeClass('collapse in'); + var x = element[0].offsetWidth; + element.addClass('collapsing'); + + doTransition({'height':'0px'}) + .then(function() { + // After the transition, remove collapsing and add collapse + if (isCollapsed) { + element.removeClass('collapsing'); + element.addClass('collapse'); + } + console.log("Fired collapse promise"); + }); } }; } From 2e013441bd3960e8452755b53efdd209fd5cd79f Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 2 Sep 2013 18:38:08 -0400 Subject: [PATCH 2/2] Added animationComplete() function Tried adding a single animationComplete function to run whenever the transition promise resolves. This *should* work, but it never fires when collapsing. :-/ --- src/collapse/collapse.js | 214 +++++++++++++++++++-------------------- 1 file changed, 105 insertions(+), 109 deletions(-) diff --git a/src/collapse/collapse.js b/src/collapse/collapse.js index 358ccc0f15..515926fa77 100644 --- a/src/collapse/collapse.js +++ b/src/collapse/collapse.js @@ -1,119 +1,115 @@ 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! + .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! - // NOTE: - // Removed the fixUpHeight function, for now, as more class manipulation was needed than before. + // NOTE: + // Removed the fixUpHeight function, for now, as more class manipulation was needed than before. - return { - link: function(scope, element, attrs) { + return { + link: function(scope, element, attrs) { - var isCollapsed; - var initialAnimSkip = true; - scope.$watch(function (){ return element[0].scrollHeight; }, function (value) { - //The listener is called when scollHeight changes - //It actually does on 2 scenarios: - // 1. Parent is set to display none - // 2. angular bindings inside are resolved - //When we have a change of scrollHeight we are setting again the correct height if the group is opened - if (element[0].scrollHeight !== 0) { - if (!isCollapsed) { - if (initialAnimSkip) { - element.css({height: element[0].scrollHeight + 'px'}); - element.removeClass('collapse in collapsing'); - var x = element[0].offsetWidth; - element.addClass('collapse in'); - } else { - element.css({height: 'auto'}); - element.removeClass('collapse in collapsing'); - var x = element[0].offsetWidth; - element.addClass('collapse in'); - } - } - } - }); - - scope.$watch(attrs.collapse, function(value) { - if (value) { - collapse(); - } else { - expand(); - } - }); - + var isCollapsed; + var initialAnimSkip = true; + scope.$watch(function (){ return element[0].scrollHeight; }, function (value) { + //The listener is called when scrollHeight changes + //It actually does on 2 scenarios: + // 1. Parent is set to display none + // 2. angular bindings inside are resolved + //When we have a change of scrollHeight we are setting again the correct height if the group is opened + if (element[0].scrollHeight !== 0) { + if (!isCollapsed) { + if (initialAnimSkip) { + element.css({height: 'auto'}); + element.removeClass('collapse in collapsing'); + var x = element[0].offsetWidth; + element.addClass('collapse in'); + } else { + element.css({height: element[0].scrollHeight + 'px'}); + element.removeClass('collapse in collapsing'); + var x = element[0].offsetWidth; + element.addClass('collapse in'); + } + } + } + }); - var currentTransition; - var doTransition = function(change) { - if ( currentTransition ) { - currentTransition.cancel(); - } - currentTransition = $transition(element,change); - currentTransition.then( - function() { currentTransition = undefined;}, - function() { currentTransition = undefined;} - ); - return currentTransition; - }; + scope.$watch(attrs.collapse, function(value) { + if (value) { + collapse(); + } else { + expand(); + } + }); - var expand = function() { - if (initialAnimSkip) { - initialAnimSkip = false; - if ( !isCollapsed ) { - element.removeClass('collapsing'); - var x = element[0].offsetWidth; - element.addClass('collapse in'); - element.css({height: 'auto'}); - } - } else { - doTransition({ height : element[0].scrollHeight + 'px' }) - .then(function() { - // This check ensures that we don't accidentally update the height if the user has closed - // the group while the animation was still running - if ( !isCollapsed ) { - // Switch to post-transition display: block - element.removeClass('collapsing in'); - var x = element[0].offsetWidth; - element.addClass('collapse in'); - element.css({height: 'auto'}); - } - // Promise testing purposes only - // console.log("Fired expand promise"); - }); - } - isCollapsed = false; - }; - - var collapse = function() { - isCollapsed = true; - if (initialAnimSkip) { - initialAnimSkip = false; - element.removeClass('collapsing in'); - var x = element[0].offsetWidth; - element.addClass('collapse'); - } else { - // Switch to collapsing for the transition - element.removeClass('collapse in'); - var x = element[0].offsetWidth; - element.addClass('collapsing'); - - doTransition({'height':'0px'}) - .then(function() { - // After the transition, remove collapsing and add collapse - if (isCollapsed) { + var currentTransition; + var doTransition = function(change) { + if ( currentTransition ) { + currentTransition.cancel(); + } + currentTransition = $transition(element,change); + currentTransition.then( + function() { currentTransition = undefined;}, + function() { currentTransition = undefined;} + ).then( + function() { animationComplete(); } + ); + }; + + var animationComplete = function() { element.removeClass('collapsing'); - element.addClass('collapse'); - } - console.log("Fired collapse promise"); - }); - } - }; - } - }; -}]); + var x = element[0].offsetWidth; + + if (isCollapsed) { + element.addClass('collapse'); + console.log('Animation Complete isCollapsed Fired'); + } + else { + element.addClass('collapse in'); + element.css({height: 'auto'}); + console.log('Animation Complete Not isCollapsed Fired'); + } + }; + + var expand = function() { + if (initialAnimSkip) { + initialAnimSkip = false; + animationComplete(); + } else { + // Switch to collapsing for the transition + element.removeClass('collapse in'); + var x = element[0].offsetWidth; + element.addClass('collapsing'); + + doTransition({ height : element[0].scrollHeight + 'px' }); + } + isCollapsed = false; + }; + + var collapse = function() { + isCollapsed = true; + if (initialAnimSkip) { + initialAnimSkip = false; + animationComplete(); + } else { + // Switch to collapsing for the transition + element.removeClass('collapse in'); + var x = element[0].offsetWidth; + element.addClass('collapsing'); + + var scrollHeight = element[0].scrollHeight + 'px'; + console.log('Height: ' + element[0].style.cssText); + element.css({height: scrollHeight}); + console.log('Height: ' + element[0].style.cssText); + doTransition({'height':'0px'}); + } + }; + } + }; + }]);