{% extends "form_view.html" %} {% load i18n crispy_forms_tags %} {% comment %} Renders ItemForm group by group rather than through one call (plan.md D-3): there is no fieldset, accordion or tabs component in django-mvp 0.17.0, so grouping is a per group, each one shown or hidden by Alpine depending on the chosen item type. (cotton/form/render.html) dumps the *whole* form through crispy in one call whenever it is given a bound form object, and form_view.html's own passes one unconditionally — so page.content is overridden here in full, not just formset/actions, and the used below deliberately carries no :form-obj, which is what keeps from firing at all. cotton/form/index.html still opens the one x-data="{form: {}}" scope on the
element itself, so every value this template adds lives under form.* rather than declaring a second x-data (plan.md D-3) — a bare top-level variable set from x-init would not become reactive at all: Alpine's expression evaluator falls back to an implicit global the first time a name is written that is not already a property somewhere in scope. {% endcomment %} {% block page.content %}
{% block before_form %} {% endblock before_form %} {% if next_url %}{% endif %} {% block formset %} {# No |safe on either value. Both are JSON, so both contain double #} {# quotes, and a raw double quote inside a double-quoted attribute #} {# closes it — the browser then reads the rest of the JSON as a #} {# string of junk attribute names and Alpine receives a truncated #} {# expression. Autoescaping emits ", which the HTML tokenizer #} {# decodes back to a quote inside the attribute value, so Alpine #} {# gets valid JavaScript. #}
{# The type field renders unconditionally — with no type chosen yet, #} {# nothing else on the page is guarded to show (FR-002, plan.md D-3). #}
{{ type_field|as_crispy_field }}
{% for group in field_groups %}
{% for field in group.fields %}{{ field|as_crispy_field }}{% endfor %}
{% endfor %} {# (django-mvp) supplies its own daisyUI classes — #} {# this app's utility-class allowlist (T021, FR-008) covers only #} {# literal Tailwind utility class attributes, never a hand-written #} {# daisyUI component class. #}
{% endblock formset %} {% block actions %} {# The stock block (form_view.html) posts default_next=list on its #} {# Save button, which NextURLMixin consults ahead of success_url — #} {# every save would land on the catalogue rather than the reference #} {# (plan.md D-3). This button carries no name/value pair, so nothing #} {# overrides success_url = "detail". #} {% endblock actions %}
{% block after_form %} {% endblock after_form %}
{% endblock page.content %}