From 0f8477dc34a89e2394331a26babc712361501b34 Mon Sep 17 00:00:00 2001 From: "Manu Mtz.-Almeida" Date: Tue, 8 May 2018 21:48:04 +0200 Subject: [PATCH] fix(router): route information is stateless --- core/src/components/router/router.tsx | 44 ++++++++----------- core/src/components/router/utils/interface.ts | 2 +- core/src/components/router/utils/matching.ts | 11 ++--- core/src/components/router/utils/parser.ts | 8 +++- 4 files changed, 28 insertions(+), 37 deletions(-) diff --git a/core/src/components/router/router.tsx b/core/src/components/router/router.tsx index 98ff156742..c163f0382d 100644 --- a/core/src/components/router/router.tsx +++ b/core/src/components/router/router.tsx @@ -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; diff --git a/core/src/components/router/utils/interface.ts b/core/src/components/router/utils/interface.ts index 00f74de47b..21f51f82f3 100644 --- a/core/src/components/router/utils/interface.ts +++ b/core/src/components/router/utils/interface.ts @@ -19,7 +19,7 @@ export const enum RouterDirection { export interface RouteRedirect { from: string[]; - to: string[]|undefined; + to?: string[]; } export interface RouteWrite { diff --git a/core/src/components/router/utils/matching.ts b/core/src/components/router/utils/matching.ts index 34b1ece5df..94fc3cd24c 100644 --- a/core/src/components/router/utils/matching.ts +++ b/core/src/components/router/utils/matching.ts @@ -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 { 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 | undefined; } diff --git a/core/src/components/router/utils/parser.ts b/core/src/components/router/utils/parser.ts index f8a8c74002..ce311b9c41 100644 --- a/core/src/components/router/utils/parser.ts +++ b/core/src/components/router/utils/parser.ts @@ -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) }; }); }