Skip to content

Commit

Permalink
feat(router): adds redirectTo
Browse files Browse the repository at this point in the history
  • Loading branch information
manucorporat committed Mar 9, 2018
1 parent 88f2981 commit f5c6333
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 15 deletions.
1 change: 1 addition & 0 deletions packages/core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2604,6 +2604,7 @@ declare global {
component?: string;
params?: {[key: string]: any};
path?: string;
redirectTo?: string;
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions packages/core/src/components/route/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ string
string


#### redirectTo

string


## Attributes

#### component
Expand All @@ -39,6 +44,11 @@ string
string


#### redirect-to

string



----------------------------------------------

Expand Down
1 change: 1 addition & 0 deletions packages/core/src/components/route/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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};
}
28 changes: 16 additions & 12 deletions packages/core/src/components/router/router.tsx
Original file line number Diff line number Diff line change
@@ -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({
Expand All @@ -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;

Expand All @@ -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`);
Expand All @@ -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();
});
}

Expand All @@ -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()
Expand Down Expand Up @@ -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);
}

Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/components/router/utils/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down
27 changes: 26 additions & 1 deletion packages/core/src/components/router/utils/matching.ts
Original file line number Diff line number Diff line change
@@ -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);
Expand Down
18 changes: 16 additions & 2 deletions packages/core/src/components/router/utils/parser.ts
Original file line number Diff line number Diff line change
@@ -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')) {
Expand Down

0 comments on commit f5c6333

Please sign in to comment.