Commit 2a7c7e96 by Afzal Wali Naushahi

Merge pull request #118 from edx/afzaledx/phx-108_client_side_time_limit

The remaining time is now independent of the browser's system clock.
parents 53968f79 4dae2267
......@@ -16,32 +16,24 @@
course_id: null,
lastFetched: new Date()
},
getRemainingSeconds: function () {
var currentTime = (new Date()).getTime();
var lastFetched = this.get('lastFetched').getTime();
var totalSeconds = this.get('time_remaining_seconds') - (currentTime - lastFetched) / 1000;
return totalSeconds;
},
getFormattedRemainingTime: function () {
var totalSeconds = this.getRemainingSeconds();
getFormattedRemainingTime: function (secondsLeft) {
/* since we can have a small grace period, we can end in the negative numbers */
if (totalSeconds < 0)
totalSeconds = 0;
if (secondsLeft < 0)
secondsLeft = 0;
var hours = parseInt(totalSeconds / 3600) % 24;
var minutes = parseInt(totalSeconds / 60) % 60;
var seconds = Math.floor(totalSeconds % 60);
var hours = parseInt(secondsLeft / 3600) % 24;
var minutes = parseInt(secondsLeft / 60) % 60;
var seconds = Math.floor(secondsLeft % 60);
return hours + ":" + (minutes < 10 ? "0" + minutes : minutes)
+ ":" + (seconds < 10 ? "0" + seconds : seconds);
},
getRemainingTimeState: function () {
var totalSeconds = this.getRemainingSeconds();
if (totalSeconds > this.get('low_threshold_sec')) {
getRemainingTimeState: function (secondsLeft) {
if (secondsLeft > this.get('low_threshold_sec')) {
return "";
}
else if (totalSeconds <= this.get('low_threshold_sec') && totalSeconds > 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
// and it displays the user with the waring message if
// total seconds is less than the low_threshold value.
......
......@@ -17,6 +17,7 @@ var edx = edx || {};
this.template = null;
this.timerId = null;
this.timerTick = 0;
this.secondsLeft = 0;
/* give an extra 5 seconds where the timer holds at 00:00 before page refreshes */
this.grace_period_secs = 5;
......@@ -62,6 +63,7 @@ var edx = edx || {};
// should not be navigating around the courseware
var taking_as_proctored = this.model.get('taking_as_proctored');
var time_left = this.model.get('time_remaining_seconds') > 0;
this.secondsLeft = this.model.get('time_remaining_seconds');
var status = this.model.get('attempt_status');
var in_courseware = document.location.href.indexOf('/courses/' + this.model.get('course_id') + '/courseware/') > -1;
......@@ -125,6 +127,7 @@ var edx = edx || {};
},
updateRemainingTime: function (self) {
self.timerTick ++;
self.secondsLeft --;
if (self.timerTick % 5 === 0){
var url = self.model.url + '/' + self.model.get('attempt_id');
$.ajax(url).success(function(data) {
......@@ -136,12 +139,15 @@ var edx = edx || {};
// refresh the page when the timer expired
location.reload();
}
else {
self.secondsLeft = data.time_remaining_seconds;
}
});
}
self.$el.find('div.exam-timer').removeClass("low-time warning critical");
self.$el.find('div.exam-timer').addClass(self.model.getRemainingTimeState());
self.$el.find('span#time_remaining_id b').html(self.model.getFormattedRemainingTime());
if (self.model.getRemainingSeconds() <= -self.grace_period_secs) {
self.$el.find('div.exam-timer').addClass(self.model.getRemainingTimeState(self.secondsLeft));
self.$el.find('span#time_remaining_id b').html(self.model.getFormattedRemainingTime(self.secondsLeft));
if (self.secondsLeft <= -self.grace_period_secs) {
clearInterval(self.timerId); // stop the timer once the time finishes.
$(window).unbind('beforeunload', this.unloadMessage);
// refresh the page when the timer expired
......
......@@ -46,31 +46,36 @@ describe('ProctoredExamView', function () {
expect(this.proctored_exam_view.$el.find('a')).toContainHtml(this.model.get('exam_display_name'));
});
it('changes behavior when clock time decreases low threshold', function () {
spyOn(this.model, 'getRemainingSeconds').and.callFake(function() {
return 25;
});
expect(this.model.getRemainingSeconds()).toEqual(25);
expect(this.proctored_exam_view.$el.find('div.exam-timer')).not.toHaveClass('low-time warning');
this.proctored_exam_view.secondsLeft = 25;
this.proctored_exam_view.render();
expect(this.proctored_exam_view.$el.find('div.exam-timer')).toHaveClass('low-time warning');
});
it('changes behavior when clock time decreases critically low threshold', function () {
spyOn(this.model, 'getRemainingSeconds').and.callFake(function () {
return 5;
});
expect(this.model.getRemainingSeconds()).toEqual(5);
expect(this.proctored_exam_view.$el.find('div.exam-timer')).not.toHaveClass('low-time critical');
this.proctored_exam_view.secondsLeft = 5;
this.proctored_exam_view.render();
expect(this.proctored_exam_view.$el.find('div.exam-timer')).toHaveClass('low-time critical');
});
it("reload the page when the exam time finishes", function(){
spyOn(this.model, 'getRemainingSeconds').and.callFake(function() {
return -10;
});
expect(this.model.getRemainingSeconds()).toEqual(-10);
this.proctored_exam_view.secondsLeft = -10;
var reloadPage = spyOn(this.proctored_exam_view, 'reloadPage');
this.proctored_exam_view.render();
this.proctored_exam_view.updateRemainingTime(this.proctored_exam_view);
expect(reloadPage).toHaveBeenCalled();
});
it("resets the remainig exam time after the ajax response", function(){
this.server.respondWith("GET", "/api/edx_proctoring/v1/proctored_exam/attempt/" + this.proctored_exam_view.model.get('attempt_id'),
[
200,
{"Content-Type": "application/json"},
JSON.stringify({
time_remaining_seconds: -10
})
]
);
this.proctored_exam_view.timerTick = 4; // to make the ajax call.
var reloadPage = spyOn(this.proctored_exam_view, 'reloadPage');
this.proctored_exam_view.updateRemainingTime(this.proctored_exam_view);
this.server.respond();
this.proctored_exam_view.updateRemainingTime(this.proctored_exam_view);
expect(reloadPage).toHaveBeenCalled();
});
});
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