class PackageIndexEntry { name: string description: string | null website: string | null version: string | null report: boolean } function toHTML(entry: PackageIndexEntry): HTMLTableRowElement { let v = entry.version != null ? `${escapeHtml(entry.version)}` : "" let d = entry.description != null ? `

${escapeHtml(entry.description)}

` : "" let w = entry.website != null ? `Website` : "" let r = entry.report ? `Log (View | Download)` : "" let row = (document.createElement('tr')) row.innerHTML = `

${escapeHtml(entry.name)} ${v}

${d} ${w} ${r} ` return row } const API_VERSION = 1 const ENDPOINT = `/api/v${API_VERSION}` class InfoPayload { count: number hakurei_version: string } async function infoRequest(): Promise { const res = await fetch(`${ENDPOINT}/info`) const payload = await res.json() return payload as InfoPayload } class GetPayload { count: number values: PackageIndexEntry[] } enum SortOrders { DeclarationAscending = 0, DeclarationDescending, NameAscending, NameDescending } async function getRequest(limit: number, index: number, sort: SortOrders): Promise { const res = await fetch(`${ENDPOINT}/get?limit=${limit}&index=${index}&sort=${sort.valueOf()}`) const payload = await res.json() return payload as GetPayload } class State { entriesPerPage: number = 10 entryIndex: number = 0 maxEntries: number = 0 sort: SortOrders = SortOrders.DeclarationAscending getEntriesPerPage(): number { return this.entriesPerPage } setEntriesPerPage(entriesPerPage: number) { this.entriesPerPage = entriesPerPage this.setEntryIndex(Math.floor(this.getEntryIndex() / entriesPerPage) * entriesPerPage) } getEntryIndex(): number { return this.entryIndex } setEntryIndex(entryIndex: number) { this.entryIndex = entryIndex this.updatePage() this.updateRange() this.updateListings() } getMaxEntries(): number { return this.maxEntries } setMaxEntries(max: number) { this.maxEntries = max } getSortOrder(): SortOrders { return this.sort } setSortOrder(sortOrder: SortOrders) { this.sort = sortOrder this.setEntryIndex(0) } updatePage() { let page = Math.ceil(((this.getEntryIndex() + this.getEntriesPerPage()) - 1) / this.getEntriesPerPage()) document.getElementById("page-number").innerText = String(page) } updateRange() { let max = Math.min(this.getEntryIndex() + this.getEntriesPerPage(), this.getMaxEntries()) document.getElementById("entry-counter").innerText = `${this.getEntryIndex() + 1}-${max} of ${this.getMaxEntries()}` } updateListings() { getRequest(this.getEntriesPerPage(), this.getEntryIndex(), this.getSortOrder()) .then(res => { let table = document.getElementById("pkg-list") table.innerHTML = '' for(let i = 0; i < res.count; i++) { table.appendChild(toHTML(res.values[i])) } }) } } let STATE: State function prevPage() { let index = STATE.getEntryIndex() STATE.setEntryIndex(Math.max(0, index - STATE.getEntriesPerPage())) } function nextPage() { let index = STATE.getEntryIndex() STATE.setEntryIndex(Math.min((Math.ceil(STATE.getMaxEntries() / STATE.getEntriesPerPage()) * STATE.getEntriesPerPage()) - STATE.getEntriesPerPage(), index + STATE.getEntriesPerPage())) } function escapeHtml(str: string): string { return str .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, ''') } document.addEventListener("DOMContentLoaded", () => { STATE = new State() infoRequest() .then(res => { STATE.setMaxEntries(res.count) document.getElementById("hakurei-version").innerText = res.hakurei_version STATE.updateRange() STATE.updateListings() }) document.getElementById("count").addEventListener("change", (event) => { STATE.setEntriesPerPage(parseInt((event.target as HTMLSelectElement).value)) }) document.getElementById("sort").addEventListener("change", (event) => { STATE.setSortOrder(parseInt((event.target as HTMLSelectElement).value)) }) })