Files
pythagoras/client/tools.ts

113 lines
2.9 KiB
TypeScript

/**
* Convert big-endian u32 to native JavaScript number.
*/
export function uint_bytes_to_num(value: Uint8Array): number {
if (value.length != 4) { throw new Error("can't convert non 4-byte integer"); }
const data_view = new DataView(value.buffer);
return data_view.getUint32(0, false);
}
export function utf8_encode(value: string): Uint8Array {
const encoder = new TextEncoder();
let res: Uint8Array = new Uint8Array(0);
for (const ch of value) {
const cur = encoder.encode(ch)[0];
const prev = res;
res = new Uint8Array(prev.length + 1);
res.set(prev, 0);
res.set([cur], prev.length);
}
return res;
}
export function utf8_decode(value: Uint8Array): string {
const decoder = new TextDecoder("utf-8");
return decoder.decode(value);
}
export async function sleep(millis: number): Promise<void> {
await new Promise<void>((resolver) => {
setTimeout(resolver, millis);
});
}
export function wait_for_dom_refresh(): Promise<void> {
return new Promise<void>((resolver) => {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
resolver();
});
});
});
}
export namespace el {
function add_classes(target: HTMLElement, classes?: string[]): void {
if (classes === undefined) { return; }
for (const cls of classes) {
target.classList.add(cls);
}
}
export function div(children: HTMLElement[], classes?: string[]): HTMLDivElement {
const el = document.createElement("div");
add_classes(el, classes);
el.append(...children);
return el;
}
export function h1(text: string, classes?: string[]): HTMLHeadingElement {
const el = document.createElement("h1");
el.innerText = text;
add_classes(el, classes);
return el;
}
export function h2(text: string, classes?: string[]): HTMLHeadingElement {
const el = document.createElement("h2");
el.innerText = text;
add_classes(el, classes);
return el;
}
export function p(text: string, classes?: string[]): HTMLParagraphElement {
const el = document.createElement("p");
el.innerText = text;
add_classes(el, classes);
return el;
}
export async function img(src: string, classes?: string[]): Promise<HTMLImageElement> {
const el = new Image();
el.src = src;
el.draggable = false;
add_classes(el, classes);
await new Promise<void>((resolver) => {
el.addEventListener("load", () => { resolver(); });
});
return el;
}
export async function video(
src: string,
subtitles_url: string | null,
classes?: string[],
): Promise<HTMLVideoElement> {
const blob = await (await fetch(src)).blob();
const el = document.createElement("video");
el.autoplay = true;
const source = document.createElement("source");
source.src = URL.createObjectURL(blob);
el.appendChild(source);
if (subtitles_url !== null) {
const subs = document.createElement("track");
subs.src = subtitles_url;
subs.kind = "subtitles";
subs.default = true;
el.appendChild(subs);
}
add_classes(el, classes);
return el;
}
}