import * as plugins from './smartrouter.plugins'; const routeLog = (message) => { console.log(`%c[Router]%c ${message}`, 'color: rgb(255, 105, 100);', 'color: inherit'); }; export interface IRouterOptions { debug?: boolean; } export type THandlerFunction = (routeArg: IRouteInfo) => Promise; export interface IRouteInfo { path: string; index: number; params: { [key: string]: string }; } /** * Router */ export class SmartRouter { public options: IRouterOptions = { debug: false, }; /** * the routes we are handling */ public routes: Array<{ matchFunction: plugins.pathToRegExp.MatchFunction; handler: THandlerFunction; }> = []; /** * Creates an instance of Router. */ constructor(optionsArg: IRouterOptions) { // lets set the router options this.options = { ...this.options, ...optionsArg, }; // lets subscribe to route changes window.addEventListener('popstate', (popStateEventArg) => { popStateEventArg.preventDefault(); this._handleRouteState(); }); window.addEventListener('DOMContentLoaded', () => { this._handleRouteState(); }); } /** * Push route state to history stack */ public async pushUrl(url: string = '/', state: any = {}) { if (url !== window.location.pathname) { window.history.pushState(state, window.document.title, url); } else { window.history.replaceState(state, window.document.title, url); } await this._handleRouteState(); } /** * Attach route with handler * @param {string|RegExp} routeArg * @param {function} handlerArg */ public on(routeArg: string, handlerArg: THandlerFunction) { this.routes.push({ matchFunction: plugins.pathToRegExp.match(routeArg), handler: handlerArg, }); } /** * Apply routes handler to current route */ async _handleRouteState() { const currentLocation = window.location.pathname; const wantedRoutes = this.routes.filter((routeArg) => { return !!routeArg.matchFunction(currentLocation); }); for (const wantedRoute of wantedRoutes) { const routeResult = wantedRoute.matchFunction(currentLocation); wantedRoute.handler(routeResult.valueOf() as IRouteInfo); // not waiting here } } }