| undefined;
};
@customElement(tagName)
export class SonicRouter extends TemplatesContainer(LitElement) {
templateValueAttribute = "data-route";
@property({ type: String }) fallBackRoute?: string;
@property({ type: Object }) routes?: RoutesToRenderer;
@property({ type: String }) basePath?: string;
protected createRenderRoot(): HTMLElement | DocumentFragment {
return this;
}
connectedCallback() {
LocationHandler.onChange(this);
super.connectedCallback();
}
disconnectedCallback(): void {
LocationHandler.offChange(this);
super.disconnectedCallback();
}
private _location: string = document.location.href.replace(
document.location.origin,
""
);
@property() set location(value: string) {
this._location = value;
//keep only the path abnd the has
this.requestUpdate();
}
get location() {
return this._location;
}
get cleanLocation() {
const url = new URL(this.location, document.location.origin);
return url.pathname + url.hash;
}
private get patternBasePath() {
if (this.basePath !== undefined) {
return this.basePath;
}
return "(/)*";
}
private get regExpBasePath() {
if (this.basePath !== undefined) {
return "^" + this.basePath;
}
return "";
}
private handleroutes(): DirectiveResult[] {
if (!this.routes) return [];
const templates: DirectiveResult[] = [];
for (let [path, renderFn] of Object.entries(this.routes)) {
if (path === "fallback" || !renderFn) continue;
const regexp = new RegExp(this.regExpBasePath + path);
if (regexp.test(this.cleanLocation)) {
const params = regexp.exec(this.cleanLocation) || [path];
params.shift();
templates.push(renderFn([...params]));
} else {
try {
const pattern = new UrlPattern(this.patternBasePath + path);
const match = pattern.match(this.cleanLocation);
if (match) {
const params = match || {};
templates.push(renderFn(params));
}
} catch (e) {
if (
this.cleanLocation.indexOf(
(this.basePath || "") + path.replace(document.location.origin, "")
) != -1
) {
templates.push(renderFn({}));
}
}
}
}
//Gestion fallback
if (templates.length == 0) {
if (this.routes?.fallback && this.isConnected) {
templates.push(this.routes.fallback());
}
}
return templates;
}
render() {
const programmaticTemplates = this.handleroutes();
if (programmaticTemplates.length > 0) {
return html`${programmaticTemplates}`;
}
const templates = [];
for (const t of this.templatePartsList) {
const path = t.getAttribute(this.templateValueAttribute) || "";
const regexp = new RegExp(this.regExpBasePath + path);
if (regexp.test(this.cleanLocation)) {
templates.push(t);
} else {
try {
if (
new UrlPattern(this.patternBasePath + path + "(/*)").match(
this.cleanLocation
)
) {
t.setAttribute("mode", "patternMatching");
templates.push(t);
}
} catch (e) {
if (
this.cleanLocation.indexOf(
(this.basePath || "") + path.replace(document.location.origin, "")
) != -1
) {
templates.push(t);
}
}
}
}
if (templates.length == 0) {
if (this.fallBackRoute && this.isConnected) {
document.location.href = this.fallBackRoute;
}
const fallback = this.templateList.find((t) =>
t.hasAttribute("data-fallback")
);
if (fallback) {
templates.push(fallback);
}
}
return html`${repeat(
templates,
(template, index) => {
template;
return index + new Date().getTime();
},
(template) => {
if (template.title) document.title = template.title;
if (template.hasAttribute("dataProviderExpression")) {
let dataProvider = "";
const dataProviderExpression =
template.getAttribute("dataProviderExpression") || "";
if (template.getAttribute("mode") == "patternMatching") {
const matcher = new UrlPattern(
"(/)*" +
(template.getAttribute(this.templateValueAttribute) || "") +
"*"
);
const filler = new UrlPattern(dataProviderExpression);
dataProvider = filler.stringify(matcher.match(this.cleanLocation));
} else {
const regexp = new RegExp(
template.getAttribute(this.templateValueAttribute) || ""
);
const match = (this.cleanLocation + "").match(regexp);
if (match) {
dataProvider =
match.shift()?.replace(regexp, dataProviderExpression) || "";
}
}
return html`
${templateContent(template)}
`;
}
return templateContent(template);
}
)}`;
}
}