UNPKG

@relax.dev/router

Version:
198 lines (164 loc) 4.68 kB
import { generatePath, MatchInterface, matchPath } from '../workWithPathRegexp'; import { Page } from './Page'; import { RouteList } from './Router'; import { InfinityPanelIdTitle, PageParams, RouterGenericBase } from './Types'; /** * @ignore */ export const POPUP_KEY = 'p'; /** * @ignore */ export const MODAL_KEY = 'm'; let routeUniqueId = 1; function getNextUniqId() { return routeUniqueId++; } function searchParamsToObject(searchParams: URLSearchParams): Record<string, string> { const obj: { [key: string]: string } = {}; for (const [key, value] of searchParams) { obj[key] = value; } return obj; } export class Route<T extends RouterGenericBase = RouterGenericBase> { /** * @type {Page} */ structure: Page<T>; pageId: T['pageId']; params: PageParams = {}; uniqId: number; constructor(structure: Page<T>, pageId: T['pageId'], params: PageParams) { this.structure = structure; this.pageId = pageId; this.params = params; this.uniqId = getNextUniqId(); } static getParamsFromPath<T extends RouterGenericBase = RouterGenericBase>(location: T['pageId']) { if (location.includes('?')) { const [, qs] = location.split('?', 2); return searchParamsToObject(new URLSearchParams(qs)); } else { return {}; } } /** * @param {RouteList} routeList * @param location "info?w=about&show=1" то, что лежит в window.location.hash * @param noSlash */ static fromLocation<T extends RouterGenericBase = RouterGenericBase>( routeList: RouteList<T>, location: T['pageId'], noSlash = true ) { const params = Route.getParamsFromPath(location); location = location.replace('#', ''); if (noSlash && location.length && !location.startsWith('/')) { location = `/${location}`; } if (noSlash && !location.length) { location = '/'; } location = location.split('?', 2).shift() || (noSlash ? '/' : ''); let match: null | MatchInterface = null; for (let pageId in routeList) { if (routeList.hasOwnProperty(pageId)) { match = matchPath(location, pageId); if (match && match.isExact) { break; } } } if (!match) { throw new Error('ROUTE_NOT_FOUND'); } const ps = routeList[match.path as T['pageId']]; if (!ps) { throw new Error(`Router fail: cant find structure in routes for ${location}`); } return new Route<T>(ps, match.path, { ...params, ...match.params, }); } static fromPageId<T extends RouterGenericBase = RouterGenericBase>( routeList: RouteList<T>, pageId: T['pageId'], params: PageParams, prevViewId: T['viewId'] ) { const ps = routeList[pageId]; if (!ps) { throw new Error(`Router fail: cant find structure in routes for ${pageId}`); } const { additionalViews } = ps; const actualViewId = additionalViews.includes(prevViewId) ? prevViewId : ps.viewId; ps.viewId = actualViewId; return new Route(ps, pageId, params || {}); } clone(): Route<T> { const copy = new Route<T>(this.structure.clone(), this.pageId, { ...this.params }); copy.uniqId = this.uniqId; return copy; } get location() { const path = generatePath<T>(this.pageId, this.params); return `#${path.replace(/\//, '')}`; } getPageId(): T['pageId'] { return this.pageId; } getPanelId(): T['panelId'] | InfinityPanelIdTitle<T['panelId']> { if (this.structure.isInfinityPanel) { return `_${this.structure.panelId}..${this.uniqId}`; } return this.structure.panelId; } getPanelIdWithoutInfinity(): T['panelId'] { return this.structure.panelId; } getViewId(): T['viewId'] { return this.structure.viewId; } getRootId(): T['rootId'] { return this.structure.rootId; } getParams(): PageParams { return this.params; } setParams(params: PageParams = {}): Route<T> { this.params = { ...this.params, ...params }; return this; } isPopup(): boolean { return !!this.getPopupId(); } getPopupId(): T['popupId'] | null { return this.params[POPUP_KEY]?.toString() || null; } setPopupId(popupId: T['popupId']): Route<T> { this.params[POPUP_KEY] = popupId; return this; } isModal(): boolean { return !!this.getModalId(); } hasOverlay() { return this.isModal() || this.isPopup(); } getModalId(): T['modalId'] | null { return this.params[MODAL_KEY]?.toString() || null; } setModalId(modalId: T['modalId']): Route<T> { this.params[MODAL_KEY] = modalId; return this; } out() { // $TSFixMe } in() { // $TSFixMe } }