1515 *
1616 * @param {string } ui-view A view name.
1717 */
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 ) {
2020
2121 function getService ( ) {
2222 return ( $injector . has ) ? function ( service ) {
@@ -30,118 +30,149 @@ function $ViewDirective( $state, $compile, $controller, $injector, $ui
3030 } ;
3131 }
3232
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' ) ;
3637
3738 // Returns a set of DOM manipulation functions based on whether animation
3839 // 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+ } ;
5846 } ;
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+ }
6070
6171 var directive = {
6272 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 : '' ) ;
8391 var view = { name : name , state : null } ;
84- element . data ( '$uiView' , view ) ;
8592
86- var eventHook = function ( ) {
93+ var eventHook = function ( ) {
8794 if ( viewIsUpdating ) return ;
8895 viewIsUpdating = true ;
8996
90- try { updateView ( true ) ; } catch ( e ) {
97+ try { updateView ( ) ; } catch ( e ) {
9198 viewIsUpdating = false ;
9299 throw e ;
93100 }
94101 viewIsUpdating = false ;
95102 } ;
96103
97- scope . $on ( '$stateChangeSuccess' , eventHook ) ;
98- scope . $on ( '$viewContentLoading' , eventHook ) ;
99- updateView ( false ) ;
104+ $scope . $on ( '$stateChangeSuccess' , eventHook ) ;
105+ $scope . $on ( '$viewContentLoading' , eventHook ) ;
100106
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 ( ) ;
105108
106- // Remove existing content
107- render . remove ( element ) ;
109+ function cleanupLastView ( ) {
110+ if ( currentEl ) {
111+ renderer ( true ) . leave ( currentEl ) ;
112+ currentEl = null ;
113+ }
108114
109- // Destroy previous view scope
110- if ( viewScope ) {
111- viewScope . $destroy ( ) ;
112- viewScope = null ;
115+ if ( currentScope ) {
116+ currentScope . $destroy ( ) ;
117+ currentScope = null ;
113118 }
119+ }
114120
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+ }
118128
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 ;
121138 }
122139
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+
123150 viewLocals = locals ;
124151 view . state = locals . $$state ;
125152
126- var link = $compile ( render . populate ( locals . $template , element ) ) ;
127- viewScope = scope . $new ( ) ;
153+ var link = $compile ( currentEl . contents ( ) ) ;
154+
155+ currentScope = $scope . $new ( ) ;
128156
129157 if ( locals . $$controller ) {
130- locals . $scope = viewScope ;
158+ locals . $scope = currentScope ;
131159 var controller = $controller ( locals . $$controller , locals ) ;
132- element . children ( ) . data ( '$ngControllerController' , controller ) ;
160+ currentEl . children ( ) . data ( '$ngControllerController' , controller ) ;
133161 }
134- link ( viewScope ) ;
135- viewScope . $emit ( '$viewContentLoaded' ) ;
136- if ( onloadExp ) viewScope . $eval ( onloadExp ) ;
137162
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 ) ;
140170 }
141171 }
142172 } ;
143173 }
144174 } ;
175+
145176 return directive ;
146177}
147178
0 commit comments