| 
									
										
											  
											
												refactor(router): improve recognition and generation pipeline
This is a big change. @matsko also deserves much of the credit for the implementation.
Previously, `ComponentInstruction`s held all the state for async components.
Now, we introduce several subclasses for `Instruction` to describe each type of navigation.
BREAKING CHANGE:
Redirects now use the Link DSL syntax. Before:
```
@RouteConfig([
	{ path: '/foo', redirectTo: '/bar' },
	{ path: '/bar', component: BarCmp }
])
```
After:
```
@RouteConfig([
	{ path: '/foo', redirectTo: ['Bar'] },
	{ path: '/bar', component: BarCmp, name: 'Bar' }
])
```
BREAKING CHANGE:
This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading
and encapsulating large routes with sub-routes easier.
Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`:
@RouteConfig([
	{ path: '/tab', redirectTo: '/tab/users' }
	{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
Now the recommended way to handle this is case is to use `useAsDefault` like so:
```
@RouteConfig([
	{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
@RouteConfig([
	{ path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' },
	{ path: '/users', component: UsersCmp, name: 'Users' }
])
TabsCmp { ... }
```
In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route.
Closes #4728
Closes #4228
Closes #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5475
											
										 
											2015-11-23 18:07:37 -08:00
										 |  |  | import {provide, Provider, Component, View} from 'angular2/core'; | 
					
						
							|  |  |  | import {Type, isBlank} from 'angular2/src/facade/lang'; | 
					
						
							|  |  |  | import {BaseException} from 'angular2/src/facade/exceptions'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import { | 
					
						
							| 
									
										
										
										
											2015-12-02 11:54:10 -08:00
										 |  |  |   ComponentFixture, | 
					
						
							| 
									
										
											  
											
												refactor(router): improve recognition and generation pipeline
This is a big change. @matsko also deserves much of the credit for the implementation.
Previously, `ComponentInstruction`s held all the state for async components.
Now, we introduce several subclasses for `Instruction` to describe each type of navigation.
BREAKING CHANGE:
Redirects now use the Link DSL syntax. Before:
```
@RouteConfig([
	{ path: '/foo', redirectTo: '/bar' },
	{ path: '/bar', component: BarCmp }
])
```
After:
```
@RouteConfig([
	{ path: '/foo', redirectTo: ['Bar'] },
	{ path: '/bar', component: BarCmp, name: 'Bar' }
])
```
BREAKING CHANGE:
This also introduces `useAsDefault` in the RouteConfig, which makes cases like lazy-loading
and encapsulating large routes with sub-routes easier.
Previously, you could use `redirectTo` like this to expand a URL like `/tab` to `/tab/posts`:
@RouteConfig([
	{ path: '/tab', redirectTo: '/tab/users' }
	{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
Now the recommended way to handle this is case is to use `useAsDefault` like so:
```
@RouteConfig([
	{ path: '/tab', component: TabsCmp, name: 'Tab' }
])
AppCmp { ... }
@RouteConfig([
	{ path: '/posts', component: PostsCmp, useAsDefault: true, name: 'Posts' },
	{ path: '/users', component: UsersCmp, name: 'Users' }
])
TabsCmp { ... }
```
In the above example, you can write just `['/Tab']` and the route `Users` is automatically selected as a child route.
Closes #4728
Closes #4228
Closes #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5475
											
										 
											2015-11-23 18:07:37 -08:00
										 |  |  |   AsyncTestCompleter, | 
					
						
							|  |  |  |   TestComponentBuilder, | 
					
						
							|  |  |  |   beforeEach, | 
					
						
							|  |  |  |   ddescribe, | 
					
						
							|  |  |  |   xdescribe, | 
					
						
							|  |  |  |   describe, | 
					
						
							|  |  |  |   el, | 
					
						
							|  |  |  |   inject, | 
					
						
							|  |  |  |   beforeEachProviders, | 
					
						
							|  |  |  |   it, | 
					
						
							|  |  |  |   xit | 
					
						
							|  |  |  | } from 'angular2/testing_internal'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import {RootRouter} from 'angular2/src/router/router'; | 
					
						
							|  |  |  | import {Router, ROUTER_DIRECTIVES, ROUTER_PRIMARY_COMPONENT} from 'angular2/router'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import {SpyLocation} from 'angular2/src/mock/location_mock'; | 
					
						
							|  |  |  | import {Location} from 'angular2/src/router/location'; | 
					
						
							|  |  |  | import {RouteRegistry} from 'angular2/src/router/route_registry'; | 
					
						
							|  |  |  | import {DirectiveResolver} from 'angular2/src/core/linker/directive_resolver'; | 
					
						
							|  |  |  | import {DOM} from 'angular2/src/platform/dom/dom_adapter'; | 
					
						
							|  |  |  | export {ComponentFixture} from 'angular2/testing_internal'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Router test helpers and fixtures | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @Component({ | 
					
						
							|  |  |  |   selector: 'root-comp', | 
					
						
							|  |  |  |   template: `<router-outlet></router-outlet>`, | 
					
						
							|  |  |  |   directives: [ROUTER_DIRECTIVES] | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | export class RootCmp { | 
					
						
							|  |  |  |   name: string; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function compile(tcb: TestComponentBuilder, | 
					
						
							|  |  |  |                         template: string = "<router-outlet></router-outlet>") { | 
					
						
							|  |  |  |   return tcb.overrideTemplate(RootCmp, ('<div>' + template + '</div>')).createAsync(RootCmp); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export var TEST_ROUTER_PROVIDERS = [ | 
					
						
							|  |  |  |   RouteRegistry, | 
					
						
							|  |  |  |   DirectiveResolver, | 
					
						
							|  |  |  |   provide(Location, {useClass: SpyLocation}), | 
					
						
							|  |  |  |   provide(ROUTER_PRIMARY_COMPONENT, {useValue: RootCmp}), | 
					
						
							|  |  |  |   provide(Router, {useClass: RootRouter}) | 
					
						
							|  |  |  | ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function clickOnElement(anchorEl) { | 
					
						
							|  |  |  |   var dispatchedEvent = DOM.createMouseEvent('click'); | 
					
						
							|  |  |  |   DOM.dispatchEvent(anchorEl, dispatchedEvent); | 
					
						
							|  |  |  |   return dispatchedEvent; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function getHref(elt) { | 
					
						
							|  |  |  |   return DOM.getAttribute(elt, 'href'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Router integration suite DSL | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var specNameBuilder = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // we add the specs themselves onto this map
 | 
					
						
							|  |  |  | export var specs = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function describeRouter(description: string, fn: Function, exclusive = false): void { | 
					
						
							|  |  |  |   var specName = descriptionToSpecName(description); | 
					
						
							|  |  |  |   specNameBuilder.push(specName); | 
					
						
							|  |  |  |   describe(description, fn); | 
					
						
							|  |  |  |   specNameBuilder.pop(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function ddescribeRouter(description: string, fn: Function, exclusive = false): void { | 
					
						
							|  |  |  |   describeRouter(description, fn, true); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function describeWithAndWithout(description: string, fn: Function): void { | 
					
						
							|  |  |  |   // the "without" case is usually simpler, so we opt to run this spec first
 | 
					
						
							|  |  |  |   describeWithout(description, fn); | 
					
						
							|  |  |  |   describeWith(description, fn); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function describeWith(description: string, fn: Function): void { | 
					
						
							|  |  |  |   var specName = 'with ' + description; | 
					
						
							|  |  |  |   specNameBuilder.push(specName); | 
					
						
							|  |  |  |   describe(specName, fn); | 
					
						
							|  |  |  |   specNameBuilder.pop(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function describeWithout(description: string, fn: Function): void { | 
					
						
							|  |  |  |   var specName = 'without ' + description; | 
					
						
							|  |  |  |   specNameBuilder.push(specName); | 
					
						
							|  |  |  |   describe(specName, fn); | 
					
						
							|  |  |  |   specNameBuilder.pop(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function descriptionToSpecName(description: string): string { | 
					
						
							|  |  |  |   return spaceCaseToCamelCase(description); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // this helper looks up the suite registered from the "impl" folder in this directory
 | 
					
						
							|  |  |  | export function itShouldRoute() { | 
					
						
							|  |  |  |   var specSuiteName = spaceCaseToCamelCase(specNameBuilder.join(' ')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var spec = specs[specSuiteName]; | 
					
						
							|  |  |  |   if (isBlank(spec)) { | 
					
						
							|  |  |  |     throw new BaseException(`Router integration spec suite "${specSuiteName}" was not found.`); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     // todo: remove spec from map, throw if there are extra left over??
 | 
					
						
							|  |  |  |     spec(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function spaceCaseToCamelCase(str: string): string { | 
					
						
							|  |  |  |   var words = str.split(' '); | 
					
						
							|  |  |  |   var first = words.shift(); | 
					
						
							|  |  |  |   return first + words.map(title).join(''); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function title(str: string): string { | 
					
						
							|  |  |  |   return str[0].toUpperCase() + str.substring(1); | 
					
						
							|  |  |  | } |