Files
2015-07-17 10:37:22 -05:00

236 lines
6.0 KiB
TypeScript

import {RegExpWrapper} from 'angular2/src/facade/lang';
import * as util from '../util/util';
import {PathRecognizer} from './path-recognizer';
export class IonicRouter {
constructor(config) {
this._routes = [];
this._viewCtrls = [];
this.config(config);
}
app(app) {
this.app = app;
}
config(config) {
if (config) {
for (let i = 0; i < config.length; i++) {
this.addRoute(config[i]);
}
}
}
addRoute(routeConfig) {
if (routeConfig && routeConfig.path && routeConfig.component) {
let route = new Route(routeConfig);
if (routeConfig.root) {
this.otherwise(route);
}
this._routes.push(route);
}
}
stateChange(type, activeView) {
// this fires when the app's state has changed. `stateChange` will
// tell each of the state managers that the state has changed, and
// each state manager will decide what to do with this info
// (the url state manager updates the url bar if a route was setup)
if (activeView && activeView.component) {
let componentRoute = activeView.component.route;
if (componentRoute) {
let path = componentRoute.generate(activeView.params);
if (path) {
for (let name in stateManagers) {
stateManagers[name].stateChange(path, type, activeView);
}
}
}
}
}
stateClear() {
for (let name in stateManagers) {
stateManagers[name].stateClear();
}
}
matchPaths(paths) {
// load each of paths to a component
let components = [];
let route;
if (paths) {
for (let i = 0; i < paths.length; i++) {
route = this.matchPath(paths[i]);
if (route && route.component) {
components.push(route.component);
}
}
}
return components;
}
matchPath(path) {
// takes a string path and loops through each of the setup
// routes to see if the path matches any of the routes
// the matched path with the highest specifity wins
let matchedRoute = null;
let route = null;
let routeMatch = null;
for (let i = 0; i < this._routes.length; i++) {
route = this._routes[i];
routeMatch = route.match(path);
if (routeMatch && (!matchedRoute || route.specificity > matchedRoute.specificity)) {
matchedRoute = route;
}
}
return matchedRoute;
}
load(window, ionicApp, ionicConfig) {
// load is called when the app has finished loading each state
// manager gets a chance to say what path the app should be at
let viewCtrl = this.viewController();
if (!viewCtrl || !this._routes.length) {
return Promise.resolve();
}
let resolve;
let promise = new Promise(res => { resolve = res; });
// get the initial load paths from the state manager with the highest priorty
this.getManagerPaths(window, ionicApp, ionicConfig).then(paths => {
// load all of the paths the highest priority state manager has given
let components = this.matchPaths(paths);
if (!components.length && this.otherwise()) {
// the state manager did not find and loaded components
// use the "otherwise" path
components = [this.otherwise().component];
}
this.app.zoneRun(() => {
viewCtrl.setItems(components).then(resolve);
});
});
return promise;
}
getManagerPaths(window, ionicApp, ionicConfig) {
// loop through all of the state managers and load their paths
// the state manager with valid paths and highest priority wins
let resolve;
let promise = new Promise(res => { resolve = res; });
// load each of the state managers
let stateManagerPromises = [];
for (let name in stateManagerClasses) {
stateManagers[name] = new stateManagerClasses[name](window, this, ionicApp, ionicConfig);
stateManagerPromises.push( stateManagers[name].load() );
}
// when all the state manager loads have resolved then see which one wins
Promise.all(stateManagerPromises).then(stateManagerLoadResults => {
// now that all the state managers are loaded
// get the highest priority state manager's paths
let stateLoadResult = null;
let paths = null;
let highestPriority = -1;
for (let i = 0; i < stateManagerLoadResults.length; i++) {
stateLoadResult = stateManagerLoadResults[i];
if (stateLoadResult && stateLoadResult.paths.length && stateLoadResult.priority > highestPriority) {
paths = stateLoadResult.paths;
highestPriority = stateLoadResult.priority;
}
}
resolve(paths);
});
return promise;
}
push(path) {
let viewCtrl = this.viewController();
if (viewCtrl) {
let matchedRoute = this.matchPath(path);
if (matchedRoute && matchedRoute.component) {
this.app.zoneRun(() => {
viewCtrl.push(matchedRoute.component, matchedRoute.params, {});
});
}
}
}
pop() {
let viewCtrl = this.viewController();
if (viewCtrl) {
this.app.zoneRun(() => {
viewCtrl.pop();
});
}
}
otherwise(val) {
if (arguments.length) {
this._otherwise = val;
}
return this._otherwise
}
addViewController(viewCtrl) {
this._viewCtrls.push(viewCtrl);
}
viewController() {
if (this._viewCtrls.length) {
return this._viewCtrls[ this._viewCtrls.length - 1 ];
}
}
static registerStateManager(name, StateManagerClass) {
stateManagerClasses[name] = StateManagerClass;
}
static deregisterStateManager(name) {
delete stateManagerClasses[name];
delete stateManagers[name];
}
}
let stateManagerClasses = {};
let stateManagers = {};
class Route {
constructor(routeConfig) {
util.extend(this, routeConfig);
this.recognizer = new PathRecognizer(this.path);
this.specificity = this.recognizer.specificity;
this.component.route = this;
}
match(path) {
return RegExpWrapper.firstMatch(this.recognizer.regex, path);
}
generate(params) {
return this.recognizer.generate(params);
}
}