138 lines
24 KiB
JavaScript
138 lines
24 KiB
JavaScript
|
|
import { ReflectiveInjector } from '@angular/core';
|
||
|
|
import { RouterOutletMap } from './router_outlet_map';
|
||
|
|
import { recognize } from './recognize';
|
||
|
|
import { rootNode } from './utils/tree';
|
||
|
|
import { createEmptyUrlTree } from './url_tree';
|
||
|
|
import { PRIMARY_OUTLET } from './shared';
|
||
|
|
import { createEmptyState, ActivatedRoute } from './router_state';
|
||
|
|
import { createUrlTree } from './create_url_tree';
|
||
|
|
import { forEach } from './utils/collection';
|
||
|
|
import 'rxjs/add/operator/map';
|
||
|
|
import 'rxjs/add/operator/mergeMap';
|
||
|
|
import 'rxjs/add/operator/toPromise';
|
||
|
|
import { fromPromise } from 'rxjs/observable/fromPromise';
|
||
|
|
import { forkJoin } from 'rxjs/observable/forkJoin';
|
||
|
|
export class Router {
|
||
|
|
constructor(rootComponent, resolver, urlSerializer, outletMap, location) {
|
||
|
|
this.rootComponent = rootComponent;
|
||
|
|
this.resolver = resolver;
|
||
|
|
this.urlSerializer = urlSerializer;
|
||
|
|
this.outletMap = outletMap;
|
||
|
|
this.location = location;
|
||
|
|
this.currentUrlTree = createEmptyUrlTree();
|
||
|
|
this.currentRouterState = createEmptyState(rootComponent.constructor);
|
||
|
|
this.setUpLocationChangeListener();
|
||
|
|
this.navigateByUrl(this.location.path());
|
||
|
|
}
|
||
|
|
get routerState() {
|
||
|
|
return this.currentRouterState;
|
||
|
|
}
|
||
|
|
get urlTree() {
|
||
|
|
return this.currentUrlTree;
|
||
|
|
}
|
||
|
|
navigateByUrl(url) {
|
||
|
|
const urlTree = this.urlSerializer.parse(url);
|
||
|
|
return this.runNavigate(urlTree, false);
|
||
|
|
}
|
||
|
|
resetConfig(config) {
|
||
|
|
this.config = config;
|
||
|
|
}
|
||
|
|
dispose() { this.locationSubscription.unsubscribe(); }
|
||
|
|
createUrlTree(commands, { relativeTo, queryParameters, fragment } = {}) {
|
||
|
|
const a = relativeTo ? relativeTo : this.routerState.root;
|
||
|
|
return createUrlTree(a, this.currentUrlTree, commands, queryParameters, fragment);
|
||
|
|
}
|
||
|
|
navigate(commands, extras = {}) {
|
||
|
|
return this.runNavigate(this.createUrlTree(commands, extras));
|
||
|
|
}
|
||
|
|
serializeUrl(url) { return this.urlSerializer.serialize(url); }
|
||
|
|
parseUrl(url) { return this.urlSerializer.parse(url); }
|
||
|
|
setUpLocationChangeListener() {
|
||
|
|
this.locationSubscription = this.location.subscribe((change) => {
|
||
|
|
this.runNavigate(this.urlSerializer.parse(change['url']), change['pop']);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
runNavigate(url, pop) {
|
||
|
|
const r = recognize(this.config, url, this.currentRouterState).mergeMap((newState) => {
|
||
|
|
return new ActivateRoutes(this.resolver, newState, this.currentRouterState).activate(this.outletMap).map(() => {
|
||
|
|
this.currentUrlTree = url;
|
||
|
|
this.currentRouterState = newState;
|
||
|
|
if (!pop) {
|
||
|
|
this.location.go(this.urlSerializer.serialize(url));
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
r.subscribe((a) => { }, (e) => { }, () => { });
|
||
|
|
return r;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
class ActivateRoutes {
|
||
|
|
constructor(resolver, futureState, currState) {
|
||
|
|
this.resolver = resolver;
|
||
|
|
this.futureState = futureState;
|
||
|
|
this.currState = currState;
|
||
|
|
}
|
||
|
|
activate(parentOutletMap) {
|
||
|
|
const currRoot = this.currState ? rootNode(this.currState) : null;
|
||
|
|
const futureRoot = rootNode(this.futureState);
|
||
|
|
return this.activateChildRoutes(futureRoot, currRoot, parentOutletMap);
|
||
|
|
}
|
||
|
|
activateChildRoutes(futureNode, currNode, outletMap) {
|
||
|
|
const prevChildren = nodeChildrenAsMap(currNode);
|
||
|
|
const observables = [];
|
||
|
|
futureNode.children.forEach(c => {
|
||
|
|
observables.push(this.activateRoutes(c, prevChildren[c.value.outlet], outletMap).toPromise());
|
||
|
|
delete prevChildren[c.value.outlet];
|
||
|
|
});
|
||
|
|
forEach(prevChildren, (v, k) => this.deactivateOutletAndItChildren(outletMap._outlets[k]));
|
||
|
|
return forkJoin(observables);
|
||
|
|
}
|
||
|
|
activateRoutes(futureNode, currNode, parentOutletMap) {
|
||
|
|
const future = futureNode.value;
|
||
|
|
const curr = currNode ? currNode.value : null;
|
||
|
|
const outlet = getOutlet(parentOutletMap, futureNode.value);
|
||
|
|
if (future === curr) {
|
||
|
|
return this.activateChildRoutes(futureNode, currNode, outlet.outletMap);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
this.deactivateOutletAndItChildren(outlet);
|
||
|
|
const outletMap = new RouterOutletMap();
|
||
|
|
return this.activateNewRoutes(outletMap, future, outlet).mergeMap(() => this.activateChildRoutes(futureNode, currNode, outletMap));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
activateNewRoutes(outletMap, future, outlet) {
|
||
|
|
const resolved = ReflectiveInjector.resolve([
|
||
|
|
{ provide: ActivatedRoute, useValue: future },
|
||
|
|
{ provide: RouterOutletMap, useValue: outletMap }
|
||
|
|
]);
|
||
|
|
return fromPromise(this.resolver.resolveComponent(future.component)).
|
||
|
|
map(factory => outlet.activate(factory, resolved, outletMap));
|
||
|
|
}
|
||
|
|
deactivateOutletAndItChildren(outlet) {
|
||
|
|
if (outlet && outlet.isActivated) {
|
||
|
|
forEach(outlet.outletMap._outlets, (v, k) => this.deactivateOutletAndItChildren(v));
|
||
|
|
outlet.deactivate();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function nodeChildrenAsMap(node) {
|
||
|
|
return node ?
|
||
|
|
node.children.reduce((m, c) => {
|
||
|
|
m[c.value.outlet] = c;
|
||
|
|
return m;
|
||
|
|
}, {}) :
|
||
|
|
{};
|
||
|
|
}
|
||
|
|
function getOutlet(outletMap, route) {
|
||
|
|
let outlet = outletMap._outlets[route.outlet];
|
||
|
|
if (!outlet) {
|
||
|
|
if (route.outlet === PRIMARY_OUTLET) {
|
||
|
|
throw new Error(`Cannot find primary outlet`);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
throw new Error(`Cannot find the outlet ${route.outlet}`);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return outlet;
|
||
|
|
}
|
||
|
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3JvdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiT0FBTyxFQUFxQixrQkFBa0IsRUFBRSxNQUFNLGVBQWU7T0FHOUQsRUFBRSxlQUFlLEVBQUUsTUFBTSxxQkFBcUI7T0FDOUMsRUFBRSxTQUFTLEVBQUUsTUFBTSxhQUFhO09BQ2hDLEVBQUUsUUFBUSxFQUFZLE1BQU0sY0FBYztPQUMxQyxFQUFXLGtCQUFrQixFQUFFLE1BQU0sWUFBWTtPQUNqRCxFQUFFLGNBQWMsRUFBVSxNQUFNLFVBQVU7T0FDMUMsRUFBRSxnQkFBZ0IsRUFBZSxjQUFjLEVBQUMsTUFBTSxnQkFBZ0I7T0FHdEUsRUFBRSxhQUFhLEVBQUUsTUFBTSxtQkFBbUI7T0FDMUMsRUFBRSxPQUFPLEVBQUUsTUFBTSxvQkFBb0I7T0FHckMsdUJBQXVCO09BQ3ZCLDRCQUE0QjtPQUM1Qiw2QkFBNkI7T0FDN0IsRUFBQyxXQUFXLEVBQUMsTUFBTSw2QkFBNkI7T0FDaEQsRUFBQyxRQUFRLEVBQUMsTUFBTSwwQkFBMEI7QUFPakQ7SUFTRSxZQUFvQixhQUFvQixFQUFVLFFBQTJCLEVBQVUsYUFBNEIsRUFBVSxTQUEwQixFQUFVLFFBQWtCO1FBQS9KLGtCQUFhLEdBQWIsYUFBYSxDQUFPO1FBQVUsYUFBUSxHQUFSLFFBQVEsQ0FBbUI7UUFBVSxrQkFBYSxHQUFiLGFBQWEsQ0FBZTtRQUFVLGNBQVMsR0FBVCxTQUFTLENBQWlCO1FBQVUsYUFBUSxHQUFSLFFBQVEsQ0FBVTtRQUNqTCxJQUFJLENBQUMsY0FBYyxHQUFHLGtCQUFrQixFQUFFLENBQUM7UUFDM0MsSUFBSSxDQUFDLGtCQUFrQixHQUFHLGdCQUFnQixDQUFNLGFBQWEsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUMzRSxJQUFJLENBQUMsMkJBQTJCLEVBQUUsQ0FBQztRQUNuQyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMs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
|