class ElementBuilder { constructor(tag) { let parts = tag.split(/(\.|#)/); if(parts.length % 2 == 0) { throw new Error("invalid element builder tag string"); } this.element = document.createElement(parts[0]); parts = parts.slice(1); for(let i = 0; i < parts.length; i += 2) { let type = parts[i]; let value = parts[i + 1]; switch(type) { case ".": this.element.classList.add(value); break; case "#": this.element.id = value; break; } } } // Need more stuff? Just implement it here. id(id) { this.element.id = id; return this; } class(clazz) { for(const subclass of clazz.split(" ").filter(x => x !== "")) { this.element.classList.add(subclass); } return this; } text(text) { this.element.innerText = text; return this; } html(html) { this.element.innerHTML = html; return this; } on_click(handler) { this.element.onclick = handler; return this; } on_input(handler) { this.element.oninput = handler; return this; } for(fr) { this.element.htmlFor = fr; return this; } src(src) { this.element.src = src; return this; } target(target) { this.element.target = target; return this; } href(href) { this.element.href = href; return this; } download(download) { this.element.download = download; return this; } type(type) { this.element.type = type; return this; } value(value) { this.element.value = value; return this; } checked(checked) { this.element.checked = checked; return this; } placeholder(placeholder) { this.element.placeholder = placeholder; return this; } append(element) { if(element instanceof ElementBuilder) { element = element.finish(); } this.element.appendChild(element); return this; } append_all(elements) { for(const element of elements) { this.element.appendChild(element); } return this; } style(name, value) { this.element.style[name] = value; return this; } if(cond, handler) { if(cond) handler(this); return this; } finish() { return this.element; } } class ButtonListBuilder { constructor(list) { this.list = list; this.display_handler = null; this.onclick_handler = null; this.modify_handler = null; } should_be_pressed(handler) { this.display_handler = handler; return this; } on_click(handler) { this.onclick_handler = handler; return this; } modify(handler) { this.modify_handler = handler; return this; } finish() { let buttons = this.list.map((key) => new ElementBuilder("button") .if(this.modify_handler !== null, (b) => this.modify_handler(b, key)) .if(this.display_handler(key), (b) => b.class("accent")) .finish() ); for(let i = 0; i < buttons.length; i++) { buttons[i].onclick = () => { if(this.onclick_handler !== null) this.onclick_handler(this.list[i]); for(let j = 0; j < buttons.length; j++) { buttons[j].classList.remove("accent"); if(this.display_handler(this.list[j])) { buttons[j].classList.add("accent"); } } }; } return buttons; } } class TextInputBuilder { constructor(result, key) { this.result = result; this.key = key; this.text = ""; } placeholder(placeholder) { this.text = placeholder; return this; } finish() { return new ElementBuilder("input") .type("text") .placeholder(this.text) .value(this.result[this.key]) .on_input((e) => this.result[this.key] = e.target.value) .finish(); } } class BinaryInputBuilder { constructor(result, key) { this.result = result; this.key = key; this.text = ""; this.update_handler = null; } label(label) { this.text = label; return this; } on_update(handler) { this.update_handler = handler; return this; } finish() { let input = new ElementBuilder("input#" + this.key) .type("checkbox") .checked(this.result[this.key]) .if(this.update_handler !== null, b => b.on_click(e => { console.log(e.target.checked); this.result[this.key] = e.target.checked; this.update_handler(e.target.checked); })) .finish(); let bundle = new ElementBuilder("div.horizontal-list") .append(input) .append(new ElementBuilder("label") .for(this.key) .text(this.text)) .finish(); if(this.update_handler !== null) { this.update_handler(this.result[this.key]); } return bundle; } } async function delay_ms(ms) { await new Promise((r) => setTimeout(r, ms)); }