'use strict'; // `any`: the page reads .value, .dataset and .onclick off whatever it looks up, and the // smoke test, not the type checker, is what makes sure a selector exists. const $ = (s: string, r: ParentNode = document): T => r.querySelector(s)!; const $$ = (s: string, r: ParentNode = document): T[] => [...r.querySelectorAll(s)]; /// What went wrong, from whatever a catch caught: the page throws Errors, but a catch cannot know. const why = (e: unknown): string => e instanceof Error ? e.message : String(e); /// A row that opens a feed, a place or a show (the feed list, the Directory): a link to a screen /// reader, named by what it shows, the open one marked current. Not a button, whose contents a /// screen reader flattens, which would hide a folder's triangle inside it; as a bare div it read as /// text, nothing to press (#298). function asLink(el: HTMLElement, current: boolean){ const said=(s: string)=>el.querySelector(s)?.textContent?.trim(); const marks=$$('[role=img][aria-label],.subbed[aria-label]',el).map(m=>m.getAttribute('aria-label')); el.setAttribute('role','link'); el.setAttribute('aria-label',[said('b'),said('small'),...marks,el.querySelector('.badge:not(.zero)')?.title].filter(Boolean).join(', ')); if(current) el.setAttribute('aria-current','page'); } const ESCAPED: Record ={'&':'&','<':'<','>':'>','"':'"',"'":'''}; const esc = (s: string|null|undefined) => (s??'').replace(/[&<>"']/g,c=>ESCAPED[c]); // A feed's link, only if it is a web address: esc() keeps a javascript: or data: one working (#326). const webUrl = (u: string|null|undefined): string|null => /^https?:\/\//i.test(u??'') ? u! : null; // Icons: Font Awesome Free 7.3.1 by @fontawesome - https://fontawesome.com // License - https://fontawesome.com/license/free (Icons: CC BY 4.0). Embedded as SVG, only the // ones used, so there is no font to download and nothing is fetched from anyone else. Each takes // the button's own colour. To add one, copy the path from svgs/