1
- angular . module ( 'ui.bootstrap.collapse' , [ 'ui.bootstrap.transition' ] )
1
+ angular . module ( 'ui.bootstrap.collapse' , [ 'ui.bootstrap.transition' ] )
2
2
3
- // The collapsible directive indicates a block of html that will expand and collapse
4
- . directive ( 'collapse' , [ '$transition' , function ( $transition ) {
5
- // CSS transitions don't work with height: auto, so we have to manually change the height to a
6
- // specific value and then once the animation completes, we can reset the height to auto.
7
- // Unfortunately if you do this while the CSS transitions are specified (i.e. in the CSS class
8
- // "collapse") then you trigger a change to height 0 in between.
9
- // The fix is to remove the "collapse" CSS class while changing the height back to auto - phew!
10
- var fixUpHeight = function ( scope , element , height ) {
11
- // We remove the collapse CSS class to prevent a transition when we change to height: auto
12
- element . removeClass ( 'collapse' ) ;
13
- element . css ( { height : height } ) ;
14
- // It appears that reading offsetWidth makes the browser realise that we have changed the
15
- // height already :-/
16
- var x = element [ 0 ] . offsetWidth ;
17
- element . addClass ( 'collapse' ) ;
18
- } ;
3
+ . directive ( 'collapse' , [ '$transition' , function ( $transition , $timeout ) {
19
4
20
- return {
21
- link : function ( scope , element , attrs ) {
5
+ return {
6
+ link : function ( scope , element , attrs ) {
22
7
23
- var isCollapsed ;
24
- var initialAnimSkip = true ;
8
+ var initialAnimSkip = true ;
9
+ var currentTransition ;
25
10
26
- scope . $watch ( attrs . collapse , function ( value ) {
27
- if ( value ) {
28
- collapse ( ) ;
29
- } else {
30
- expand ( ) ;
11
+ function resetCurrentTransition ( ) {
12
+ currentTransition = undefined ;
31
13
}
32
- } ) ;
33
-
34
14
35
- var currentTransition ;
36
- var doTransition = function ( change ) {
37
- if ( currentTransition ) {
38
- currentTransition . cancel ( ) ;
15
+ function doTransition ( change ) {
16
+ if ( currentTransition ) {
17
+ currentTransition . cancel ( ) ;
18
+ }
19
+ ( currentTransition = $transition ( element , change ) ) . then ( resetCurrentTransition , resetCurrentTransition ) ;
20
+ return currentTransition ;
39
21
}
40
- currentTransition = $transition ( element , change ) ;
41
- currentTransition . then (
42
- function ( ) { currentTransition = undefined ; } ,
43
- function ( ) { currentTransition = undefined ; }
44
- ) ;
45
- return currentTransition ;
46
- } ;
47
22
48
- var expand = function ( ) {
49
- if ( initialAnimSkip ) {
50
- initialAnimSkip = false ;
51
- if ( ! isCollapsed ) {
52
- fixUpHeight ( scope , element , 'auto' ) ;
53
- element . addClass ( 'in' ) ;
23
+ function expand ( ) {
24
+ if ( initialAnimSkip ) {
25
+ initialAnimSkip = false ;
26
+ element . removeClass ( 'collapsing' ) ;
27
+ element . addClass ( 'collapse in' ) ;
28
+ element . css ( { height : 'auto' } ) ;
29
+ } else {
30
+ element . removeClass ( 'collapse' ) . addClass ( 'collapsing' ) ;
31
+ doTransition ( { height : element [ 0 ] . scrollHeight + 'px' } ) . then ( function ( ) {
32
+ element . removeClass ( 'collapsing' ) ;
33
+ element . addClass ( 'collapse in' ) ;
34
+ element . css ( { height : 'auto' } ) ;
35
+ } ) ;
54
36
}
55
- } else {
56
- doTransition ( { height : element [ 0 ] . scrollHeight + 'px' } )
57
- . then ( function ( ) {
58
- // This check ensures that we don't accidentally update the height if the user has closed
59
- // the group while the animation was still running
60
- if ( ! isCollapsed ) {
61
- fixUpHeight ( scope , element , 'auto' ) ;
62
- element . addClass ( 'in' ) ;
63
- }
64
- } ) ;
65
37
}
66
- isCollapsed = false ;
67
- } ;
68
-
69
- var collapse = function ( ) {
70
- isCollapsed = true ;
71
- element . removeClass ( 'in' ) ;
72
- if ( initialAnimSkip ) {
73
- initialAnimSkip = false ;
74
- fixUpHeight ( scope , element , 0 ) ;
75
- } else {
76
- fixUpHeight ( scope , element , element [ 0 ] . scrollHeight + 'px' ) ;
77
- doTransition ( { 'height' :'0' } ) ;
38
+
39
+ function collapse ( ) {
40
+ if ( initialAnimSkip ) {
41
+ element . removeClass ( 'collapsing' ) ;
42
+ element . addClass ( 'collapse' ) ;
43
+ element . css ( { height : 0 } ) ;
44
+ } else {
45
+ // CSS transitions don't work with height: auto, so we have to manually change the height to a specific value
46
+ element . css ( { height : element [ 0 ] . scrollHeight + 'px' } ) ;
47
+ //trigger reflow so a browser relaizes that height was updated from auto to a specific value
48
+ var x = element [ 0 ] . offsetWidth ;
49
+
50
+ element . removeClass ( 'collapse in' ) . addClass ( 'collapsing' ) ;
51
+
52
+ doTransition ( { height : 0 } ) . then ( function ( ) {
53
+ element . removeClass ( 'collapsing' ) ;
54
+ element . addClass ( 'collapse' ) ;
55
+ } ) ;
56
+ }
78
57
}
79
- } ;
80
- }
81
- } ;
82
- } ] ) ;
58
+
59
+ scope . $watch ( attrs . collapse , function ( shouldCollapse ) {
60
+ if ( shouldCollapse ) {
61
+ collapse ( ) ;
62
+ } else {
63
+ expand ( ) ;
64
+ }
65
+ } ) ;
66
+
67
+ }
68
+ } ;
69
+ } ] ) ;
70
+
71
+ //TODO:
72
+ //- refactor to remove code duplication
73
+ //- corner cases - what happens in animation is in progress?
74
+ //- tests based on the DOM state / classes
0 commit comments