autonomous.contact/public/js/smartforms.js
Andy Burke ab63d4ba8d feature: first pass on replies
refactor: move more smarts in the smartforms around
2025-09-21 16:02:08 -07:00

192 lines
4.6 KiB
JavaScript

function smarten_forms() {
const forms = document.body.querySelectorAll("form[data-smart]:not([data-smartened])");
for (const form of forms) {
async function on_submit(event) {
debugger;
event.preventDefault();
form.disabled = true;
form.__submitted_at = new Date();
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()) {
if (key.length === 0) {
continue;
}
const input = form.querySelector(`[name="${key}"]`);
if (input.type === "file") {
if (input.dataset["smartformsSaveToHome"]) {
form.uploaded = [];
form.errors = [];
const user = document.body.dataset.user
? JSON.parse(document.body.dataset.user)
: undefined;
if (!user) {
throw new Error("You must be logged in to upload files here.");
}
for await (const file of input.files) {
const body = new FormData();
body.append("file", file, encodeURIComponent(file.name));
const file_path =
"/files/users/" + user.id + "/" + encodeURIComponent(file.name);
const file_upload_response = await api.fetch(file_path, {
method: "PUT",
body,
});
if (!file_upload_response.ok) {
const error = await file_upload_response.json();
form.errors.push(error?.error?.message ?? "Unknown error.");
continue;
}
const file_url =
window.location.protocol + "//" + window.location.host + file_path;
form.uploaded.push(file_url);
}
if (form.errors.length) {
const errors = form.errors.join("\n\n");
alert(errors);
return false;
}
continue;
}
}
const generator = input.getAttribute("generator");
const generated_value =
typeof generator === "string" && generator.length
? eval(generator)(input, form)
: undefined;
const resolved_value =
typeof value === "string" && value.length ? value : generated_value;
if (typeof resolved_value === "undefined") {
const should_submit_empty = input && input.dataset["smartformsSubmitEmpty"];
if (!should_submit_empty) {
continue;
}
}
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()] = resolved_value;
}
if (form.uploaded?.length > 0) {
json.data = json.data ?? {};
json.data.media = [...form.uploaded];
}
const on_parsed =
form.on_parsed ??
(form.getAttribute("on_parsed") ? eval(form.getAttribute("on_parsed")) : undefined);
if (on_parsed) {
await 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:\n\n" + error);
return;
}
if (form.on_response) {
await form.on_response(response);
}
const response_body = await response.json();
const on_reply =
form.on_reply ??
(form.getAttribute("on_reply")
? eval(form.getAttribute("on_reply"))
: undefined);
if (on_reply) {
await on_reply(response_body);
}
const inputs_for_reset = form.querySelectorAll("input[reset-on-submit]");
for (const input of inputs_for_reset) {
const reset_value = input.getAttribute("reset-on-submit");
input.value = reset_value ?? "";
}
} 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.dataset.smartened = true;
}
}
const smarten_observer = new MutationObserver(smarten_forms);
smarten_observer.observe(document, {
childList: true,
subtree: true,
});
/*
document.addEventListener("DOMContentLoaded", smarten_forms);
document.addEventListener("DOMSubtreeModified", smarten_forms);
*/