UNPKG

@addasoft/lit-element-router

Version:

A LitElement Router (1278 bytes gzip) that uses JavaScript Mixin, Decorators and RegExp.

255 lines (235 loc) 7.73 kB
import { parseParams, parseQuery, testRoute } from "./utility/router-utility"; export function router(base) { return class extends base { static get properties() { return { route: { type: String, reflect: true, attribute: "route" }, canceled: { type: Boolean }, }; } constructor(...args) { super(...args); this.route = ""; this.canceled = false; } connectedCallback(...args) { super.connectedCallback(...args); // @ts-ignore this.routing(this.constructor.routes, (...args) => this.router(...args)); window.addEventListener("route", () => { // @ts-ignore this.routing(this.constructor.routes, (...args) => this.router(...args) ); }); window.onpopstate = () => { window.dispatchEvent(new CustomEvent("route")); }; } routed(name, params, query, data, callback, localCallback) { localCallback && localCallback(name, params, query, data); callback(name, params, query, data); } routing(routes, callback) { this.canceled = true; // const uri = decodeURIComponent(window.location.pathname); const uri = window.location.pathname; const querystring = decodeURIComponent(window.location.search); let notFoundRoute = routes.filter((route) => route.pattern === "*")[0]; let activeRoute = routes.filter( (route) => route.pattern !== "*" && testRoute(uri, route.pattern) )[0]; let query = parseQuery(querystring); if (activeRoute) { activeRoute.params = parseParams(activeRoute.pattern, uri); activeRoute.data = activeRoute.data || {}; if ( activeRoute.authentication && activeRoute.authentication.authenticate && typeof activeRoute.authentication.authenticate === "function" ) { this.canceled = false; Promise.resolve( activeRoute.authentication.authenticate.bind(this).call() ).then((authenticated) => { if (!this.canceled) { if (authenticated) { if ( activeRoute.authorization && activeRoute.authorization.authorize && typeof activeRoute.authorization.authorize === "function" ) { this.canceled = false; Promise.resolve( activeRoute.authorization.authorize.bind(this).call() ).then((authorizatied) => { if (!this.canceled) { if (authorizatied) { this.routed( activeRoute.name, activeRoute.params, query, activeRoute.data, callback, activeRoute.callback ); } else { this.routed( activeRoute.authorization.unauthorized.name, activeRoute.params, query, activeRoute.data, callback, activeRoute.callback ); } } }); } else { this.routed( activeRoute.name, activeRoute.params, query, activeRoute.data, callback, activeRoute.callback ); } } else { this.routed( activeRoute.authentication.unauthenticated.name, activeRoute.params, query, activeRoute.data, callback, activeRoute.callback ); } } }); } else if ( activeRoute.authorization && activeRoute.authorization.authorize && typeof activeRoute.authorization.authorize === "function" ) { this.canceled = false; Promise.resolve( activeRoute.authorization.authorize.bind(this).call() ).then((authorizatied) => { if (!this.canceled) { if (authorizatied) { this.routed( activeRoute.name, activeRoute.params, query, activeRoute.data, callback, activeRoute.callback ); } else { this.routed( activeRoute.authorization.unauthorized.name, activeRoute.params, query, activeRoute.data, callback, activeRoute.callback ); } } }); } else { this.routed( activeRoute.name, activeRoute.params, query, activeRoute.data, callback, activeRoute.callback ); } } else if (notFoundRoute) { notFoundRoute.data = notFoundRoute.data || {}; this.routed( notFoundRoute.name, {}, query, notFoundRoute.data, callback, notFoundRoute.callback ); } } }; } export function navigator(base) { return class extends base { navigate(href) { window.history.pushState({}, null, href); window.dispatchEvent(new CustomEvent("route")); } }; } export function outlet(base) { return class extends base { static get properties() { return { activeRoute: { type: String, reflect: true, attribute: "active-route" }, }; } attributeChangedCallback(...args) { super.attributeChangedCallback(...args); args.some((arg) => arg === "active-route") && this.outlet(); } connectedCallback(...args) { super.connectedCallback(...args); setTimeout(() => { this.outlet(); }); } moveChildNodes(node, tagName = "template") { const template = document.createElement(tagName); for (const attr of node.attributes) { template.setAttribute(attr.name, attr.value); } while (node.childNodes.length > 0) { template.appendChild(node.childNodes[0]); } return template; } outlet() { Array.from(this.querySelectorAll(`[route]`)).map((active) => { if (active.tagName !== "TEMPLATE") { const template = this.moveChildNodes(active); active.replaceWith(template); } }); if (this.shadowRoot) { Array.from(this.shadowRoot.querySelectorAll(`[route]`)).map( (active) => { if (active.tagName !== "TEMPLATE") { const template = this.moveChildNodes(active); active.replaceWith(template); } } ); } if (this.activeRoute) { Array.from(this.querySelectorAll(`[route~=${this.activeRoute}]`)).map( (active) => { const dom = this.moveChildNodes(active, "div"); active.replaceWith(dom); } ); if (this.shadowRoot) { Array.from( this.shadowRoot.querySelectorAll(`[route~=${this.activeRoute}]`) ).map((active) => { const dom = this.moveChildNodes(active, "div"); active.replaceWith(dom); }); } } } }; }