15
15
*
16
16
* @param {string } ui-view A view name.
17
17
*/
18
- $ViewDirective . $inject = [ '$state' , '$compile' , '$controller' , '$injector' , '$uiViewScroll' ] ;
19
- function $ViewDirective ( $state , $compile , $controller , $injector , $uiViewScroll ) {
18
+ $ViewDirective . $inject = [ '$state' , '$compile' , '$controller' , '$injector' , '$uiViewScroll' , '$document' ] ;
19
+ function $ViewDirective ( $state , $compile , $controller , $injector , $uiViewScroll , $document ) {
20
20
21
21
function getService ( ) {
22
22
return ( $injector . has ) ? function ( service ) {
@@ -30,118 +30,149 @@ function $ViewDirective( $state, $compile, $controller, $injector, $ui
30
30
} ;
31
31
}
32
32
33
- var viewIsUpdating = false , service = getService ( ) ,
34
- $animator = service ( '$animator' ) , $animate = service ( '$animate' ) ,
35
- hasAnimator = ! ! ( $animator || $animate ) ;
33
+ var viewIsUpdating = false ,
34
+ service = getService ( ) ,
35
+ $animator = service ( '$animator' ) ,
36
+ $animate = service ( '$animate' ) ;
36
37
37
38
// Returns a set of DOM manipulation functions based on whether animation
38
39
// should be performed
39
- var renderer = function ( shouldAnimate ) {
40
- return ( hasAnimator && shouldAnimate ) ? {
41
- remove : function ( element ) { $animate . leave ( element . contents ( ) ) ; } ,
42
- // remove: function(element) { animate.leave(element.contents(), element); },
43
- restore : function ( compiled , element ) { $animate . enter ( compiled , element ) ; } ,
44
- // restore: function(compiled, element) { animate.enter(compiled, element); },
45
- populate : function ( template , element ) {
46
- var contents = angular . element ( '<div></div>' ) . html ( template ) . contents ( ) ;
47
- // animate.enter(contents, element);
48
- $animate . enter ( contents , element ) ;
49
- return contents ;
50
- }
51
- } : {
52
- remove : function ( element ) { element . html ( '' ) ; } ,
53
- restore : function ( compiled , element ) { element . append ( compiled ) ; } ,
54
- populate : function ( template , element ) {
55
- element . html ( template ) ;
56
- return element . contents ( ) ;
57
- }
40
+ function getRenderer ( element , attrs , scope ) {
41
+ var statics = function ( ) {
42
+ return {
43
+ leave : function ( element ) { element . remove ( ) ; } ,
44
+ enter : function ( element , parent , anchor ) { anchor . after ( element ) ; }
45
+ } ;
58
46
} ;
59
- } ;
47
+
48
+ if ( $animate ) {
49
+ return function ( shouldAnimate ) {
50
+ return ! shouldAnimate ? statics ( ) : {
51
+ enter : function ( element , parent , anchor ) { $animate . enter ( element , null , anchor ) ; } ,
52
+ leave : function ( element ) { $animate . leave ( element , function ( ) { element . remove ( ) ; } ) ; }
53
+ } ;
54
+ } ;
55
+ }
56
+
57
+ if ( $animator ) {
58
+ var animate = $animator && $animator ( scope , attrs ) ;
59
+
60
+ return function ( shouldAnimate ) {
61
+ return ! shouldAnimate ? statics ( ) : {
62
+ enter : function ( element , parent , anchor ) { animate . enter ( element , parent ) ; } ,
63
+ leave : function ( element ) { animate . leave ( element . contents ( ) , element ) ; }
64
+ } ;
65
+ } ;
66
+ }
67
+
68
+ return statics ;
69
+ }
60
70
61
71
var directive = {
62
72
restrict : 'ECA' ,
63
- terminal : true ,
64
- priority : 1000 ,
65
- transclude : true ,
66
- compile : function ( element , attr , transclude ) {
67
- return function ( scope , element , attr ) {
68
- var viewScope , viewLocals ,
69
- name = attr [ directive . name ] || attr . name || '' ,
70
- onloadExp = attr . onload || '' ,
71
- autoscrollExp = attr . autoscroll ,
72
- animate = $animator && $animator ( scope , attr ) ,
73
- initialView = transclude ( scope ) ;
74
-
75
- // Put back the compiled initial view
76
- element . append ( initialView ) ;
77
-
78
- // Find the details of the parent view directive (if any) and use it
79
- // to derive our own qualified view name, then hang our own details
80
- // off the DOM so child directives can find it.
81
- var parent = element . parent ( ) . inheritedData ( '$uiView' ) ;
82
- if ( name . indexOf ( '@' ) < 0 ) name = name + '@' + ( parent ? parent . state . name : '' ) ;
73
+ compile : function ( element , attrs ) {
74
+ var initial = element . html ( ) ,
75
+ isDefault = true ,
76
+ anchor = angular . element ( $document [ 0 ] . createComment ( ' ui-view-anchor ' ) ) ,
77
+ parentEl = element . parent ( ) ;
78
+
79
+ element . prepend ( anchor ) ;
80
+
81
+ return function ( $scope ) {
82
+ var inherited = parentEl . inheritedData ( '$uiView' ) ;
83
+
84
+ var currentScope , currentEl , viewLocals ,
85
+ name = attrs [ directive . name ] || attrs . name || '' ,
86
+ onloadExp = attrs . onload || '' ,
87
+ autoscrollExp = attrs . autoscroll ,
88
+ renderer = getRenderer ( element , attrs , $scope ) ;
89
+
90
+ if ( name . indexOf ( '@' ) < 0 ) name = name + '@' + ( inherited ? inherited . state . name : '' ) ;
83
91
var view = { name : name , state : null } ;
84
- element . data ( '$uiView' , view ) ;
85
92
86
- var eventHook = function ( ) {
93
+ var eventHook = function ( ) {
87
94
if ( viewIsUpdating ) return ;
88
95
viewIsUpdating = true ;
89
96
90
- try { updateView ( true ) ; } catch ( e ) {
97
+ try { updateView ( ) ; } catch ( e ) {
91
98
viewIsUpdating = false ;
92
99
throw e ;
93
100
}
94
101
viewIsUpdating = false ;
95
102
} ;
96
103
97
- scope . $on ( '$stateChangeSuccess' , eventHook ) ;
98
- scope . $on ( '$viewContentLoading' , eventHook ) ;
99
- updateView ( false ) ;
104
+ $scope . $on ( '$stateChangeSuccess' , eventHook ) ;
105
+ $scope . $on ( '$viewContentLoading' , eventHook ) ;
100
106
101
- function updateView ( doAnimate ) {
102
- var locals = $state . $current && $state . $current . locals [ name ] ;
103
- if ( locals === viewLocals ) return ; // nothing to do
104
- var render = renderer ( doAnimate ) ;
107
+ updateView ( ) ;
105
108
106
- // Remove existing content
107
- render . remove ( element ) ;
109
+ function cleanupLastView ( ) {
110
+ if ( currentEl ) {
111
+ renderer ( true ) . leave ( currentEl ) ;
112
+ currentEl = null ;
113
+ }
108
114
109
- // Destroy previous view scope
110
- if ( viewScope ) {
111
- viewScope . $destroy ( ) ;
112
- viewScope = null ;
115
+ if ( currentScope ) {
116
+ currentScope . $destroy ( ) ;
117
+ currentScope = null ;
113
118
}
119
+ }
114
120
115
- if ( ! locals ) {
116
- viewLocals = null ;
117
- view . state = null ;
121
+ function updateView ( ) {
122
+ var locals = $state . $current && $state . $current . locals [ name ] ;
123
+
124
+ if ( isDefault ) {
125
+ isDefault = false ;
126
+ element . replaceWith ( anchor ) ;
127
+ }
118
128
119
- // Restore the initial view
120
- return render . restore ( initialView , element ) ;
129
+ if ( ! locals ) {
130
+ cleanupLastView ( ) ;
131
+ currentEl = element . clone ( ) ;
132
+ currentEl . html ( initial ) ;
133
+ anchor . after ( currentEl ) ;
134
+
135
+ currentScope = $scope . $new ( ) ;
136
+ $compile ( currentEl . contents ( ) ) ( currentScope ) ;
137
+ return ;
121
138
}
122
139
140
+ if ( locals === viewLocals ) return ; // nothing to do
141
+
142
+ cleanupLastView ( ) ;
143
+
144
+ currentEl = element . clone ( ) ;
145
+ currentEl . html ( locals . $template ? locals . $template : initial ) ;
146
+ renderer ( true ) . enter ( currentEl , parentEl , anchor ) ;
147
+
148
+ currentEl . data ( '$uiView' , view ) ;
149
+
123
150
viewLocals = locals ;
124
151
view . state = locals . $$state ;
125
152
126
- var link = $compile ( render . populate ( locals . $template , element ) ) ;
127
- viewScope = scope . $new ( ) ;
153
+ var link = $compile ( currentEl . contents ( ) ) ;
154
+
155
+ currentScope = $scope . $new ( ) ;
128
156
129
157
if ( locals . $$controller ) {
130
- locals . $scope = viewScope ;
158
+ locals . $scope = currentScope ;
131
159
var controller = $controller ( locals . $$controller , locals ) ;
132
- element . children ( ) . data ( '$ngControllerController' , controller ) ;
160
+ currentEl . children ( ) . data ( '$ngControllerController' , controller ) ;
133
161
}
134
- link ( viewScope ) ;
135
- viewScope . $emit ( '$viewContentLoaded' ) ;
136
- if ( onloadExp ) viewScope . $eval ( onloadExp ) ;
137
162
138
- if ( ! angular . isDefined ( autoscrollExp ) || ! autoscrollExp || scope . $eval ( autoscrollExp ) ) {
139
- $uiViewScroll ( element ) ;
163
+ link ( currentScope ) ;
164
+
165
+ currentScope . $emit ( '$viewContentLoaded' ) ;
166
+ if ( onloadExp ) currentScope . $eval ( onloadExp ) ;
167
+
168
+ if ( ! angular . isDefined ( autoscrollExp ) || ! autoscrollExp || $scope . $eval ( autoscrollExp ) ) {
169
+ $uiViewScroll ( currentEl ) ;
140
170
}
141
171
}
142
172
} ;
143
173
}
144
174
} ;
175
+
145
176
return directive ;
146
177
}
147
178
0 commit comments