/** * An "entry" is an element with a `[data-value]` attribute that is a valid ISO8601 string. * * It has an `.idl` property that represents the date range of this entry * * @module */ import { iso8601ToDate } from "@hesxenon/prelude/Codec.js"; import * as Either from "@hesxenon/prelude/Either.js"; import { pipe } from "@hesxenon/prelude/Function.js"; import * as Option from "@hesxenon/prelude/Option.js"; export type Entry = { element: HTMLElement; readonly content: string; readonly start: Date; readonly end: Date; }; export namespace Entry { type Meta = Omit; type InitializedElement = HTMLElement & { [k in typeof entryIdlCacheKey]: Meta; }; const entryIdlCacheKey = Symbol("entry idl cache key"); const isInitialized = ( element: HTMLElement, ): element is InitializedElement => { const values = (element as InitializedElement)[entryIdlCacheKey]; return ( values != null && values.content === element.getAttribute("data-value") ); }; export const fromElement = ( datepicker: UwcDatepickerElement, element: HTMLElement, ): Entry | undefined => { return isInitialized(element) ? { element, ...element[entryIdlCacheKey] } : pipe( Option.fromNullable(element.getAttribute("data-value")), Option.flatMap((content) => pipe( iso8601ToDate.decode(content), Either.match( () => Option.none, (start) => { const meta: Meta = { start, end: datepicker.currentView.addOneUnit(start), content, }; (element as InitializedElement)[entryIdlCacheKey] = meta; return Option.some({ element, ...meta }); }, ), ), ), Option.toUndefined, ); }; export const fromEventTarget = ( datepicker: UwcDatepickerElement, target: EventTarget | null, ): Entry | undefined => { if (!(target instanceof HTMLElement)) { return; } const element = target.closest("[data-value]"); if (element == null || !datepicker.contains(element)) { return; } return fromElement(datepicker, element); }; } export type Idl = Date | string | number; export namespace Idl { export const asComparable = (idl: Idl) => typeof idl === "string" || idl === Number.NEGATIVE_INFINITY || idl === Number.POSITIVE_INFINITY ? idl : idl instanceof Date ? idl.toISOString() : new Date(idl).toISOString(); export const asDate = (idl: Idl) => idl instanceof Date ? idl : new Date(idl); } export type Page = { entries: Entry[]; };