This repository has been archived by the owner on May 29, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(collapse): make collapse work with bootstrap3
Closes #1240 If starting out collapsed, the expand animation would jump since the `initialAnimSkip` was still `true`.
- Loading branch information
1 parent
a3d53d8
commit e907599
Showing
1 changed file
with
64 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |