11import { provide , ReflectiveInjector , ComponentResolver } from 'angular2/core' ;
22import { RouterOutlet } from './directives/router_outlet' ;
33import { Type , isBlank , isPresent } from 'angular2/src/facade/lang' ;
4+ import { StringMapWrapper } from 'angular2/src/facade/collection' ;
5+ import { BaseException } from 'angular2/src/facade/exceptions' ;
46import { RouterUrlParser } from './router_url_parser' ;
57import { recognize } from './recognize' ;
6- import { equalSegments , routeSegmentComponentFactory , RouteSegment , Tree } from './segments' ;
8+ import {
9+ equalSegments ,
10+ routeSegmentComponentFactory ,
11+ RouteSegment ,
12+ Tree ,
13+ rootNode ,
14+ TreeNode
15+ } from './segments' ;
716import { hasLifecycleHook } from './lifecycle_reflector' ;
17+ import { DEFAULT_OUTLET_NAME } from './constants' ;
818
919export class RouterOutletMap {
1020 /** @internal */
@@ -18,38 +28,78 @@ export class Router {
1828 private _urlParser : RouterUrlParser , private _routerOutletMap : RouterOutletMap ) { }
1929
2030 navigateByUrl ( url : string ) : Promise < void > {
21- let urlSegmentTree = this . _urlParser . parse ( url . substring ( 1 ) ) ;
31+ let urlSegmentTree = this . _urlParser . parse ( url ) ;
2232 return recognize ( this . _componentResolver , this . _componentType , urlSegmentTree )
2333 . then ( currTree => {
24- let prevRoot = isPresent ( this . prevTree ) ? this . prevTree . root : null ;
25- _loadSegments ( currTree , currTree . root , this . prevTree , prevRoot , this ,
26- this . _routerOutletMap ) ;
34+ let prevRoot = isPresent ( this . prevTree ) ? rootNode ( this . prevTree ) : null ;
35+ new _SegmentLoader ( currTree , this . prevTree )
36+ . loadSegments ( rootNode ( currTree ) , prevRoot , this . _routerOutletMap ) ;
2737 this . prevTree = currTree ;
2838 } ) ;
2939 }
3040}
3141
32- function _loadSegments ( currTree : Tree < RouteSegment > , curr : RouteSegment ,
33- prevTree : Tree < RouteSegment > , prev : RouteSegment , router : Router ,
34- parentOutletMap : RouterOutletMap ) : void {
35- let outlet = parentOutletMap . _outlets [ curr . outlet ] ;
42+ class _SegmentLoader {
43+ constructor ( private currTree : Tree < RouteSegment > , private prevTree : Tree < RouteSegment > ) { }
3644
37- let outletMap ;
38- if ( equalSegments ( curr , prev ) ) {
39- outletMap = outlet . outletMap ;
40- } else {
41- outletMap = new RouterOutletMap ( ) ;
45+ loadSegments ( currNode : TreeNode < RouteSegment > , prevNode : TreeNode < RouteSegment > ,
46+ parentOutletMap : RouterOutletMap ) : void {
47+ let curr = currNode . value ;
48+ let prev = isPresent ( prevNode ) ? prevNode . value : null ;
49+ let outlet = this . getOutlet ( parentOutletMap , currNode . value ) ;
50+
51+ if ( equalSegments ( curr , prev ) ) {
52+ this . loadChildSegments ( currNode , prevNode , outlet . outletMap ) ;
53+ } else {
54+ let outletMap = new RouterOutletMap ( ) ;
55+ this . loadNewSegment ( outletMap , curr , prev , outlet ) ;
56+ this . loadChildSegments ( currNode , prevNode , outletMap ) ;
57+ }
58+ }
59+
60+ private loadNewSegment ( outletMap : RouterOutletMap , curr : RouteSegment , prev : RouteSegment ,
61+ outlet : RouterOutlet ) : void {
4262 let resolved = ReflectiveInjector . resolve (
4363 [ provide ( RouterOutletMap , { useValue : outletMap } ) , provide ( RouteSegment , { useValue : curr } ) ] ) ;
4464 let ref = outlet . load ( routeSegmentComponentFactory ( curr ) , resolved , outletMap ) ;
4565 if ( hasLifecycleHook ( "routerOnActivate" , ref . instance ) ) {
46- ref . instance . routerOnActivate ( curr , prev , currTree , prevTree ) ;
66+ ref . instance . routerOnActivate ( curr , prev , this . currTree , this . prevTree ) ;
67+ }
68+ }
69+
70+ private loadChildSegments ( currNode : TreeNode < RouteSegment > , prevNode : TreeNode < RouteSegment > ,
71+ outletMap : RouterOutletMap ) : void {
72+ let prevChildren = isPresent ( prevNode ) ?
73+ prevNode . children . reduce (
74+ ( m , c ) => {
75+ m [ c . value . outlet ] = c ;
76+ return m ;
77+ } ,
78+ { } ) :
79+ { } ;
80+
81+ currNode . children . forEach ( c => {
82+ this . loadSegments ( c , prevChildren [ c . value . outlet ] , outletMap ) ;
83+ StringMapWrapper . delete ( prevChildren , c . value . outlet ) ;
84+ } ) ;
85+
86+ StringMapWrapper . forEach ( prevChildren , ( v , k ) => this . unloadOutlet ( outletMap . _outlets [ k ] ) ) ;
87+ }
88+
89+ private getOutlet ( outletMap : RouterOutletMap , segment : RouteSegment ) : RouterOutlet {
90+ let outlet = outletMap . _outlets [ segment . outlet ] ;
91+ if ( isBlank ( outlet ) ) {
92+ if ( segment . outlet == DEFAULT_OUTLET_NAME ) {
93+ throw new BaseException ( `Cannot find default outlet` ) ;
94+ } else {
95+ throw new BaseException ( `Cannot find the outlet ${ segment . outlet } ` ) ;
96+ }
4797 }
98+ return outlet ;
4899 }
49100
50- if ( isPresent ( currTree . firstChild ( curr ) ) ) {
51- let cc = currTree . firstChild ( curr ) ;
52- let pc = isBlank ( prevTree ) ? null : prevTree . firstChild ( prev ) ;
53- _loadSegments ( currTree , cc , prevTree , pc , router , outletMap ) ;
101+ private unloadOutlet ( outlet : RouterOutlet ) : void {
102+ StringMapWrapper . forEach ( outlet . outletMap . _outlets , ( v , k ) => { this . unloadOutlet ( v ) ; } ) ;
103+ outlet . unload ( ) ;
54104 }
55105}
0 commit comments