Implement timed-out submission handling and AJAX response for collection case view

This commit is contained in:
Ross
2025-10-13 10:32:25 +01:00
parent 1cf18c6f0d
commit fa08f9cf76
2 changed files with 52 additions and 9 deletions
@@ -25,6 +25,7 @@
<div id="question-timer-progress-inner" style="width:100%; height:100%; background:var(--timer-color, #28a745);"></div> <div id="question-timer-progress-inner" style="width:100%; height:100%; background:var(--timer-color, #28a745);"></div>
</div> </div>
</div> </div>
<div id="timer-htmx-target" style="display:none;"></div>
</div> </div>
{% endif %} {% endif %}
@@ -414,15 +415,35 @@
var $next = $form.find('button[name="next"]'); var $next = $form.find('button[name="next"]');
var $finish = $form.find('button[name="finish"]'); var $finish = $form.find('button[name="finish"]');
if ($next.length) { // Instead of navigating away, submit via fetch with timed_out flag
$next.prop('disabled', false); // Use HTMX to POST the timed_out flag and then lock the UI
$next.click(); var onAfter = function (evt) {
} else if ($finish.length) { try {
$finish.prop('disabled', false); // lock the form UI in-place
$finish.click(); $form.find('input, textarea, select, button').prop('disabled', true);
} else { $form.addClass('timed-out-locked');
$form.submit(); $('#question-timer').text('Locked');
}
// hide the progress bar
$('#question-timer-progress, #question-timer-progress-outer, #question-timer-progress-inner').hide();
// ensure inner shows empty state if something relies on it
$('#question-timer-progress-inner').css({ width: '0%', background: '#dc3545' });
} catch (e) {
console.error('Error locking UI after htmx request', e);
} finally {
htmx.off('htmx:afterRequest', onAfter);
}
};
htmx.on('htmx:afterRequest', onAfter);
htmx.ajax('POST', window.location.href, {
values: { timed_out: '1' },
swap: 'none',
headers: {
'X-CSRFToken': document.querySelector('input[name="csrfmiddlewaretoken"]').value,
},
target: "#timer-htmx-target",
});
} else { } else {
$timer.text(formatTime(remaining)); $timer.text(formatTime(remaining));
updateProgress(); updateProgress();
+22
View File
@@ -2786,11 +2786,33 @@ def collection_case_view_take(
raise Http404("Self review not enabled") raise Http404("Self review not enabled")
answer.completed = True answer.completed = True
# If this was a timed-out submission, mark as completed
if request.POST.get('timed_out') == '1':
answer.completed = True
answer.save() answer.save()
cid_user_exam.end_time = timezone.now() cid_user_exam.end_time = timezone.now()
cid_user_exam.save() cid_user_exam.save()
# If this was an AJAX/HTMX request, return JSON so the client
# can remain on the same page and update the UI without redirect.
# Detect HTMX/XHR requests robustly. HTMX sets the HX-Request header.
is_ajax = (
request.headers.get('HX-Request', '').lower() == 'true'
or request.headers.get('x-requested-with') == 'XMLHttpRequest'
or getattr(request, 'htmx', False)
)
if is_ajax:
from django.http import JsonResponse
return JsonResponse(
{
'status': 'ok',
'locked': answer.completed,
'submitted_at': answer.submitted_at.isoformat() if getattr(answer, 'submitted_at', None) else None,
}
)
if cid is not None: if cid is not None:
kwargs = {"pk": pk, "cid": cid, "passcode": passcode} kwargs = {"pk": pk, "cid": cid, "passcode": passcode}
redirect_url = "atlas:collection_case_view_take" redirect_url = "atlas:collection_case_view_take"