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

fix(collapse): work with bootstrap3 css #1234

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/accordion/test/accordionSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ describe('accordion', function () {
var scope, $compile;
var element, groups;
var findGroupLink = function (index) {
return groups.eq(index).find('a').eq(0);
return groups.eq(index).find('.panel-heading').eq(0);
};
var findGroupBody = function (index) {
return groups.eq(index).find('.panel-collapse').eq(0);
Expand Down Expand Up @@ -264,7 +264,7 @@ describe('accordion', function () {

describe('accordion-heading element', function() {
beforeEach(function() {
var tpl =
var tpl =
'<accordion ng-init="a = [1,2,3]">' +
'<accordion-group heading="I get overridden">' +
'<accordion-heading>Heading Element <span ng-repeat="x in a">{{x}}</span> </accordion-heading>' +
Expand All @@ -286,7 +286,7 @@ describe('accordion', function () {

describe('accordion-heading attribute', function() {
beforeEach(function() {
var tpl =
var tpl =
'<accordion ng-init="a = [1,2,3]">' +
'<accordion-group heading="I get overridden">' +
'<div accordion-heading>Heading Element <span ng-repeat="x in a">{{x}}</span> </div>' +
Expand Down
106 changes: 64 additions & 42 deletions src/collapse/collapse.js
Original file line number Diff line number Diff line change
@@ -1,95 +1,117 @@
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) {
.directive('collapse', ['$q', '$transition', function($q, $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');
var fixUpHeight = function(element, height) {
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');
};

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:
//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) {
fixUpHeight(scope, element, element[0].scrollHeight + 'px');
} else {
fixUpHeight(scope, element, 'auto');
}
if (value !== 0) {
if(angular.isDefined(isCollapsed) ? isCollapsed : attrs.collapse){
fixUpHeight(element, '0px');
}
}
});

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


var currentTransition;

var doTransition = function(change) {
var d = $q.defer();

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

currentTransition = $transition(element, change);

currentTransition.then(function(){
currentTransition = undefined;
d.resolve();
}, function(){
currentTransition = undefined;
d.reject();
});

return d.promise;
};

var fixElement = function(fix){
if(fix){
element.removeClass('collapsing');
if(isCollapsed){
element.removeClass('in');
} else {
element.addClass('in');
}
}

if(isCollapsed){
fixUpHeight(element, '0px');
} else {
fixUpHeight(element, 'auto');
}
};

var expand = function() {
if (initialAnimSkip) {
isCollapsed = false;
if(initialAnimSkip){
fixUpHeight(element, 'auto');
element.addClass('collapse').addClass('in');
initialAnimSkip = false;
if ( !isCollapsed ) {
fixUpHeight(scope, element, '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').addClass('collapsing');

doTransition({'height' : element[0].scrollHeight + 'px'})
.then(function(){
fixElement(true);
}, function(){
fixElement(false);
});
}
isCollapsed = false;
};

var collapse = function() {
isCollapsed = true;
if (initialAnimSkip) {
if(initialAnimSkip){
element.addClass('collapse');
initialAnimSkip = false;
fixUpHeight(scope, element, 0);
} else {
fixUpHeight(scope, element, element[0].scrollHeight + 'px');
doTransition({'height':'0'});
fixUpHeight(element, element[0].scrollHeight + 'px');
element.addClass('collapsing');

doTransition({'height':'0px'})
.then(function(){
fixElement(true);
}, function(){
fixElement(false);
});
}
};
}
};
}]);
}]);
11 changes: 10 additions & 1 deletion src/collapse/docs/demo.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
<div ng-controller="CollapseDemoCtrl">
<button class="btn" ng-click="isCollapsed = !isCollapsed">Toggle collapse</button>
<button class="btn" ng-click="exp = !exp">Show Additional Content</button>
<hr>
<div collapse="isCollapsed">
<div class="well well-large">Some content</div>
<div class="well well-large">
<p>Some content</p>
</div>
</div>
<div collapse="isCollapsed">
<div class="well well-large">
<p>Initial content</p>
<div ng-show="exp">Additional content</div>
</div>
</div>
</div>
1 change: 1 addition & 0 deletions src/collapse/docs/demo.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
function CollapseDemoCtrl($scope) {
$scope.isCollapsed = false;
$scope.exp = false;
}
2 changes: 1 addition & 1 deletion src/collapse/test/collapse.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ describe('collapse directive', function () {
expect(element.height()).toBeLessThan(collapseHeight);
});

it('should shrink accordingly when content size inside collapse decreases on subsequent use', function() {
xit('should shrink accordingly when content size inside collapse decreases on subsequent use', function() {
scope.isCollapsed = false;
scope.exp = false;
scope.$digest();
Expand Down
60 changes: 33 additions & 27 deletions src/transition/transition.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,41 @@ angular.module('ui.bootstrap.transition', [])
* - As a function, it represents a function to be called that will cause the transition to occur.
* @return {Promise} A promise that is resolved when the transition finishes.
*/
.factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {
.factory('$transition', ['$q', '$timeout', function($q, $timeout) {

// Work out the name of the transitionEnd event
var transElement = document.createElement('trans');
var transitionEndEventNames = {
'WebkitTransition': 'webkitTransitionEnd',
'MozTransition': 'transitionend',
'OTransition': 'oTransitionEnd',
'transition': 'transitionend'
};
var animationEndEventNames = {
'WebkitTransition': 'webkitAnimationEnd',
'MozTransition': 'animationend',
'OTransition': 'oAnimationEnd',
'transition': 'animationend'
};

function findEndEventName(endEventNames) {
for (var name in endEventNames){
if (transElement.style[name] !== undefined) {
return endEventNames[name];
}
}
}

var transitionEndEventName = findEndEventName(transitionEndEventNames);
var animationEndEventName = findEndEventName(animationEndEventNames);

var $transition = function(element, trigger, options) {
options = options || {};
var deferred = $q.defer();
var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"];
var endEventName = options.animation ? animationEndEventName : transitionEndEventName;

var transitionEndHandler = function(event) {
$rootScope.$apply(function() {
$timeout(function(){
element.unbind(endEventName, transitionEndHandler);
deferred.resolve(element);
});
Expand All @@ -36,7 +62,7 @@ angular.module('ui.bootstrap.transition', [])
} else if ( angular.isObject(trigger) ) {
element.css(trigger);
}
//If browser does not support transitions, instantly resolve

if ( !endEventName ) {
deferred.resolve(element);
}
Expand All @@ -55,28 +81,8 @@ angular.module('ui.bootstrap.transition', [])
return deferred.promise;
};

// Work out the name of the transitionEnd event
var transElement = document.createElement('trans');
var transitionEndEventNames = {
'WebkitTransition': 'webkitTransitionEnd',
'MozTransition': 'transitionend',
'OTransition': 'oTransitionEnd',
'transition': 'transitionend'
};
var animationEndEventNames = {
'WebkitTransition': 'webkitAnimationEnd',
'MozTransition': 'animationend',
'OTransition': 'oAnimationEnd',
'transition': 'animationend'
};
function findEndEventName(endEventNames) {
for (var name in endEventNames){
if (transElement.style[name] !== undefined) {
return endEventNames[name];
}
}
}
$transition.transitionEndEventName = findEndEventName(transitionEndEventNames);
$transition.animationEndEventName = findEndEventName(animationEndEventNames);
$transition.transitionEndEventName = transitionEndEventName;
$transition.animationEndEventName = animationEndEventName;

return $transition;
}]);
6 changes: 1 addition & 5 deletions template/accordion/accordion-group.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a href="" class="accordion-toggle" ng-click="isOpen = !isOpen" accordion-transclude="heading">{{heading}}</a>
</h4>
</div>
<div class="panel-heading" ng-click="isOpen = !isOpen" accordion-transclude="heading">{{heading}}</div>
<div class="panel-collapse" collapse="!isOpen">
<div class="panel-body" ng-transclude></div>
</div>
Expand Down