import { type InProgressGeneratedState, RolledValues, RollSelections, type RollTableAuthor, type RollTableDetailsNoResults, type RollTableLimited, type RollTableResult, type RollTableResultSet } from '../common/rolltable'; export function asBoolean(s: string|undefined): boolean|undefined { if (typeof s === "undefined") { return } switch (s.toLowerCase()) { case "true": return true case "false": return false default: return } } export function asInteger(s: string|undefined): number|undefined { if (typeof s === "undefined") { return } const result = parseInt(s) if (Number.isNaN(result)) { return } return result } export function asTimestamp(s: string|undefined): Date|undefined { const i = asInteger(s) if (typeof i === "undefined") { return } const date = new Date(i) if (Number.isNaN(date.valueOf())) { return } return date } export function textFrom(e: HTMLElement|null): string|undefined { if (!e) { return } return e.innerText.trim() } export function hrefFrom(e: HTMLAnchorElement|null): string | null { if (!e) { return null } return e.href } export function checkedFrom(e: HTMLInputElement|null): boolean | null { if (!e) { return null } return e.checked } // element to find here is .author export function scrapeAuthor(author: HTMLElement|null): RollTableAuthor|null|undefined { if (!author) { return null } const id = asInteger(author.dataset["id"]) const name = textFrom(author.querySelector(".authorName")) const url = hrefFrom(author.querySelector("a[href]")) const relation = textFrom(author.querySelector(".authorRelation")) if (typeof id === "undefined" || typeof name === "undefined" || typeof relation === 'undefined') { return } return { id, name, url, relation } } // element to find here is .resultSet export function scrapeResultSet(set: HTMLElement|null): RollTableResultSet|null|undefined { if (!set) { return null } const id = asInteger(set.dataset["id"]) const name = textFrom(set.querySelector(".setName")) const global = asBoolean(set.dataset["global"]) if (typeof id === "undefined" || typeof global === "undefined") { return } return { id, name: name ?? null, description: null, global, } } // element to find here is .tableHeader export function scrapeTableHeader(head: HTMLElement|null): RollTableLimited|RollTableDetailsNoResults|null|undefined { if (!head) { return null } const emoji = textFrom(head.querySelector(".tableEmoji")) const title = textFrom(head.querySelector(".tableTitle")) const ordinal = asInteger(head.dataset["ordinal"]) const id = asInteger(head.dataset["id"]) const identifier = head.dataset["identifier"] const name = head.dataset["name"] if (typeof emoji === 'undefined' || typeof title === 'undefined' || typeof ordinal === 'undefined') { return } const header = `${emoji} ${title}` if (typeof id === 'undefined' || typeof identifier === 'undefined' || typeof name === 'undefined') { return { full: false, emoji, title, header, ordinal, } } return { full: 'details', id, identifier, emoji, title, header, ordinal, name, } } export function scrapeGeneratedHead(head: HTMLElement|null): {table: RollTableLimited|RollTableDetailsNoResults, selected: boolean|null}|null|undefined { if (!head) { return null } const table = scrapeTableHeader(head.querySelector(".tableHeader")) if (!table) { return } const selected = checkedFrom(head.querySelector("input[type=checkbox].generatedSelect")) return { table, selected, } } // element to find here is .resultText export function scrapeResultText(result: HTMLElement|null): {full: false, text: string}|{full: true, mappingId: number, textId: number, updated: Date, text: string}|undefined|null { if (!result) { return null } const text = textFrom(result) const mappingId = asInteger(result.dataset["mappingid"]) const textId = asInteger(result.dataset["textid"]) const updated = asTimestamp(result.dataset["updated"]) if (typeof text === 'undefined') { return } if (typeof mappingId === 'undefined' || typeof textId === 'undefined' || typeof updated == 'undefined') { return { full: false, text, } } return { full: true, text, textId, mappingId, updated: new Date(updated) } } // element to find here is .generatedElement export function scrapeGeneratedElement(generated: HTMLElement|null): {result: RollTableResult, selected: boolean|null}|null|undefined { if (!generated) { return null } const result = scrapeResultText(generated.querySelector(".resultText")) const author = scrapeAuthor(generated.querySelector(".author")) const set = scrapeResultSet(generated.querySelector(".resultSet")) const header = scrapeGeneratedHead(generated.querySelector(".generatedHead")) if (!header || !result) { return } const {table, selected} = header if (!set || typeof author === "undefined" || !result.full) { return { result: { full: false, table, text: result.text, }, selected } } return { result: { ...result, author, set, table, }, selected, } } export function scrapeGeneratedScenario(scenario: HTMLElement): InProgressGeneratedState|undefined export function scrapeGeneratedScenario(scenario: null): null // element to find here is #generatedScenario export function scrapeGeneratedScenario(scenario: HTMLElement|null): InProgressGeneratedState|null|undefined { if (!scenario) { return null } const rolls = new RolledValues() const selection = new RollSelections() for (const item of scenario.querySelectorAll(".generatedElement")) { const element = scrapeGeneratedElement(item) if (!element) { return } const {result, selected} = element rolls.add(result) if (selected) { selection.add(result.table) } } return { final: false, rolled: rolls, selected: selection, } }