Commit 2a497831 by chrisndodge

Merge pull request #142 from edx/muhhshoaib/PHX-141-proctoring-timer-count-down-acccessibility

PHX-141 added the timer accessibility issue.
parents 3c51b9ab dac503f1
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
low_threshold_sec: 0, low_threshold_sec: 0,
critically_low_threshold_sec: 0, critically_low_threshold_sec: 0,
course_id: null, course_id: null,
accessibility_time_string: '',
lastFetched: new Date() lastFetched: new Date()
}, },
getFormattedRemainingTime: function (secondsLeft) { getFormattedRemainingTime: function (secondsLeft) {
...@@ -31,19 +32,19 @@ ...@@ -31,19 +32,19 @@
}, },
getRemainingTimeState: function (secondsLeft) { getRemainingTimeState: function (secondsLeft) {
if (secondsLeft > this.get('low_threshold_sec')) { if (secondsLeft > this.get('low_threshold_sec')) {
return ""; return null;
} }
else if (secondsLeft <= this.get('low_threshold_sec') && secondsLeft > this.get('critically_low_threshold_sec')) { else if (secondsLeft <= this.get('low_threshold_sec') && secondsLeft > this.get('critically_low_threshold_sec')) {
// returns the class name that has some css properties // returns the class name that has some css properties
// and it displays the user with the waring message if // and it displays the user with the waring message if
// total seconds is less than the low_threshold value. // total seconds is less than the low_threshold value.
return "low-time warning"; return "warning";
} }
else { else {
// returns the class name that has some css properties // returns the class name that has some css properties
// and it displays the user with the critical message if // and it displays the user with the critical message if
// total seconds is less than the critically_low_threshold_sec value. // total seconds is less than the critically_low_threshold_sec value.
return "low-time critical"; return "critical";
} }
} }
}); });
......
...@@ -20,6 +20,7 @@ var edx = edx || {}; ...@@ -20,6 +20,7 @@ var edx = edx || {};
this.secondsLeft = 0; this.secondsLeft = 0;
/* give an extra 5 seconds where the timer holds at 00:00 before page refreshes */ /* give an extra 5 seconds where the timer holds at 00:00 before page refreshes */
this.grace_period_secs = 5; this.grace_period_secs = 5;
this.first_time_rendering = true;
// we need to keep a copy here because the model will // we need to keep a copy here because the model will
// get destroyed before onbeforeunload is called // get destroyed before onbeforeunload is called
...@@ -89,6 +90,13 @@ var edx = edx || {}; ...@@ -89,6 +90,13 @@ var edx = edx || {};
var html = this.template(this.model.toJSON()); var html = this.template(this.model.toJSON());
this.$el.html(html); this.$el.html(html);
this.$el.show(); this.$el.show();
// only render the accesibility string the first time we render after
// page load (then we will update on time left warnings)
if (this.first_time_rendering) {
this.accessibility_time_string = this.model.get('accessibility_time_string');
this.$el.find('.timer-announce').html(this.accessibility_time_string);
this.first_time_rendering = false;
}
this.updateRemainingTime(this); this.updateRemainingTime(this);
this.timerId = setInterval(this.updateRemainingTime, 1000, this); this.timerId = setInterval(this.updateRemainingTime, 1000, this);
...@@ -141,11 +149,20 @@ var edx = edx || {}; ...@@ -141,11 +149,20 @@ var edx = edx || {};
} }
else { else {
self.secondsLeft = data.time_remaining_seconds; self.secondsLeft = data.time_remaining_seconds;
self.accessibility_time_string = data.accessibility_time_string;
} }
}); });
} }
self.$el.find('div.exam-timer').removeClass("low-time warning critical"); var oldState = self.$el.find('div.exam-timer').attr('class');
self.$el.find('div.exam-timer').addClass(self.model.getRemainingTimeState(self.secondsLeft)); var newState = self.model.getRemainingTimeState(self.secondsLeft);
if (newState !== null && !self.$el.find('div.exam-timer').hasClass(newState)) {
self.$el.find('div.exam-timer').removeClass("warning critical");
self.$el.find('div.exam-timer').addClass("low-time " + newState);
// refresh accessibility string
self.$el.find('.timer-announce').html(self.accessibility_time_string);
}
self.$el.find('span#time_remaining_id b').html(self.model.getFormattedRemainingTime(self.secondsLeft)); self.$el.find('span#time_remaining_id b').html(self.model.getFormattedRemainingTime(self.secondsLeft));
if (self.secondsLeft <= -self.grace_period_secs) { if (self.secondsLeft <= -self.grace_period_secs) {
clearInterval(self.timerId); // stop the timer once the time finishes. clearInterval(self.timerId); // stop the timer once the time finishes.
......
...@@ -502,6 +502,8 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase): ...@@ -502,6 +502,8 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
self.assertEqual(response_data['proctored_exam']['id'], proctored_exam.id) self.assertEqual(response_data['proctored_exam']['id'], proctored_exam.id)
self.assertIsNotNone(response_data['started_at']) self.assertIsNotNone(response_data['started_at'])
self.assertIsNone(response_data['completed_at']) self.assertIsNone(response_data['completed_at'])
# make sure we have the accessible human string
self.assertEqual(response_data['accessibility_time_string'], 'you have 1 hour and 30 minutes remaining')
def test_attempt_ready_to_start(self): def test_attempt_ready_to_start(self):
""" """
...@@ -1128,6 +1130,8 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase): ...@@ -1128,6 +1130,8 @@ class TestStudentProctoredExamAttempt(LoggedInTestCase):
self.assertEqual(data['exam_display_name'], 'Test Exam') self.assertEqual(data['exam_display_name'], 'Test Exam')
self.assertEqual(data['low_threshold_sec'], 1080) self.assertEqual(data['low_threshold_sec'], 1080)
self.assertEqual(data['critically_low_threshold_sec'], 270) self.assertEqual(data['critically_low_threshold_sec'], 270)
# make sure we have the accessible human string
self.assertEqual(data['accessibility_time_string'], 'you have 1 hour and 30 minutes remaining')
def test_get_expired_attempt(self): def test_get_expired_attempt(self):
""" """
......
...@@ -41,7 +41,7 @@ from edx_proctoring.exceptions import ( ...@@ -41,7 +41,7 @@ from edx_proctoring.exceptions import (
from edx_proctoring.serializers import ProctoredExamSerializer, ProctoredExamStudentAttemptSerializer from edx_proctoring.serializers import ProctoredExamSerializer, ProctoredExamStudentAttemptSerializer
from edx_proctoring.models import ProctoredExamStudentAttemptStatus, ProctoredExamStudentAttempt from edx_proctoring.models import ProctoredExamStudentAttemptStatus, ProctoredExamStudentAttempt
from .utils import AuthenticatedAPIView, get_time_remaining_for_attempt from .utils import AuthenticatedAPIView, get_time_remaining_for_attempt, humanized_time
ATTEMPTS_PER_PAGE = 25 ATTEMPTS_PER_PAGE = 25
...@@ -296,6 +296,11 @@ class StudentProctoredExamAttempt(AuthenticatedAPIView): ...@@ -296,6 +296,11 @@ class StudentProctoredExamAttempt(AuthenticatedAPIView):
time_remaining_seconds = get_time_remaining_for_attempt(attempt) time_remaining_seconds = get_time_remaining_for_attempt(attempt)
attempt['time_remaining_seconds'] = time_remaining_seconds attempt['time_remaining_seconds'] = time_remaining_seconds
attempt['accessibility_time_string'] = _('you have {remaining_time} remaining').format(
remaining_time=humanized_time(int(round(time_remaining_seconds / 60.0, 0)))
)
print attempt['accessibility_time_string']
return Response( return Response(
data=attempt, data=attempt,
...@@ -490,6 +495,9 @@ class StudentProctoredExamAttemptCollection(AuthenticatedAPIView): ...@@ -490,6 +495,9 @@ class StudentProctoredExamAttemptCollection(AuthenticatedAPIView):
'critically_low_threshold_sec': critically_low_threshold, 'critically_low_threshold_sec': critically_low_threshold,
'course_id': exam['course_id'], 'course_id': exam['course_id'],
'attempt_id': attempt['id'], 'attempt_id': attempt['id'],
'accessibility_time_string': _('you have {remaining_time} remaining').format(
remaining_time=humanized_time(int(round(time_remaining_seconds / 60.0, 0)))
),
'attempt_status': attempt['status'] 'attempt_status': attempt['status']
} }
else: else:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment