feat: answer field UX improvements

- Auto-add one empty answer field when opening a blank question form
- Auto-append new empty field when typing in the last answer field
- Strip empty answer rows before submit (novalidate + JS cleanup)
- Tab key skips correct/delete buttons, jumping straight to next answer
This commit is contained in:
2026-07-06 22:28:57 +02:00
parent 64a09453e6
commit 394b8c7d33
5 changed files with 29 additions and 6 deletions
@@ -8,6 +8,29 @@ export default class extends Controller {
this.index = this.collectionTarget.children.length; this.index = this.collectionTarget.children.length;
this._setupDrag(); this._setupDrag();
this._syncOrdering(); this._syncOrdering();
if (this.index === 0) {
this.addItem();
}
this.collectionTarget.addEventListener('input', (e) => {
if (e.target.type !== 'text') return;
const item = e.target.closest('[data-collection-item]');
const last = [...this.collectionTarget.children].at(-1);
if (item && item === last && e.target.value.trim() !== '') {
this.addItem();
}
});
const form = this.element.closest('form');
if (form) {
form.addEventListener('submit', () => {
[...this.collectionTarget.children].forEach(item => {
const input = item.querySelector('input[type="text"]');
if (input && input.value.trim() === '') item.remove();
});
});
}
} }
addItem() { addItem() {
@@ -4,13 +4,13 @@
<span class="text-muted" data-drag-handle style="cursor: grab" title="{{ 'Drag to reorder'|trans }}"><i class="bi bi-grip-vertical"></i></span> <span class="text-muted" data-drag-handle style="cursor: grab" title="{{ 'Drag to reorder'|trans }}"><i class="bi bi-grip-vertical"></i></span>
<div class="flex-grow-1">{{ form_widget(answerForm.text) }}</div> <div class="flex-grow-1">{{ form_widget(answerForm.text) }}</div>
<div class="d-none">{{ form_widget(answerForm.isRightAnswer) }}</div> <div class="d-none">{{ form_widget(answerForm.isRightAnswer) }}</div>
<button type="button" <button type="button" tabindex="-1"
class="btn btn-sm {{ answerForm.isRightAnswer.vars.checked ? 'btn-success' : 'btn-danger' }}" class="btn btn-sm {{ answerForm.isRightAnswer.vars.checked ? 'btn-success' : 'btn-danger' }}"
title="{{ 'Toggle correct answer'|trans }}" title="{{ 'Toggle correct answer'|trans }}"
onclick="var cb=this.closest('[data-collection-item]').querySelector('input[type=checkbox]');cb.checked=!cb.checked;this.classList.toggle('btn-success',cb.checked);this.classList.toggle('btn-danger',!cb.checked);this.querySelector('i').className=cb.checked?'bi bi-check-lg':'bi bi-x-lg'"> onclick="var cb=this.closest('[data-collection-item]').querySelector('input[type=checkbox]');cb.checked=!cb.checked;this.classList.toggle('btn-success',cb.checked);this.classList.toggle('btn-danger',!cb.checked);this.querySelector('i').className=cb.checked?'bi bi-check-lg':'bi bi-x-lg'">
<i class="{{ answerForm.isRightAnswer.vars.checked ? 'bi bi-check-lg' : 'bi bi-x-lg' }}"></i> <i class="{{ answerForm.isRightAnswer.vars.checked ? 'bi bi-check-lg' : 'bi bi-x-lg' }}"></i>
</button> </button>
<button type="button" class="btn btn-sm btn-outline-danger" <button type="button" tabindex="-1" class="btn btn-sm btn-outline-danger"
data-action="bo--form-collection#removeItem"><i class="bi bi-trash"></i></button> data-action="bo--form-collection#removeItem"><i class="bi bi-trash"></i></button>
</div> </div>
{% endmacro %} {% endmacro %}
@@ -1,6 +1,6 @@
{% import 'backoffice/partials/answer_row.html.twig' as macros %} {% import 'backoffice/partials/answer_row.html.twig' as macros %}
{{ form_start(form) }} {{ form_start(form, {attr: {novalidate: 'novalidate'}}) }}
{{ form_row(form.question) }} {{ form_row(form.question) }}
{{ form_row(form.reusable) }} {{ form_row(form.reusable) }}
{{ form_row(form.labels) }} {{ form_row(form.labels) }}
@@ -1,6 +1,6 @@
{% import 'backoffice/partials/answer_row.html.twig' as macros %} {% import 'backoffice/partials/answer_row.html.twig' as macros %}
{{ form_start(form) }} {{ form_start(form, {attr: {novalidate: 'novalidate'}}) }}
{{ form_row(form.question) }} {{ form_row(form.question) }}
<div data-controller="bo--form-collection" <div data-controller="bo--form-collection"
@@ -73,7 +73,7 @@
</button> </button>
</form> </form>
{% endif %} {% endif %}
<button class="btn btn-danger" data-action="click->bo--quiz#clearQuiz"> <button class="btn btn-danger rounded-0" data-action="click->bo--quiz#clearQuiz">
{{ 'Clear Quiz...'|trans }} {{ 'Clear Quiz...'|trans }}
</button> </button>
<button class="btn btn-danger rounded-0" data-action="click->bo--quiz#deleteQuiz"> <button class="btn btn-danger rounded-0" data-action="click->bo--quiz#deleteQuiz">