forked from andyburke/autonomous.contact
213 lines
5.2 KiB
JavaScript
213 lines
5.2 KiB
JavaScript
let smarten_forms_debounce_timeout;
|
|
function smarten_forms() {
|
|
if (smarten_forms_debounce_timeout) {
|
|
clearTimeout(smarten_forms_debounce_timeout);
|
|
}
|
|
|
|
smarten_forms_debounce_timeout = setTimeout(() => {
|
|
smarten_forms_debounce_timeout = undefined;
|
|
|
|
const forms =
|
|
document?.body?.querySelectorAll("form[data-smart]:not([data-smartened])") ?? [];
|
|
for (const form of forms) {
|
|
async function on_submit(event) {
|
|
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 = eval("`" + (form.attributes.url?.textContent ?? 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 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;
|
|
}
|
|
}
|
|
|
|
if (key.length === 0) {
|
|
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) {
|
|
try {
|
|
await on_reply(response_body);
|
|
} catch (error) {
|
|
console.trace(error);
|
|
}
|
|
}
|
|
|
|
const inputs_for_reset = form.querySelectorAll("[reset-on-submit]");
|
|
for (const input of inputs_for_reset) {
|
|
const reset_value = input.getAttribute("reset-on-submit");
|
|
input.value = reset_value ?? "";
|
|
}
|
|
|
|
form.querySelector("[focus-on-submit]")?.focus();
|
|
} catch (error) {
|
|
console.dir({
|
|
error,
|
|
});
|
|
|
|
if (form.on_error) {
|
|
return form.on_error(error);
|
|
}
|
|
|
|
alert(error);
|
|
} finally {
|
|
form.disabled = false;
|
|
}
|
|
}
|
|
|
|
form.querySelectorAll("[enter-key-submits]").forEach((element) => {
|
|
element.addEventListener("keypress", (event) => {
|
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
form.requestSubmit();
|
|
}
|
|
});
|
|
});
|
|
|
|
form.addEventListener("submit", on_submit);
|
|
form.dataset.smartened = true;
|
|
}
|
|
}, 10);
|
|
}
|
|
|
|
const smarten_forms_observer = new MutationObserver(smarten_forms);
|
|
smarten_forms_observer.observe(document, {
|
|
childList: true,
|
|
subtree: true,
|
|
});
|