diff --git a/src/accordion/test/accordionSpec.js b/src/accordion/test/accordionSpec.js index 05896ab6ff..28a614061f 100644 --- a/src/accordion/test/accordionSpec.js +++ b/src/accordion/test/accordionSpec.js @@ -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); @@ -264,7 +264,7 @@ describe('accordion', function () { describe('accordion-heading element', function() { beforeEach(function() { - var tpl = + var tpl = '' + '' + 'Heading Element {{x}} ' + @@ -286,7 +286,7 @@ describe('accordion', function () { describe('accordion-heading attribute', function() { beforeEach(function() { - var tpl = + var tpl = '' + '' + '
Heading Element {{x}}
' + diff --git a/src/collapse/collapse.js b/src/collapse/collapse.js index d0a33b454f..913d3c50b5 100644 --- a/src/collapse/collapse.js +++ b/src/collapse/collapse.js @@ -1,44 +1,35 @@ 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(); @@ -46,50 +37,81 @@ angular.module('ui.bootstrap.collapse',['ui.bootstrap.transition']) 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); + }); } }; } }; -}]); +}]); \ No newline at end of file diff --git a/src/collapse/docs/demo.html b/src/collapse/docs/demo.html index 207113ee76..b0ca0acf28 100644 --- a/src/collapse/docs/demo.html +++ b/src/collapse/docs/demo.html @@ -1,7 +1,16 @@
+
-
Some content
+
+

Some content

+
+
+
+

Initial content

+
Additional content
+
+
\ No newline at end of file diff --git a/src/collapse/docs/demo.js b/src/collapse/docs/demo.js index b85bab4b52..028bc48db6 100644 --- a/src/collapse/docs/demo.js +++ b/src/collapse/docs/demo.js @@ -1,3 +1,4 @@ function CollapseDemoCtrl($scope) { $scope.isCollapsed = false; + $scope.exp = false; } diff --git a/src/collapse/test/collapse.spec.js b/src/collapse/test/collapse.spec.js index d04a8b3c90..36b1c7708c 100644 --- a/src/collapse/test/collapse.spec.js +++ b/src/collapse/test/collapse.spec.js @@ -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(); diff --git a/src/transition/transition.js b/src/transition/transition.js index c23d3f76f7..c93af5da71 100644 --- a/src/transition/transition.js +++ b/src/transition/transition.js @@ -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); }); @@ -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); } @@ -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; }]); diff --git a/template/accordion/accordion-group.html b/template/accordion/accordion-group.html index 00746a482b..93b72120df 100644 --- a/template/accordion/accordion-group.html +++ b/template/accordion/accordion-group.html @@ -1,9 +1,5 @@
-
-

- {{heading}} -

-
+
{{heading}}