{% extends "vantage/base.html" %} {% load static vantage vantage_slots i18n %} {% block head %} {% if inlines %}{% endif %} {% endblock %} {% block content %} {% comment %} enctype is unconditional: a panel gains a FileField the day someone adds one, and a form that silently drops the upload because the encoding was decided at template time is a bug nobody reports as one. {% endcomment %}
{% csrf_token %}

{{ page_title }}

{{ panel.get_label }}{% if object.pk %} ยท #{{ object.pk }}{% endif %}

{% slot "before_form" %} {% if messages %} {% endif %} {% if form.errors %} {% endif %} {% if layout %} {% comment %} A declared ModelPanel.layout replaces the fixed-section grouping below outright โ€” see PanelFormView.get_layout. {% endcomment %} {% include "vantage/partials/layout_node.html" with node=layout %} {% else %} {% for section in sections %}

{{ section.title }}

{% for entry in section.fields %} {% include "vantage/partials/field.html" with field=entry %} {% endfor %}
{% endfor %} {% endif %} {% comment %} After the parent's own fields, before the submit bar: the children belong to this record, and a save button that appears above half the form invites pressing it before that half has been read. {% endcomment %} {% for group in inlines %} {% include "vantage/partials/inline_group.html" with group=group %} {% endfor %} {% slot "after_form" %}
{% translate "Cancel" %}
{% endblock %} {% block scripts %} {% comment %} Only the form pages carry relation pickers, so only they pay for the file. It enhances every [data-vantage-combobox] on the page, inlines included. {% endcomment %} {% if inlines %}{% endif %} {% comment %} Enhances every textarea[data-markdown] โ€” every RICHTEXT field renders as one, see vantage.widgets.infer_widget. Loaded unconditionally for the same reason as combobox.js above: whether this page has one is a per-request fact the template would otherwise have to thread through just to skip one small file. {% endcomment %} /* Unsaved-changes guard. Compares a snapshot taken at load against the current state, * rather than latching on the first input event โ€” a keystroke that was then undone is * not an unsaved change, and a guard that cries wolf gets clicked through. Submitting * disarms it, or every successful save would prompt on its own redirect. */ (function () { var form = document.querySelector('form[data-vantage-dirty]'); if (!form) return; var hint = form.querySelector('[data-vantage-dirty-hint]'); var armed = true; function serialize() { var parts = []; Array.prototype.forEach.call(form.elements, function (el) { if (!el.name || el.disabled) return; if (el.type === 'checkbox' || el.type === 'radio') { parts.push(el.name + '=' + (el.checked ? el.value : '')); } else if (el.multiple && el.selectedOptions) { parts.push(el.name + '=' + Array.prototype.map.call( el.selectedOptions, function (option) { return option.value; }).join(',')); } else { parts.push(el.name + '=' + el.value); } }); return parts.join('&'); } var snapshot = serialize(); function dirty() { return armed && serialize() !== snapshot; } form.addEventListener('input', function () { if (hint) hint.hidden = !dirty(); }); form.addEventListener('change', function () { if (hint) hint.hidden = !dirty(); }); form.addEventListener('submit', function () { armed = false; if (hint) hint.hidden = true; }); window.addEventListener('beforeunload', function (event) { if (!dirty()) return; event.preventDefault(); event.returnValue = ''; }); })(); {% endblock %}