{{ a.id }}
This mark could not be read: {{ a.error }}
{# Shared MARKS panel — included by booth.html (auto-gallery view) and by marks.html (the standalone page a VERBATIM index.html booth links to, since a verbatim page is served as-is and can never render this inline). One primitive, three shapes, one slot: pick — a session declared N options; the operator chooses. Renders as a radio form; answering POSTs to /answer and rewrites .marks.json. note — free text the operator volunteered, in either direction. flag — the operator pointing at one item. Rendered on the item's tile rather than here, so the judgment sits beside the artifact; the count below is the way back to them. Works with JS off — plain form POST, every shape. An answered pick shows the recorded judgment and a collapsed "change" form, because the mark is the CURRENT judgment and not a log. #} {# A mark carrying `error` is sorted out FIRST, whatever shape it claims. A pick keeps its own ⚠ broken rendering below (richer — it has a declaration to show); a broken note would otherwise render as an empty
with a withdraw
button, indistinguishable from a note the operator wrote and then cleared,
and a broken flag would link to a target that is not there. Unreadable state
is visible state — the rule `_hydrate` states for picks, applied to all
three. #}
{% set broken = marks | selectattr('error') | rejectattr('shape', 'equalto', 'pick') | list %}
{% set picks = marks | selectattr('shape', 'equalto', 'pick') | list %}
{% set notes = marks | selectattr('shape', 'equalto', 'note') | rejectattr('error') | list %}
{% set flags = marks | selectattr('shape', 'equalto', 'flag') | rejectattr('error') | list %}
{# `picks_only` + `back_view`: the review rail (view.html) includes this panel
with `marks` narrowed to the open picks it should offer, and wants only the
pick forms, each landing back on the review (`back=view`, R2 C3). ONE
renderer of a pick form, whichever page it sits on. #}
{% if not picks_only %}
{% for a in broken %}
⚠ broken
{{ a.id }}
This mark could not be read: {{ a.error }}
{% endfor %}
{% endif %}
{% for a in picks %}
{% if a.error %}⚠ broken{% elif a.answer and a.answer.complete %}✓ answered{% elif a.answer %}◐ partial{% else %}? open{% endif %}
{{ a.id }}{% if a.multi %} · {{ a.questions|length }} questions{% endif %}
{% if a.target %}on {{ a.target }}{% endif %}
{% if a.answer and not a.answer.complete %}{{ (a.questions|length) - (a.answer.unanswered|length) }}/{{ a.questions|length }}{% endif %}
{% if a.answer %}{{ a.answer.answered_at }}{% if a.answer.answered_by %} · {{ a.answer.answered_by }}{% endif %}{% endif %}
{% if a.error %}
This question could not be read: {{ a.error }}
{% else %}
{% if a.title and not a.multi %}{{ a.title }}
{% endif %}
{{ a.prompt }}
{% if a.answer %}
{% if a.multi %}
{% for q in a.questions %}{% set qa = a.answer.answers.get(q.key) %}
{{ q.prompt }}
{{ qa.label if (qa and qa.choice is not none) else 'left blank' }}
{% if qa and qa.notes %}{{ qa.notes }}{% endif %}
{% endfor %}
{% else %}
{{ a.answer.label }}
{% endif %}
{% if a.answer.notes %}{{ a.answer.notes }}{% endif %}
{% endif %}
{% if a.answer %}change answer{% else %}answer{% endif %}
{% endif %}
{% endfor %}
{% if not picks_only %}
{# FLAGS come right after the picks. On the lightbox (`tray` defined) they
render as the TRAY: the flagged items in SET order — by tile number, the
declared R2 change from the click order below — each the original shown
small, blurred if the item is. The standalone marks page has no item
records, so it keeps the list, in `(created, id)` order. #}
{% if tray is defined %}{% if tray %}
{# In the lightbox the tray and the notes FOLD on a narrow screen (R2 C5):
a closed , which base.html shows open-and-summary-less above
1000px with no script. Below it, the question sits above the set and the
tray and notes are one tap away instead of burying it. #}
✔ flagged · {{ tray|length }}
✔ flagged
{{ tray|length }} item{{ '' if tray|length == 1 else 's' }} · in set order
{% for it in tray %}
{%- if it.kind == 'image' %}
{% else %}{{ it.kind }}{% endif -%}
#{{ "%0*d"|format(ord_width, it.ordinal) }}
{% endfor %}
{% endif %}
{% if orphan_flags %}
✔ flagged
{{ orphan_flags|length }} on files no longer in this booth
{% for m in orphan_flags %}
- {{ m.target }}
{% endfor %}
{% endif %}
{% elif flags %}
✔ flagged
{{ flags|length }} item{{ '' if flags|length == 1 else 's' }}
{% for a in flags %}
- {{ a.target }}
{% endfor %}
{% endif %}
{% set fold_notes = tray is defined and notes %}
{% if fold_notes %}notes · {{ notes|length }}
{% endif %}
{% for a in notes %}
note
{% if a.target %}on {{ a.target }}
{% else %}on this booth{% endif %}
{{ a.created }}{% if a.by %} · {{ a.by }}{% endif %}
{{ a.text }}
{% endfor %}
{% if fold_notes %}{% endif %}
{# The operator volunteering a remark, which before marks had no mechanism at
all — this is the direction that was running through chat. #}
{% endif %}