Enhance exam navigation by adding a skip button for non-saving question transitions and implementing unsaved changes confirmation.

This commit is contained in:
Ross
2026-01-05 11:59:23 +00:00
parent ba0c380f18
commit f44f3bbcfe
@@ -60,7 +60,13 @@
{% endif %}
{% if next %}
<button type="submit" name="next" class="save btn btn-secondary" title="Click to save your answer(s) and go to the next question">Next</button>
<button type="submit" name="next" class="save btn btn-secondary" title="Click to save your answer(s) and go to the next question">Next</button>
<!-- Skip: load the next question fragment without submitting the form -->
<button type="button" id="skip-button" class="btn btn-outline-secondary ms-2" title="Skip to next question without saving"
hx-get="{% if cid %}{% url 'physics:exam_take_fragment' pk=exam.pk sk=pos|add:1 cid=cid passcode=passcode %}{% else %}{% url 'physics:exam_take_fragment_user' pk=exam.pk sk=pos|add:1 %}{% endif %}"
hx-target="#question-fragment" hx-swap="innerHTML">Skip</button>
<!-- Fallback link for non-HTMX clients: simple navigation without saving -->
<a class="d-none" href="{% if cid %}{% url 'physics:exam_take' pk=exam.pk sk=pos|add:1 cid=cid passcode=passcode %}{% else %}{% url 'physics:exam_take_user' pk=exam.pk sk=pos|add:1 %}{% endif %}"></a>
{% else %}
{% if not exam.publish_results %}
<button type="submit" name="save" class="save btn btn-default" title="Click to save your current answer(s)">Save</button>
@@ -128,6 +134,58 @@
document.getElementById('goto-button').value = e.currentTarget.dataset.qn;
$('#goto-button').click();
});
// Skip confirmation: if the user's current selections differ from
// the saved answer, prompt before allowing the HTMX skip to proceed.
(function(){
const skip = document.getElementById('skip-button');
if(!skip) return;
// Build a JS array of saved answers (booleans) or null
{% if saved_answer %}
const savedAnswers = [{% for s in saved_answer %}{{ s|yesno:"true,false" }}{% if not forloop.last %}, {% endif %}{% endfor %}];
{% else %}
const savedAnswers = null;
{% endif %}
function readCurrent(){
const lis = document.querySelectorAll('ol.physics-answer-list li');
return Array.from(lis).map(li => {
const inp = li.querySelector('input');
return !!(inp && inp.checked);
});
}
skip.addEventListener('click', function(evt){
try{
const current = readCurrent();
let changed = false;
if(savedAnswers === null){
// no previously-saved answer; any current selection is a change
changed = current.some(Boolean);
} else {
if(current.length === savedAnswers.length){
for(let i=0;i<current.length;i++){
if(!!current[i] !== !!savedAnswers[i]){ changed = true; break; }
}
} else {
// differing lengths — consider changed if any selection present
changed = current.some(Boolean);
}
}
if(changed){
const ok = confirm('You have unsaved changes. Skip to the next question without saving?');
if(!ok){
// prevent HTMX from handling the click
evt.preventDefault(); evt.stopImmediatePropagation();
return false;
}
}
// allow the HTMX attribute on the button to proceed
}catch(e){ console && console.error && console.error(e); }
});
})();
})();
</script>
</div>