.
This commit is contained in:
@@ -2,6 +2,28 @@
|
||||
|
||||
{% block content %}
|
||||
CID: {{cid}}
|
||||
<div id="timeup">
|
||||
Allocated time over.
|
||||
</div>
|
||||
<div id="clockdiv">
|
||||
Time remaining:
|
||||
{% comment %} <div>
|
||||
<span class="days"></span>
|
||||
<div class="smalltext">Days</div>
|
||||
</div> {% endcomment %}
|
||||
<div>
|
||||
<span class="hours num"></span>
|
||||
<span class="smalltext">Hours</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="minutes num"></span>
|
||||
<span class="smalltext">Minutes</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="seconds num"></span>
|
||||
<span class="smalltext">Seconds</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="no-select">
|
||||
<h2>{{exam.name}}: Question [{{pos|add:1}}/{{exam_length}}]</h2>
|
||||
{% if exam.publish_results %}
|
||||
@@ -100,6 +122,13 @@
|
||||
// $(el).addClass("selected")
|
||||
// })
|
||||
//})
|
||||
|
||||
let time_limit = '{{exam_time_limit}}'
|
||||
if (time_limit != "None") {
|
||||
let end_time = new Date({{cid_user_exam.start_time|date:"U"}}*1000+{{exam.time_limit}}*1000);
|
||||
initializeClock("clockdiv", end_time);
|
||||
}
|
||||
|
||||
{% else %}
|
||||
$(`ol.physics-answer-list input`).each((n, el) => { el.disabled = true; });
|
||||
{{question.get_answers_js}}.forEach((el, n) => {
|
||||
@@ -134,7 +163,54 @@
|
||||
$("#goto-button").click();
|
||||
});
|
||||
/* beautify ignore:end */
|
||||
|
||||
})
|
||||
|
||||
function getTimeRemaining(endtime) {
|
||||
const total = Date.parse(endtime) - Date.parse(new Date());
|
||||
const seconds = Math.floor((total / 1000) % 60);
|
||||
const minutes = Math.floor((total / 1000 / 60) % 60);
|
||||
const hours = Math.floor((total / (1000 * 60 * 60)) % 24);
|
||||
//const days = Math.floor(total / (1000 * 60 * 60 * 24));
|
||||
|
||||
return {
|
||||
total,
|
||||
//days,
|
||||
hours,
|
||||
minutes,
|
||||
seconds
|
||||
};
|
||||
}
|
||||
|
||||
function initializeClock(id, endtime) {
|
||||
const clock = document.getElementById(id);
|
||||
clock.style.display = "block"
|
||||
const daysSpan = clock.querySelector('.days');
|
||||
const hoursSpan = clock.querySelector('.hours');
|
||||
const minutesSpan = clock.querySelector('.minutes');
|
||||
const secondsSpan = clock.querySelector('.seconds');
|
||||
|
||||
function updateClock() {
|
||||
const t = getTimeRemaining(endtime);
|
||||
|
||||
//daysSpan.innerHTML = t.days;
|
||||
hoursSpan.innerHTML = ('0' + t.hours).slice(-2);
|
||||
minutesSpan.innerHTML = ('0' + t.minutes).slice(-2);
|
||||
secondsSpan.innerHTML = ('0' + t.seconds).slice(-2);
|
||||
|
||||
if (t.total <= 0) {
|
||||
clearInterval(timeinterval);
|
||||
timeup.style.display = "block"
|
||||
clock.style.display = "none"
|
||||
}
|
||||
}
|
||||
|
||||
const timeinterval = setInterval(updateClock, 1000);
|
||||
updateClock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% block css %}
|
||||
@@ -160,13 +236,13 @@
|
||||
|
||||
.answer-true::after {
|
||||
content: "[Correct answer: True]";
|
||||
color: purple;
|
||||
|
||||
color: darkgray;
|
||||
|
||||
}
|
||||
.answer-false::after {
|
||||
content: "[Correct answer: False]";
|
||||
color: purple;
|
||||
|
||||
color: darkgray;
|
||||
|
||||
}
|
||||
.answer-correct {
|
||||
border: 1px dotted darkgreen;
|
||||
@@ -183,5 +259,36 @@
|
||||
margin-left: 20px;
|
||||
content: "False"
|
||||
}
|
||||
|
||||
#clockdiv{
|
||||
font-family: sans-serif;
|
||||
display: inline-block;
|
||||
font-weight: 100;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
display: none;
|
||||
color: darkgray;
|
||||
}
|
||||
|
||||
#clockdiv > div{
|
||||
padding: 1px;
|
||||
border-radius: 3px;
|
||||
{% comment %} background: purple; {% endcomment %}
|
||||
display: inline-block;
|
||||
}
|
||||
#clockdiv div > span.num{
|
||||
color: white;
|
||||
padding: 1px;
|
||||
border-radius: 3px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#timeup {
|
||||
display: none;
|
||||
color: red;
|
||||
font-weight: 100;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
+2
@@ -18,6 +18,8 @@
|
||||
<a href="{% url 'physics:exam_take' pk=exam.id sk=forloop.counter0 cid=cid passcode=passcode %}"><button {% if not answer %}class="unanswered"{% endif %}>{{forloop.counter}}: {{answer.answer}}</button></a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
Start time: {{cid_user_exam.start_time}}<br/>
|
||||
Last change time: {{cid_user_exam.end_time}}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -3,5 +3,7 @@
|
||||
{% block navigation %}
|
||||
{{block.super}}
|
||||
<br/>
|
||||
Exams: {{exam.name}}-> <a href="{% url 'physics:exam_overview' pk=exam.pk %}">Overview</a> / <a href="{% url 'physics:exam_scores_cid' pk=exam.pk %}">Scores</a>
|
||||
Exams: {{exam.name}}-> <a href="{% url 'physics:exam_overview' pk=exam.pk %}">Overview</a> /
|
||||
<a href="{% url 'physics:exam_scores_cid' pk=exam.pk %}">Scores</a> /
|
||||
<a href="{% url 'physics:exam_cids' exam_id=exam.pk %}">Candidates</a>
|
||||
{% endblock %}
|
||||
+7
-3
@@ -22,11 +22,15 @@ urlpatterns = [
|
||||
path("exam/<int:pk>/start", views.exam_start, name="exam_start"),
|
||||
path(
|
||||
"exam/<int:pk>/<str:cid>/<str:passcode>/finish",
|
||||
views.exam_finish,
|
||||
name="exam_finish",
|
||||
views.exam_take_overview,
|
||||
name="exam_take_overview",
|
||||
),
|
||||
path("exam/<int:pk>/", views.GenericExamViews.exam_overview, name="exam_overview"),
|
||||
path("exam/<int:pk>/scores", views.GenericExamViews.exam_scores_cid, name="exam_scores_cid"),
|
||||
path(
|
||||
"exam/<int:pk>/scores",
|
||||
views.GenericExamViews.exam_scores_cid,
|
||||
name="exam_scores_cid",
|
||||
),
|
||||
path(
|
||||
"exam/<int:pk>/scores/<int:cid>/<str:passcode>/",
|
||||
views.exam_scores_cid_user,
|
||||
|
||||
+19
-5
@@ -1,3 +1,6 @@
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils import timezone
|
||||
from generic.models import CidUser
|
||||
from physics.decorators import user_is_author_or_physics_checker
|
||||
from physics.filters import QuestionFilter, UserAnswerFilter
|
||||
from generic.mixins import SuperuserRequiredMixin
|
||||
@@ -178,9 +181,12 @@ def exam_start(request, pk):
|
||||
)
|
||||
|
||||
|
||||
def exam_finish(request, pk, cid, passcode):
|
||||
def exam_take_overview(request, pk, cid, passcode):
|
||||
exam = get_object_or_404(Exam, pk=pk)
|
||||
|
||||
if not exam.active:
|
||||
raise Http404("Exam not found")
|
||||
|
||||
if not exam.check_cid_user(cid, passcode):
|
||||
raise Http404("Error accessing exam")
|
||||
|
||||
@@ -202,12 +208,12 @@ def exam_finish(request, pk, cid, passcode):
|
||||
else:
|
||||
question_answer_tuples.append((q, None))
|
||||
|
||||
if not exam.active:
|
||||
raise Http404("Exam not found")
|
||||
c = CidUser.objects.filter(cid=cid).first()
|
||||
cid_user_exam = exam.get_or_create_cid_user_exam(cid_user=c)
|
||||
|
||||
return render(
|
||||
request,
|
||||
"physics/exam_finish.html",
|
||||
"physics/exam_take_overview.html",
|
||||
{
|
||||
"exam": exam,
|
||||
"cid": cid,
|
||||
@@ -215,6 +221,7 @@ def exam_finish(request, pk, cid, passcode):
|
||||
"answer_count": answer_count,
|
||||
"exam_length": len(questions),
|
||||
"passcode": passcode,
|
||||
"cid_user_exam": cid_user_exam,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -229,6 +236,9 @@ def exam_take(request, pk, sk, cid, passcode):
|
||||
if not exam.check_cid_user(cid, passcode):
|
||||
raise Http404("Error accessing exam")
|
||||
|
||||
c = CidUser.objects.filter(cid=cid).first()
|
||||
cid_user_exam = exam.get_or_create_cid_user_exam(cid_user=c)
|
||||
|
||||
question = exam.exam_questions.all()[sk]
|
||||
|
||||
exam_length = len(exam.exam_questions.all())
|
||||
@@ -250,9 +260,12 @@ def exam_take(request, pk, sk, cid, passcode):
|
||||
# answer.published_date = timezone.now()
|
||||
answer.save()
|
||||
|
||||
cid_user_exam.end_time = timezone.now()
|
||||
cid_user_exam.save()
|
||||
|
||||
kwargs = {"pk": pk, "cid": cid, "passcode": passcode}
|
||||
take_url = "physics:exam_take"
|
||||
finish_url = "physics:exam_finish"
|
||||
finish_url = "physics:exam_take_overview"
|
||||
|
||||
if "next" in request.POST:
|
||||
return redirect(take_url, sk=pos + 1, **kwargs)
|
||||
@@ -289,6 +302,7 @@ def exam_take(request, pk, sk, cid, passcode):
|
||||
"exam_length": exam_length,
|
||||
"pos": pos,
|
||||
"passcode": passcode,
|
||||
"cid_user_exam": cid_user_exam,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user