import type { ElementChild, ElementSpec } from "#types/element.types"; import { HOME_PATH, pageFromPath, pagePath } from "#assets/link.assets"; import { ANCHOR_PREFIX } from "#configuration/constants/document.constants"; import { HOME_PAGE } from "#core/ids/page.ids"; import { ROUTE_REQUESTED } from "#core/ids/route.ids"; import { createElement } from "#core/factories/element.factory"; import { emitEvent } from "#core/buses/base.bus"; import { scrollToId } from "#presentation/components/tab.component"; const specOf = function specOf( className: string, children: readonly ElementChild[], attributes: Readonly>, ): ElementSpec { return className.length === 0 ? { attributes, children } : { attributes, children, className }; }; const jumpTo = function jumpTo(href: string, targetId: string): void { window.history.replaceState({}, "", href); scrollToId(targetId); }; const anchorOf = function anchorOf(href: string): { readonly path: string; readonly target: string | null } { const cut = href.indexOf(ANCHOR_PREFIX); return cut === -1 ? { path: href, target: null } : { path: href.slice(0, cut), target: href.slice(cut + ANCHOR_PREFIX.length) }; }; export const createPageLink = function createPageLink( page: string, className: string, children: readonly ElementChild[], path = pagePath(page), ): HTMLAnchorElement { const link = createElement("a", specOf(className, children, { href: path })); const anchor = anchorOf(path); link.addEventListener("click", (event) => { event.preventDefault(); if (anchor.target !== null && anchor.path === window.location.pathname) { jumpTo(path, anchor.target); return; } emitEvent({ name: ROUTE_REQUESTED, page, path }); }); return link; }; const createAnchorLink = function createAnchorLink( targetId: string, className: string, children: readonly ElementChild[], ): HTMLAnchorElement { const href = ANCHOR_PREFIX + targetId; const link = createElement("a", specOf(className, children, { href })); link.addEventListener("click", (event) => { event.preventDefault(); jumpTo(href, targetId); }); return link; }; export const createExternalLink = function createExternalLink( href: string, className: string, children: readonly ElementChild[], ): HTMLAnchorElement { return createElement("a", specOf(className, children, { href, rel: "noopener noreferrer", target: "_blank" })); }; export const createLink = function createLink( href: string, className: string, children: readonly ElementChild[], ): HTMLAnchorElement { if (href.startsWith(ANCHOR_PREFIX)) { return createAnchorLink(href.slice(ANCHOR_PREFIX.length), className, children); } if (!href.startsWith(HOME_PATH)) { return createExternalLink(href, className, children); } return createPageLink(pageFromPath(href, HOME_PAGE), className, children, href); };