Enhance exam question fragment by exposing current question index for global listeners and updating question list state locally to reflect answered questions

This commit is contained in:
Ross
2026-01-05 14:16:02 +00:00
parent 8d638cc08b
commit 3d1b9a57f9
3 changed files with 93 additions and 81 deletions
+29 -19
View File
@@ -204,26 +204,26 @@
.physics-answer-list li { padding: 0.6rem; } .physics-answer-list li { padding: 0.6rem; }
} }
/* Question menu item states (small pill buttons) */ /* Question menu item states (small pill buttons) */
button.question-menu-item { button.question-menu-item {
color: var(--text); color: var(--text);
border: 1px solid var(--card-border); border: 1px solid var(--card-border);
background: var(--card-bg); background: var(--card-bg);
padding: 0.25rem 0.5rem; padding: 0.25rem 0.5rem;
border-radius: 0.35rem; border-radius: 0.35rem;
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 0.4rem; gap: 0.4rem;
} }
button.question-menu-item.answered { button.question-menu-item.answered {
border-color: var(--success) !important; /* answered -> success border */ border-color: var(--success) !important; /* answered -> success border */
} }
/* flagged items show an icon only; no border change here */ /* flagged items show an icon only; no border change here */
button.question-menu-item .question-flag { button.question-menu-item .question-flag {
margin-left: 0.25rem; margin-left: 0.25rem;
font-size: 0.85em; font-size: 0.85em;
color: #ffc107; color: #ffc107;
line-height: 1; line-height: 1;
} }
</style> </style>
{% endblock %} {% endblock %}
@@ -298,6 +298,16 @@
requestAnimationFrame(function(){ el.style.opacity = '1'; }); requestAnimationFrame(function(){ el.style.opacity = '1'; });
// hide after 1.6s // hide after 1.6s
setTimeout(function(){ el.style.opacity = '0'; }, 1600); setTimeout(function(){ el.style.opacity = '0'; }, 1600);
// Update the question list state locally so the menu reflects answered questions
try {
var pos = (typeof window.currentQuestionPos === 'number') ? window.currentQuestionPos : (document.getElementById('question-number') ? parseInt(document.getElementById('question-number').textContent, 10) - 1 : NaN);
if (!isNaN(pos)) {
window.examQuestionAnswered = window.examQuestionAnswered || new Array({{ exam_length }}).fill(false);
window.examQuestionAnswered[pos] = true;
var btn = document.querySelector('#menu-list [data-qn="' + pos + '"]');
if (btn) btn.classList.add('answered');
}
} catch (e) { console && console.error && console.error(e); }
} catch (e) { console && console.error && console.error(e); } } catch (e) { console && console.error && console.error(e); }
}); });
</script> </script>
@@ -2,11 +2,11 @@
{% block content %} {% block content %}
<span id="user-id"> <span id="user-id">
{% if not cid %} {% if not cid %}
User: {{request.user}} User: {{request.user}}
{% else %} {% else %}
CID: {{cid}} CID: {{cid}}
{% endif %} {% endif %}
</span> </span>
{% include "exam_clock.html" %} {% include "exam_clock.html" %}
@@ -63,9 +63,9 @@
{% endfor %} {% endfor %}
</div> </div>
<div id="time-details"> <div id="time-details">
Start time: {{cid_user_exam.start_time}}<br/> Start time: {{cid_user_exam.start_time}}<br/>
Last change time: {{cid_user_exam.end_time}}<br/> Last change time: {{cid_user_exam.end_time}}<br/>
Completed: {{cid_user_exam.completed}} Completed: {{cid_user_exam.completed}}
</div> </div>
{% if not cid_user_exam.completed %} {% if not cid_user_exam.completed %}
@@ -97,69 +97,69 @@
{% endblock %} {% endblock %}
{% block css %} {% block css %}
<style> <style>
/* Overview page specific styles */ /* Overview page specific styles */
.overview-text { .overview-text {
margin-bottom: 1rem; margin-bottom: 1rem;
font-weight: 500; font-weight: 500;
} }
.physics-finish-list { .physics-finish-list {
display: grid; display: grid;
/* Limit the maximum width of each tile so buttons don't stretch too wide on large screens. /* Limit the maximum width of each tile so buttons don't stretch too wide on large screens.
Each tile will be between 80px and 140px. The grid will wrap responsively. */ Each tile will be between 80px and 140px. The grid will wrap responsively. */
grid-template-columns: repeat(auto-fit, minmax(80px, 140px)); grid-template-columns: repeat(auto-fit, minmax(80px, 140px));
justify-content: start; justify-content: start;
gap: .5rem; gap: .5rem;
align-items: stretch; align-items: stretch;
margin-bottom: 1rem; margin-bottom: 1rem;
} }
.overview-question-btn { .overview-question-btn {
/* Fill the grid cell but the cell itself is capped by the grid-template-columns above. */ /* Fill the grid cell but the cell itself is capped by the grid-template-columns above. */
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
text-align: left; text-align: left;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
padding: .5rem .75rem; padding: .5rem .75rem;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-start; justify-content: flex-start;
} }
/* Flagged question indicator: use border colour to signal a flagged item */ /* Flagged question indicator: use border colour to signal a flagged item */
.overview-question-btn.flagged { .overview-question-btn.flagged {
border-color: #ffc107 !important; border-color: #ffc107 !important;
box-shadow: 0 1px 2px rgba(255,193,7,0.06); box-shadow: 0 1px 2px rgba(255,193,7,0.06);
background: rgba(255,193,7,0.03); background: rgba(255,193,7,0.03);
} }
/* Unanswered questions should draw attention */ /* Unanswered questions should draw attention */
.overview-question-btn[title] { .overview-question-btn[title] {
border-color: #dc3545 !important; border-color: #dc3545 !important;
color: #dc3545 !important; color: #dc3545 !important;
background: rgba(220,53,69,0.03); background: rgba(220,53,69,0.03);
} }
#time-details { #time-details {
font-size: .95rem; font-size: .95rem;
color: #9aa0a6; color: #9aa0a6;
margin-top: .5rem; margin-top: .5rem;
} }
/* Make the finish button stand out on small screens */ /* Make the finish button stand out on small screens */
.btn-primary.mt-3 { .btn-primary.mt-3 {
min-width: 160px; min-width: 160px;
}
@media (max-width: 575.98px) {
.physics-finish-list {
/* On very small screens allow slightly narrower tiles but still wrap */
grid-template-columns: repeat(auto-fit, minmax(70px, 110px));
} }
.overview-question-btn { font-size: .95rem }
} @media (max-width: 575.98px) {
</style> .physics-finish-list {
/* On very small screens allow slightly narrower tiles but still wrap */
grid-template-columns: repeat(auto-fit, minmax(70px, 110px));
}
.overview-question-btn { font-size: .95rem }
}
</style>
{% endblock %} {% endblock %}
@@ -86,6 +86,8 @@
try { try {
var qnum = document.getElementById('question-number'); var qnum = document.getElementById('question-number');
if (qnum) { qnum.textContent = '{{ pos|add:"1" }}'; } if (qnum) { qnum.textContent = '{{ pos|add:"1" }}'; }
// expose current question index for global listeners
window.currentQuestionPos = {{ pos }};
var qstem = document.getElementById('question-stem'); var qstem = document.getElementById('question-stem');
if (qstem) { qstem.innerHTML = '{{ question.stem|escapejs }}'; } if (qstem) { qstem.innerHTML = '{{ question.stem|escapejs }}'; }
} catch (err) { } catch (err) {