2015-07-17 13:36:53 -07:00
|
|
|
import {AsyncRoute, AuxRoute, Route, Redirect, RouteDefinition} from './route_config_decorator';
|
2015-07-13 16:12:48 -07:00
|
|
|
import {ComponentDefinition} from './route_definition';
|
2015-11-06 17:34:07 -08:00
|
|
|
import {isType, Type} from 'angular2/src/facade/lang';
|
|
|
|
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
|
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 #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5352
2015-11-02 16:14:10 -08:00
|
|
|
import {RouteRegistry} from './route_registry';
|
2015-09-10 15:25:36 -07:00
|
|
|
|
2015-07-13 16:12:48 -07:00
|
|
|
|
|
|
|
/**
|
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 #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5352
2015-11-02 16:14:10 -08:00
|
|
|
* Given a JS Object that represents a route config, returns a corresponding Route, AsyncRoute,
|
|
|
|
* AuxRoute or Redirect object.
|
|
|
|
*
|
|
|
|
* Also wraps an AsyncRoute's loader function to add the loaded component's route config to the
|
|
|
|
* `RouteRegistry`.
|
2015-07-13 16:12:48 -07:00
|
|
|
*/
|
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 #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5352
2015-11-02 16:14:10 -08:00
|
|
|
export function normalizeRouteConfig(config: RouteDefinition,
|
|
|
|
registry: RouteRegistry): RouteDefinition {
|
|
|
|
if (config instanceof AsyncRoute) {
|
|
|
|
var wrappedLoader = wrapLoaderToReconfigureRegistry(config.loader, registry);
|
|
|
|
return new AsyncRoute({
|
|
|
|
path: config.path,
|
|
|
|
loader: wrappedLoader,
|
|
|
|
name: config.name,
|
|
|
|
data: config.data,
|
|
|
|
useAsDefault: config.useAsDefault
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (config instanceof Route || config instanceof Redirect || config instanceof AuxRoute) {
|
2015-07-13 16:12:48 -07:00
|
|
|
return <RouteDefinition>config;
|
|
|
|
}
|
|
|
|
|
2015-10-08 12:27:55 -07:00
|
|
|
if ((+!!config.component) + (+!!config.redirectTo) + (+!!config.loader) != 1) {
|
2015-07-13 16:12:48 -07:00
|
|
|
throw new BaseException(
|
2015-07-17 13:36:53 -07:00
|
|
|
`Route config should contain exactly one "component", "loader", or "redirectTo" property.`);
|
2015-07-13 16:12:48 -07:00
|
|
|
}
|
2015-10-25 15:00:27 +05:30
|
|
|
if (config.as && config.name) {
|
|
|
|
throw new BaseException(`Route config should contain exactly one "as" or "name" property.`);
|
|
|
|
}
|
|
|
|
if (config.as) {
|
|
|
|
config.name = config.as;
|
|
|
|
}
|
2015-10-08 12:27:55 -07:00
|
|
|
if (config.loader) {
|
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 #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5352
2015-11-02 16:14:10 -08:00
|
|
|
var wrappedLoader = wrapLoaderToReconfigureRegistry(config.loader, registry);
|
|
|
|
return new AsyncRoute({
|
|
|
|
path: config.path,
|
|
|
|
loader: wrappedLoader,
|
|
|
|
name: config.name,
|
|
|
|
useAsDefault: config.useAsDefault
|
|
|
|
});
|
2015-10-08 12:27:55 -07:00
|
|
|
}
|
2015-10-30 17:05:30 -07:00
|
|
|
if (config.aux) {
|
|
|
|
return new AuxRoute({path: config.aux, component:<Type>config.component, name: config.name});
|
|
|
|
}
|
2015-07-13 16:12:48 -07:00
|
|
|
if (config.component) {
|
|
|
|
if (typeof config.component == 'object') {
|
|
|
|
let componentDefinitionObject = <ComponentDefinition>config.component;
|
|
|
|
if (componentDefinitionObject.type == 'constructor') {
|
|
|
|
return new Route({
|
|
|
|
path: config.path,
|
|
|
|
component:<Type>componentDefinitionObject.constructor,
|
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 #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5352
2015-11-02 16:14:10 -08:00
|
|
|
name: config.name,
|
|
|
|
data: config.data,
|
|
|
|
useAsDefault: config.useAsDefault
|
2015-07-13 16:12:48 -07:00
|
|
|
});
|
|
|
|
} else if (componentDefinitionObject.type == 'loader') {
|
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 #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5352
2015-11-02 16:14:10 -08:00
|
|
|
return new AsyncRoute({
|
|
|
|
path: config.path,
|
|
|
|
loader: componentDefinitionObject.loader,
|
|
|
|
name: config.name,
|
|
|
|
useAsDefault: config.useAsDefault
|
|
|
|
});
|
2015-07-13 16:12:48 -07:00
|
|
|
} else {
|
|
|
|
throw new BaseException(
|
2015-07-17 13:36:53 -07:00
|
|
|
`Invalid component type "${componentDefinitionObject.type}". Valid types are "constructor" and "loader".`);
|
2015-07-13 16:12:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return new Route(<{
|
|
|
|
path: string;
|
|
|
|
component: Type;
|
2015-10-25 15:00:27 +05:30
|
|
|
name?: string;
|
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 #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5352
2015-11-02 16:14:10 -08:00
|
|
|
data?: {[key: string]: any};
|
|
|
|
useAsDefault?: boolean;
|
2015-07-13 16:12:48 -07:00
|
|
|
}>config);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config.redirectTo) {
|
|
|
|
return new Redirect({path: config.path, redirectTo: config.redirectTo});
|
|
|
|
}
|
|
|
|
|
|
|
|
return config;
|
|
|
|
}
|
2015-09-18 15:41:02 -07:00
|
|
|
|
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 #4170
Closes #4490
Closes #4694
Closes #5200
Closes #5352
2015-11-02 16:14:10 -08:00
|
|
|
|
|
|
|
function wrapLoaderToReconfigureRegistry(loader: Function, registry: RouteRegistry): Function {
|
|
|
|
return () => {
|
|
|
|
return loader().then((componentType) => {
|
|
|
|
registry.configFromComponent(componentType);
|
|
|
|
return componentType;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-09-18 15:41:02 -07:00
|
|
|
export function assertComponentExists(component: Type, path: string): void {
|
|
|
|
if (!isType(component)) {
|
|
|
|
throw new BaseException(`Component for route "${path}" is not defined, or is not a class.`);
|
|
|
|
}
|
|
|
|
}
|