Implement timed-out submission handling and AJAX response for collection case view
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
<div id="question-timer-progress-inner" style="width:100%; height:100%; background:var(--timer-color, #28a745);"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="timer-htmx-target" style="display:none;"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -414,15 +415,35 @@
|
||||
var $next = $form.find('button[name="next"]');
|
||||
var $finish = $form.find('button[name="finish"]');
|
||||
|
||||
if ($next.length) {
|
||||
$next.prop('disabled', false);
|
||||
$next.click();
|
||||
} else if ($finish.length) {
|
||||
$finish.prop('disabled', false);
|
||||
$finish.click();
|
||||
} else {
|
||||
$form.submit();
|
||||
}
|
||||
// Instead of navigating away, submit via fetch with timed_out flag
|
||||
// Use HTMX to POST the timed_out flag and then lock the UI
|
||||
var onAfter = function (evt) {
|
||||
try {
|
||||
// lock the form UI in-place
|
||||
$form.find('input, textarea, select, button').prop('disabled', true);
|
||||
$form.addClass('timed-out-locked');
|
||||
$('#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 {
|
||||
$timer.text(formatTime(remaining));
|
||||
updateProgress();
|
||||
|
||||
@@ -2786,11 +2786,33 @@ def collection_case_view_take(
|
||||
raise Http404("Self review not enabled")
|
||||
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()
|
||||
|
||||
cid_user_exam.end_time = timezone.now()
|
||||
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:
|
||||
kwargs = {"pk": pk, "cid": cid, "passcode": passcode}
|
||||
redirect_url = "atlas:collection_case_view_take"
|
||||
|
||||
Reference in New Issue
Block a user