This repository has been archived on 2024-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
authentik/web/src/elements/router/RouterOutlet.ts
Jens Langhammer 2c4239d79a web: allow for non-path elements in hash, store current tab page in hash
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
2021-04-04 23:19:08 +02:00

112 lines
3.8 KiB
TypeScript

import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
import { Route } from "./Route";
import { ROUTES } from "../../routes";
import { RouteMatch } from "./RouteMatch";
import AKGlobal from "../../authentik.css";
import "./Router404";
import { Page } from "../Page";
import { ROUTE_SEPARATOR, TITLE_SUFFIX } from "../../constants";
// Poliyfill for hashchange.newURL,
// https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onhashchange
window.addEventListener("load", () => {
if (!window.HashChangeEvent) (function () {
let lastURL = document.URL;
window.addEventListener("hashchange", function (event) {
Object.defineProperty(event, "oldURL", { enumerable: true, configurable: true, value: lastURL });
Object.defineProperty(event, "newURL", { enumerable: true, configurable: true, value: document.URL });
lastURL = document.URL;
});
}());
});
@customElement("ak-router-outlet")
export class RouterOutlet extends LitElement {
@property({attribute: false})
current?: RouteMatch;
@property()
defaultUrl?: string;
static get styles(): CSSResult[] {
return [AKGlobal,
css`
:host {
height: 100vh;
background-color: var(--ak-dark-background, var(--pf-c-page--BackgroundColor)) !important;
}
*:first-child {
height: 100%;
display: flex;
flex-direction: column;
}
`,
];
}
constructor() {
super();
window.addEventListener("hashchange", (ev: HashChangeEvent) => this.navigate(ev));
}
firstUpdated(): void {
this.navigate();
}
updated(): void {
if (!this.shadowRoot) return;
Array.from(this.shadowRoot?.children).forEach((el) => {
if ("pageTitle" in el) {
const title = (el as Page).pageTitle();
document.title = `${title} - ${TITLE_SUFFIX}`;
} else {
document.title = TITLE_SUFFIX;
}
});
}
navigate(ev?: HashChangeEvent): void {
let activeUrl = window.location.hash.slice(1, Infinity).split(ROUTE_SEPARATOR)[0];
if (ev) {
// Check if we've actually changed paths
const oldPath = new URL(ev.oldURL).hash.slice(1, Infinity).split(ROUTE_SEPARATOR)[0];
if (oldPath === activeUrl) return;
}
if (activeUrl === "") {
activeUrl = this.defaultUrl || "/";
window.location.hash = `#${activeUrl}`;
console.debug(`authentik/router: defaulted URL to ${window.location.hash}`);
return;
}
let matchedRoute: RouteMatch | null = null;
ROUTES.some((route) => {
const match = route.url.exec(activeUrl);
if (match != null) {
matchedRoute = new RouteMatch(route);
matchedRoute.arguments = match.groups || {};
matchedRoute.fullUrl = activeUrl;
console.debug("authentik/router: found match ", matchedRoute);
return true;
}
});
if (!matchedRoute) {
console.debug(`authentik/router: route "${activeUrl}" not defined`);
const route = new Route(
RegExp(""),
html`<div class="pf-c-page__main">
<ak-router-404 url=${activeUrl}></ak-router-404>
</div>`
);
matchedRoute = new RouteMatch(route);
matchedRoute.arguments = route.url.exec(activeUrl)?.groups || {};
matchedRoute.fullUrl = activeUrl;
}
this.current = matchedRoute;
}
render(): TemplateResult | undefined {
return this.current?.render();
}
}