Implement primary answer management with HTMX support, including form for selecting or creating answers and display templates

This commit is contained in:
Ross
2026-02-16 09:46:57 +00:00
parent ec03def164
commit 17d3b4206a
7 changed files with 165 additions and 3 deletions
@@ -0,0 +1,25 @@
<div id="primary-answer-container" class="position-relative primary-answer-wrap py-1">
<strong>{{ question.get_primary_answer }}</strong>
<button
class="edit-primary-btn btn btn-sm btn-link text-muted position-absolute"
style="right:0; top:0;"
hx-get="{% url 'anatomy:primary_answer_htmx' pk=question.pk %}"
hx-target="#primary-answer-container"
hx-swap="outerHTML"
aria-label="Edit primary answer"
>
Edit
</button>
<style>
/* Scoped styles for primary answer edit control */
.primary-answer-wrap .edit-primary-btn {
opacity: 0.55;
transition: opacity 120ms ease, color 120ms ease;
}
.primary-answer-wrap:hover .edit-primary-btn {
opacity: 1;
color: inherit;
}
</style>
</div>
@@ -0,0 +1,4 @@
<div id="primary-answer-container">
<span class="small text-muted">No primary answer set</span>
<button class="btn btn-sm btn-link" hx-get="{% url 'anatomy:primary_answer_htmx' pk=question.pk %}" hx-target="#primary-answer-container" hx-swap="outerHTML">Add primary answer</button>
</div>
@@ -0,0 +1,58 @@
{% load crispy_forms_tags %}
<div id="primary-answer-container">
<form hx-post="{% url 'anatomy:primary_answer_htmx' pk=question.pk %}" hx-target="#primary-answer-container" hx-swap="outerHTML">
{% csrf_token %}
<div class="mb-2">
<label for="id_existing_answer" class="form-label">Select existing answer</label>
<select name="existing_answer" id="id_existing_answer" class="form-select">
{% for val, text in form.existing_answer.field.choices %}
<option value="{{ val }}" {% if val == form.initial.existing_answer %}selected{% endif %}>{{ text }}</option>
{% endfor %}
</select>
</div>
<div class="mb-2">
<label for="id_new_answer" class="form-label">Or add a new primary answer</label>
<textarea name="new_answer" id="id_new_answer" class="form-control" rows="3"></textarea>
<script>
(function(){
const sel = document.getElementById('id_existing_answer');
const ta = document.getElementById('id_new_answer');
if(!sel || !ta) return;
function update() {
try {
if (ta.value && ta.value.trim().length > 0) {
sel.disabled = true;
} else {
sel.disabled = false;
}
} catch(e) {
// ignore
}
}
// initial state
update();
// listeners
sel.addEventListener('change', function(){
if(this.value && this.value !== '') {
ta.disabled = true;
} else {
ta.disabled = false;
}
});
ta.addEventListener('input', update);
})();
</script>
</div>
<div class="d-flex gap-2">
<button class="btn btn-primary btn-sm" type="submit">Save primary answer</button>
<button class="btn btn-secondary btn-sm" type="button" hx-get="{% url 'anatomy:primary_answer_htmx' pk=question.pk %}?cancel=1" hx-target="#primary-answer-container" hx-swap="outerHTML">Cancel</button>
</div>
</form>
</div>
@@ -36,7 +36,11 @@
</div>
<h6 class="mt-2">Primary answer</h6>
<div class="mb-2"><strong>{{ question.get_primary_answer }}</strong></div>
{% if question.primary_answer %}
{% include 'anatomy/partials/primary_answer_display.html' %}
{% else %}
<div id="primary-answer-container" hx-get="{% url 'anatomy:primary_answer_htmx' pk=question.pk %}" hx-trigger="load" hx-swap="outerHTML"></div>
{% endif %}
<h6>Answers</h6>
<details class="mb-3">