document.addEventListener("DOMContentLoaded", () => { /* make all forms semi-smart */ const forms = document.querySelectorAll("form[data-smart]"); for (const form of forms) { async function on_submit(event) { event.preventDefault(); form.disabled = true; if (form.on_submit) { const result = await form.on_submit(event); if (result === false) { form.disabled = false; return; } } const url = form.action; const method = form.dataset.method ?? "POST"; const json = {}; const form_data = new FormData(form); for (const [key, value] of form_data.entries()) { const elements = key.split("."); let current = json; for (const element of elements.slice(0, elements.length - 1)) { current[element] = current[element] ?? {}; current = current[element]; } current[elements.slice(elements.length - 1).shift()] = value; } if (form.on_parsed) { await form.on_parsed(json); } try { const options = { method, headers: { Accept: "application/json", }, }; if (["POST", "PUT", "PATCH"].includes(method)) { options.json = json; } const response = await api.fetch(url, options); if (!response.ok) { const error_body = await response.json(); const error = error_body?.error; if (form.on_error) { return form.on_error(error); } alert(error.message ?? "Unknown error!"); return; } if (form.on_response) { await form.on_response(response); } const response_body = await response.json(); if (form.on_reply) { return form.on_reply(response_body); } } catch (error) { console.dir({ error, }); if (form.on_error) { return form.on_error(error); } alert(error); } finally { form.disabled = false; } } form.addEventListener("submit", on_submit); //form.onsubmit = on_submit; } });