85 lines
1.6 KiB
TypeScript
85 lines
1.6 KiB
TypeScript
import { invalidate } from '$app/navigation';
|
|
|
|
// this action (https://svelte.dev/tutorial/actions) allows us to
|
|
// progressively enhance a <form> that already works without JS
|
|
export function enhance(
|
|
form: HTMLFormElement,
|
|
{
|
|
pending,
|
|
error,
|
|
result
|
|
}: {
|
|
pending?: ({ data, form }: { data: FormData; form: HTMLFormElement }) => void;
|
|
error?: ({
|
|
data,
|
|
form,
|
|
response,
|
|
error
|
|
}: {
|
|
data: FormData;
|
|
form: HTMLFormElement;
|
|
response: Response | null;
|
|
error: Error | null;
|
|
}) => void;
|
|
result?: ({
|
|
data,
|
|
form,
|
|
response
|
|
}: {
|
|
data: FormData;
|
|
response: Response;
|
|
form: HTMLFormElement;
|
|
}) => void;
|
|
} = {}
|
|
) {
|
|
let current_token: unknown;
|
|
|
|
async function handle_submit(e: SubmitEvent) {
|
|
const token = (current_token = {});
|
|
|
|
e.preventDefault();
|
|
|
|
const data = new FormData(form);
|
|
|
|
if (pending) pending({ data, form });
|
|
|
|
try {
|
|
const response = await fetch(form.action, {
|
|
method: form.method,
|
|
headers: {
|
|
accept: 'application/json'
|
|
},
|
|
body: data
|
|
});
|
|
|
|
if (token !== current_token) return;
|
|
|
|
if (response.ok) {
|
|
if (result) result({ data, form, response });
|
|
|
|
const url = new URL(form.action);
|
|
url.search = url.hash = '';
|
|
invalidate(url.href);
|
|
} else if (error) {
|
|
error({ data, form, error: null, response });
|
|
} else {
|
|
console.error(await response.text());
|
|
}
|
|
} catch (e: unknown) {
|
|
if (error && e instanceof Error) {
|
|
error({ data, form, error: e, response: null });
|
|
} else {
|
|
throw e;
|
|
}
|
|
}
|
|
}
|
|
|
|
form.addEventListener('submit', handle_submit);
|
|
|
|
return {
|
|
destroy() {
|
|
form.removeEventListener('submit', handle_submit);
|
|
}
|
|
};
|
|
}
|