fix(router): route information is stateless

This commit is contained in:
Manu Mtz.-Almeida
2018-05-08 21:48:04 +02:00
parent ba551fda01
commit 0f8477dc34
4 changed files with 28 additions and 37 deletions

View File

@ -3,9 +3,9 @@ import { Config, QueueController } from '../../interface';
import { debounce } from '../../utils/helpers';
import { printRedirects, printRoutes } from './utils/debug';
import { readNavState, waitUntilNavNode, writeNavState } from './utils/dom';
import { RouteChain, RouteRedirect, RouterDirection, RouterEventDetail } from './utils/interface';
import { RouteChain, RouterDirection, RouterEventDetail } from './utils/interface';
import { routeRedirect, routerIDsToChain, routerPathToChain } from './utils/matching';
import { flattenRouterTree, readRedirects, readRoutes } from './utils/parser';
import { readRedirects, readRoutes } from './utils/parser';
import { chainToPath, generatePath, parsePath, readPath, writePath } from './utils/path';
@ -14,9 +14,7 @@ import { chainToPath, generatePath, parsePath, readPath, writePath } from './uti
})
export class Router {
private routes: RouteChain[] = [];
private previousPath: string|null = null;
private redirects: RouteRedirect[] = [];
private busy = false;
private state = 0;
private lastState = 0;
@ -59,17 +57,11 @@ export class Router {
await waitUntilNavNode(this.win);
console.debug('[ion-router] found nav');
const tree = readRoutes(this.el);
this.routes = flattenRouterTree(tree);
this.redirects = readRedirects(this.el);
await this.onRoutesChanged();
this.win.addEventListener('ionRouteRedirectChanged', debounce(this.onRedirectChanged.bind(this), 10));
this.win.addEventListener('ionRouteDataChanged', debounce(this.onRoutesChanged.bind(this), 100));
const changed = await this.writeNavStateRoot(this.getPath(), RouterDirection.None);
if (!changed) {
console.error('[ion-router] did not change on will load');
}
this.onRedirectChanged();
}
@Listen('window:popstate')
@ -81,17 +73,14 @@ export class Router {
}
private onRedirectChanged() {
this.redirects = readRedirects(this.el);
const path = this.getPath();
if (path && routeRedirect(path, this.redirects)) {
if (path && routeRedirect(path, readRedirects(this.el))) {
this.writeNavStateRoot(path, RouterDirection.None);
}
}
private onRoutesChanged() {
const tree = readRoutes(this.el);
this.routes = flattenRouterTree(tree);
this.writeNavStateRoot(this.getPath(), RouterDirection.None);
return this.writeNavStateRoot(this.getPath(), RouterDirection.None);
}
private historyDirection() {
@ -117,8 +106,8 @@ export class Router {
printDebug() {
console.debug('CURRENT PATH', this.getPath());
console.debug('PREVIOUS PATH', this.previousPath);
printRoutes(this.routes);
printRedirects(this.redirects);
printRoutes(readRoutes(this.el));
printRedirects(readRedirects(this.el));
}
@Method()
@ -127,7 +116,8 @@ export class Router {
return false;
}
const { ids, outlet } = readNavState(this.win.document.body);
const chain = routerIDsToChain(ids, this.routes);
const routes = readRoutes(this.el);
const chain = routerIDsToChain(ids, routes);
if (!chain) {
console.warn('[ion-router] no matching URL for ', ids.map(i => i.id));
return false;
@ -149,9 +139,9 @@ export class Router {
@Method()
push(url: string, direction = RouterDirection.Forward) {
const path = parsePath(url);
this.setPath(path, direction);
console.debug('[ion-router] URL pushed -> updating nav', url, direction);
this.setPath(path, direction);
return this.writeNavStateRoot(path, direction);
}
@ -165,16 +155,18 @@ export class Router {
}
// lookup redirect rule
const redirect = routeRedirect(path, this.redirects);
const redirects = readRedirects(this.el);
const redirect = routeRedirect(path, redirects);
let redirectFrom: string[]|null = null;
if (redirect) {
this.setPath(redirect.to!, direction);
this.setPath(redirect.to, direction);
redirectFrom = redirect.from;
path = redirect.to!;
path = redirect.to;
}
// lookup route chain
const chain = routerPathToChain(path, this.routes);
const routes = readRoutes(this.el);
const chain = routerPathToChain(path, routes);
if (!chain) {
console.error('[ion-router] the path does not match any route');
return false;

View File

@ -19,7 +19,7 @@ export const enum RouterDirection {
export interface RouteRedirect {
from: string[];
to: string[]|undefined;
to?: string[];
}
export interface RouteWrite {

View File

@ -1,7 +1,7 @@
import { RouteChain, RouteID, RouteRedirect } from './interface';
export function matchesRedirect(input: string[], route: RouteRedirect): boolean {
export function matchesRedirect(input: string[], route: RouteRedirect): route is Required<RouteRedirect> {
const {from, to} = route;
if (to === undefined) {
return false;
@ -23,13 +23,8 @@ export function matchesRedirect(input: string[], route: RouteRedirect): boolean
return from.length === input.length;
}
export function routeRedirect(path: string[], routes: RouteRedirect[]): RouteRedirect|null {
for (const route of routes) {
if (matchesRedirect(path, route)) {
return route;
}
}
return null;
export function routeRedirect(path: string[], routes: RouteRedirect[]) {
return routes.find(route => matchesRedirect(path, route)) as Required<RouteRedirect> | undefined;
}

View File

@ -14,7 +14,11 @@ export function readRedirects(root: Element): RouteRedirect[] {
});
}
export function readRoutes(root: Element, node = root): RouteTree {
export function readRoutes(root: Element): RouteChain[] {
return flattenRouterTree(readRouteNodes(root));
}
export function readRouteNodes(root: Element, node = root): RouteTree {
return (Array.from(node.children) as HTMLIonRouteElement[])
.filter(el => el.tagName === 'ION-ROUTE' && el.component)
.map(el => {
@ -26,7 +30,7 @@ export function readRoutes(root: Element, node = root): RouteTree {
path: parsePath(readProp(el, 'url')),
id: component.toLowerCase(),
params: el.componentProps,
children: readRoutes(root, el)
children: readRouteNodes(root, el)
};
});
}