Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

Commit

Permalink
feat(collapse): make collapse work with bootstrap3
Browse files Browse the repository at this point in the history
Closes #1240

If starting out collapsed, the expand animation would jump since the `initialAnimSkip` was still `true`.
  • Loading branch information
pkozlowski-opensource committed Dec 26, 2013
1 parent d04a063 commit cadc0f9
Showing 1 changed file with 64 additions and 71 deletions.
135 changes: 64 additions & 71 deletions src/collapse/collapse.js
Original file line number Diff line number Diff line change
@@ -1,82 +1,75 @@
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 resetCurrentTransition() {
currentTransition = undefined;
}
});


var currentTransition;
var doTransition = function(change) {
if ( currentTransition ) {
currentTransition.cancel();
function doTransition(change) {
if (currentTransition) {
currentTransition.cancel();
}
(currentTransition = $transition(element, change)).then(resetCurrentTransition, resetCurrentTransition);
return currentTransition;
}
currentTransition = $transition(element,change);
currentTransition.then(
function() { currentTransition = undefined; },
function() { currentTransition = undefined; }
);
return currentTransition;
};

var expand = function() {
if (initialAnimSkip) {
initialAnimSkip = false;
if ( !isCollapsed ) {
fixUpHeight(scope, element, 'auto');
element.addClass('in');
function expand() {
if (initialAnimSkip) {
initialAnimSkip = false;
element.removeClass('collapsing');
element.addClass('collapse in');
element.css({height: 'auto'});
} else {
element.removeClass('collapse').addClass('collapsing');
doTransition({ height: element[0].scrollHeight + 'px' }).then(function () {
element.removeClass('collapsing');
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 ) {
fixUpHeight(scope, element, 'auto');
element.addClass('in');
}
});
}
isCollapsed = false;
};

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'});

function collapse() {
if (initialAnimSkip) {
initialAnimSkip = false;
element.removeClass('collapsing');
element.addClass('collapse');
element.css({height: 0});
} else {
// 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(function () {
element.removeClass('collapsing');
element.addClass('collapse');
});
}
}
};
}
};
}]);

scope.$watch(attrs.collapse, function (shouldCollapse) {
if (shouldCollapse) {
collapse();
} else {
expand();
}
});

}
};
}]);

//TODO:
//- refactor to remove code duplication
//- corner cases - what happens in animation is in progress?
//- tests based on the DOM state / classes

0 comments on commit cadc0f9

Please sign in to comment.