feat(router): adds redirectTo

This commit is contained in:
Manu Mtz.-Almeida
2018-03-09 23:27:55 +01:00
parent 88f2981044
commit f5c6333417
7 changed files with 75 additions and 15 deletions

View File

@@ -2604,6 +2604,7 @@ declare global {
component?: string;
params?: {[key: string]: any};
path?: string;
redirectTo?: string;
}
}
}

View File

@@ -22,6 +22,11 @@ string
string
#### redirectTo
string
## Attributes
#### component
@@ -39,6 +44,11 @@ string
string
#### redirect-to
string
----------------------------------------------

View File

@@ -7,5 +7,6 @@ import { Component, Prop } from '@stencil/core';
export class Route {
@Prop() path = '';
@Prop() component: string;
@Prop() redirectTo: string;
@Prop() params: {[key: string]: any};
}

View File

@@ -1,10 +1,10 @@
import { Build, Component, Element, Listen, Method, Prop } from '@stencil/core';
import { Config, DomController } from '../../index';
import { flattenRouterTree, readRoutes } from './utils/parser';
import { flattenRouterTree, readRoutes, readRedirects } from './utils/parser';
import { readNavState, writeNavState } from './utils/dom';
import { chainToPath, generatePath, parsePath, readPath, writePath } from './utils/path';
import { RouteChain } from './utils/interfaces';
import { routerIDsToChain, routerPathToChain } from './utils/matching';
import { RouteChain, RouteRedirect } from './utils/interfaces';
import { routerIDsToChain, routerPathToChain, routeRedirect } from './utils/matching';
@Component({
@@ -13,6 +13,7 @@ import { routerIDsToChain, routerPathToChain } from './utils/matching';
export class Router {
private routes: RouteChain[];
private redirects: RouteRedirect[];
private busy = false;
private state = 0;
@@ -28,6 +29,7 @@ export class Router {
// read config
const tree = readRoutes(this.el);
this.routes = flattenRouterTree(tree);
this.redirects = readRedirects(this.el);
if (Build.isDev) {
console.debug('%c[@ionic/core]', 'font-weight: bold', `ion-router registered ${this.routes.length} routes`);
@@ -42,7 +44,7 @@ export class Router {
// perform first write
this.dom.raf(() => {
console.debug('[OUT] page load -> write nav state');
this.writeNavStateRoot();
this.onPopState();
});
}
@@ -52,7 +54,7 @@ export class Router {
this.state++;
window.history.replaceState(this.state, document.title, document.location.href);
}
this.writeNavStateRoot();
this.writeNavStateRoot(this.readPath());
}
@Method()
@@ -80,21 +82,23 @@ export class Router {
@Method()
push(url: string, backDirection = false) {
this.writePath(parsePath(url), backDirection);
return this.writeNavStateRoot();
const path = parsePath(url);
this.writePath(path, backDirection);
return this.writeNavStateRoot(path);
}
private writeNavStateRoot(): Promise<any> {
private writeNavStateRoot(path: string[]): Promise<any> {
if (this.busy) {
return Promise.resolve();
}
const currentPath = this.readPath();
if (!currentPath) {
return Promise.resolve();
const redirect = routeRedirect(path, this.redirects);
if (redirect) {
this.writePath(redirect.to, true);
path = redirect.to;
}
const direction = window.history.state >= this.state ? 1 : -1;
const node = document.querySelector('ion-app');
const chain = routerPathToChain(currentPath, this.routes);
const chain = routerPathToChain(path, this.routes);
return this.writeNavState(node, chain, direction);
}

View File

@@ -6,6 +6,11 @@ export interface NavOutlet {
getContainerEl(): HTMLElement | null;
}
export interface RouteRedirect {
path: string[];
to: string[];
}
export interface RouteWrite {
changed: boolean;
markVisible?: () => void|Promise<void>;

View File

@@ -1,4 +1,29 @@
import { RouteChain, RouteID } from './interfaces';
import { RouteChain, RouteID, RouteRedirect } from './interfaces';
export function matchesRedirect(input: string[], route: RouteRedirect): boolean {
const {path} = route;
if (path.length !== input.length) {
return false;
}
for (let i = 0; i < path.length; i++) {
if (path[i] !== input[i]) {
return false;
}
}
return true;
}
export function routeRedirect(path: string[], routes: RouteRedirect[]): RouteRedirect|null {
for (const route of routes) {
if (matchesRedirect(path, route)) {
return route;
}
}
return null;
}
export function matchesIDs(ids: string[], chain: RouteChain): number {
const len = Math.min(ids.length, chain.length);

View File

@@ -1,10 +1,24 @@
import { RouteChain, RouteNode, RouteTree } from './interfaces';
import { RouteChain, RouteNode, RouteRedirect, RouteTree } from './interfaces';
import { parsePath } from './path';
export function readRedirects(root: Element): RouteRedirect[] {
return (Array.from(root.children) as HTMLIonRouteElement[])
.filter(el => el.tagName === 'ION-ROUTE' && el.redirectTo)
.map(el => {
if (el.component) {
throw new Error('Can\'t mix the component and redirectTo attribute in the same ion-route');
}
return {
path: parsePath(readProp(el, 'path')),
to: parsePath(readProp(el, 'redirectTo'))
};
});
}
export function readRoutes(root: Element): RouteTree {
return (Array.from(root.children) as HTMLIonRouteElement[])
.filter(el => el.tagName === 'ION-ROUTE')
.filter(el => el.tagName === 'ION-ROUTE' && el.component)
.map(el => {
const path = parsePath(readProp(el, 'path'));
if (path.includes(':id')) {