Refactor exam question fragment to move flag button inside the fragment for HTMX updates and enhance local state management for answered and flagged questions.
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
[<span id="question-number">{{ pos|add:1 }}</span>/<span id="exam-length">{{ exam_length }}</span>]
|
||||
</h2>
|
||||
<div class="ms-3">
|
||||
{% include 'physics/partials/exam_flag_button.html' %}
|
||||
<!-- flag button moved into the question fragment so it updates with HTMX swaps -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -69,6 +69,27 @@
|
||||
}catch(e){ console && console.error && console.error(e); }
|
||||
};
|
||||
</script>
|
||||
<script>
|
||||
// Listen for flag button swaps (HTMX) and update the local menu state
|
||||
document.addEventListener('htmx:afterSwap', function(evt){
|
||||
try{
|
||||
var target = (evt.detail && (evt.detail.target || evt.detail.elt)) || evt.target;
|
||||
if(!target) return;
|
||||
// If the flag button was swapped, update flagged array for current pos
|
||||
var container = (target.id === 'flag-button-container') ? target : target.querySelector && target.querySelector('#flag-button-container');
|
||||
if(!container) return;
|
||||
var btn = container.querySelector('button');
|
||||
if(!btn) return;
|
||||
var flaggedNow = btn.classList.contains('btn-warning');
|
||||
var pos = (typeof window.currentQuestionPos === 'number') ? window.currentQuestionPos : NaN;
|
||||
if(!isNaN(pos)){
|
||||
window.examQuestionFlagged = window.examQuestionFlagged || new Array({{ exam_length }}).fill(false);
|
||||
window.examQuestionFlagged[pos] = !!flaggedNow;
|
||||
if(typeof window.updateQuestionMenu === 'function') window.updateQuestionMenu();
|
||||
}
|
||||
}catch(e){ console && console.error && console.error(e); }
|
||||
});
|
||||
</script>
|
||||
|
||||
{% include "physics/exam_take_help.html" %}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<div class="exam-question-fragment">
|
||||
<!-- Flag button lives inside the fragment so it updates together with other question controls -->
|
||||
{% include 'physics/partials/exam_flag_button.html' %}
|
||||
<form method="POST" class="post-form"
|
||||
hx-post="{% if cid %}{% url 'physics:exam_take' pk=exam.pk sk=pos cid=cid passcode=passcode %}{% else %}{% url 'physics:exam_take_user' pk=exam.pk sk=pos %}{% endif %}"
|
||||
hx-target="#question-fragment" hx-swap="innerHTML">
|
||||
@@ -134,6 +136,14 @@
|
||||
|
||||
// build the question menu locally so it is available after fragment swaps
|
||||
$('#menu-list').empty();
|
||||
const serverAnswered = {{ answered_json|default:'null'|safe }};
|
||||
const serverFlagged = {{ flagged_json|default:'null'|safe }};
|
||||
if ((!window.examQuestionAnswered || !Array.isArray(window.examQuestionAnswered)) && Array.isArray(serverAnswered)) {
|
||||
window.examQuestionAnswered = serverAnswered;
|
||||
}
|
||||
if ((!window.examQuestionFlagged || !Array.isArray(window.examQuestionFlagged)) && Array.isArray(serverFlagged)) {
|
||||
window.examQuestionFlagged = serverFlagged;
|
||||
}
|
||||
const answeredArr = (window.examQuestionAnswered && Array.isArray(window.examQuestionAnswered)) ? window.examQuestionAnswered : null;
|
||||
const flaggedArr = (window.examQuestionFlagged && Array.isArray(window.examQuestionFlagged)) ? window.examQuestionFlagged : null;
|
||||
for (let i = 0; i < {{ exam_length }}; i++) {
|
||||
|
||||
@@ -485,6 +485,16 @@ def exam_take_fragment(request, pk: int, sk: int, cid: str | None = None, passco
|
||||
"saved_answer": saved_answer,
|
||||
"answer": answer,
|
||||
"flagged": flagged,
|
||||
"answered_json": json.dumps([
|
||||
True if (q.cid_user_answers.filter(cid=cid, exam=exam).exists() if cid is not None else q.cid_user_answers.filter(user=request.user, exam=exam).exists()) else False
|
||||
for q in questions
|
||||
]),
|
||||
"flagged_json": json.dumps([
|
||||
(Flag.objects.filter(content_type=ContentType.objects.get_for_model(q), object_id=q.pk).filter(cid_user__cid=cid).exists()
|
||||
if cid is not None
|
||||
else Flag.objects.filter(content_type=ContentType.objects.get_for_model(q), object_id=q.pk).filter(user=request.user).exists())
|
||||
for q in questions
|
||||
]),
|
||||
"passcode": passcode,
|
||||
"cid_user_exam": cid_user_exam,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user