97 lines
3.9 KiB
HTML
97 lines
3.9 KiB
HTML
<button type="submit" class="btn btn-primary" id="submit">Save</button>
|
|
<script>
|
|
window.newDrafts = window.newDrafts || [];
|
|
window.deletedIds = window.deletedIds || [];
|
|
|
|
function formToJson(form) {
|
|
const fd = new FormData(form);
|
|
const out = {};
|
|
fd.forEach((value, key) => {
|
|
if (key in out) {
|
|
if (!Array.isArray(out[key])) out[key] = [out[key]];
|
|
out[key].push(value);
|
|
} else {
|
|
out[key] = value;
|
|
}
|
|
});
|
|
form.querySelectorAll('input[type="checkbox"], input[type="radio"]').forEach(el => {
|
|
if (!el.name) return;
|
|
if (el.type === 'radio') {
|
|
if (out[el.name] !== undefined) return;
|
|
const checked = form.querySelector(`input[type="radio"][name="${CSS.escape(el.name)}"]:checked`);
|
|
if (checked) out[el.name] = checked.value ?? true;
|
|
return;
|
|
}
|
|
if (el.type === 'checkbox') {
|
|
const group = form.querySelectorAll(`input[type="checkbox"][name="${CSS.escape(el.name)}"]`);
|
|
out[el.name] = group.length > 1
|
|
? Array.from(group).filter(i => i.checked).map(i => i.value ?? true)
|
|
: el.checked;
|
|
}
|
|
});
|
|
return out;
|
|
}
|
|
|
|
function collectExistingUpdateIds() {
|
|
return Array.from(document.querySelectorAll('script[type="application/json"][id^="md-"]'))
|
|
.map(el => Number(el.id.slice(3)))
|
|
.filter(Number.isFinite);
|
|
}
|
|
function collectEditedUpdates() {
|
|
const updates = [];
|
|
for (const id of collectExistingUpdateIds()) updates.push({ id, content: getMarkdown(id) });
|
|
for (const md of (window.newDrafts || [])) if ((md ?? '').trim()) updates.push({ content: md });
|
|
return updates;
|
|
}
|
|
function collectDeletedIds() { return (window.deletedIds || []).filter(Number.isFinite); }
|
|
|
|
// much simpler, and correct
|
|
const formEl = document.getElementById({{ (field['attrs']['data-model'] ~ '_form') | tojson }});
|
|
const model = {{ field['attrs']['data-model'] | tojson }};
|
|
const idVal = {{ field['template_ctx']['values'].get('id') | tojson }};
|
|
const hasId = idVal !== null && idVal !== undefined;
|
|
|
|
// Never call url_for for update on the "new" page.
|
|
// Create URL is fine to build server-side:
|
|
const createUrl = {{ url_for('entry.create_entry', model=field['attrs']['data-model']) | tojson }};
|
|
// Update URL is assembled on the client to avoid BuildError on "new":
|
|
const updateUrl = hasId ? `/entry/${model}/${idVal}` : null;
|
|
|
|
formEl.addEventListener("submit", async e => {
|
|
e.preventDefault();
|
|
|
|
const json = formToJson(formEl);
|
|
|
|
if (model === 'inventory' && typeof getMarkdown === 'function') {
|
|
json.notes = getMarkdown().trim();
|
|
} else if (model === 'worklog') {
|
|
json.updates = collectEditedUpdates();
|
|
json.delete_update_ids = collectDeletedIds();
|
|
}
|
|
|
|
if (hasId) json.id = idVal;
|
|
|
|
const url = hasId ? updateUrl : createUrl;
|
|
|
|
try {
|
|
const res = await fetch(url, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(json),
|
|
});
|
|
const reply = await res.json();
|
|
if (reply.status === 'success') {
|
|
toastMessage('This entry has been successfully saved!', 'success');
|
|
window.newDrafts = [];
|
|
window.deletedIds = [];
|
|
if (!hasId && reply.id) {
|
|
window.location.href = `/entry/${model}/${reply.id}?pretty=1`;
|
|
}
|
|
} else {
|
|
toastMessage(`Unable to save entry: ${reply.error}`, 'danger');
|
|
}
|
|
} catch (err) {
|
|
toastMessage(`Network error: ${String(err)}`, 'danger');
|
|
}
|
|
});
|
|
</script>
|