MDL-3030 quiz overdue handling: display message on the summary page.

This change also includes a clean-up of how we display and initialise the countdown timer.
This commit is contained in:
Tim Hunt 2011-11-15 17:25:26 +00:00
parent 2de9be52aa
commit 2b2b645842
7 changed files with 67 additions and 45 deletions

View File

@ -410,25 +410,6 @@ class quiz_access_manager {
return $timeleft;
}
/**
* Will cause the attempt time to start counting down after the page has loaded,
* if that is necessary.
*
* @param object $attempt the data from the relevant quiz_attempts row.
* @param int $timenow the time to consider as 'now'.
* @param mod_quiz_renderer $output the quiz renderer.
*/
public function show_attempt_timer_if_needed($attempt, $timenow, $output) {
$timeleft = $this->get_time_left($attempt, $timenow);
if ($timeleft !== false) {
// Make sure the timer starts just above zero. If $timeleft was <= 0, then
// this will just have the effect of causing the quiz to be submitted immediately.
$timerstartvalue = max($timeleft, 1);
$output->initialise_timer($timerstartvalue);
}
}
/**
* @return bolean if this quiz should only be shown to students in a popup window.
*/

View File

@ -126,5 +126,4 @@ if ($attemptobj->is_last_page($page)) {
$nextpage = $page + 1;
}
$accessmanager->show_attempt_timer_if_needed($attemptobj->get_attempt(), time(), $output);
echo $output->attempt_page($attemptobj, $page, $accessmanager, $messages, $slots, $id, $nextpage);

View File

@ -945,6 +945,19 @@ class quiz_attempt {
return $this->quba->get_question_action_time($slot);
}
/**
* Get the time remaining for an in-progress attempt, if the time is short
* enought that it would be worth showing a timer.
* @param int $timenow the time to consider as 'now'.
* @return int|false the number of seconds remaining for this attempt.
* False if there is no limit.
*/
public function get_time_left($timenow) {
if ($this->attempt->state != self::IN_PROGRESS) {
return false;
}
return $this->get_access_manager($timenow)->get_time_left($this->attempt, $timenow);
}
/**
* @return int the time when this attempt was submitted. 0 if it has not been
@ -959,23 +972,29 @@ class quiz_attempt {
* student should next do something.
* @return int timestamp by which the student needs to do something.
*/
function get_due_date($timenow) {
function get_due_date() {
$deadlines = array();
if ($this->quizobj->get_quiz()->timelimit) {
$deadlines[] = $this->attempt->timestart + $this->quizobj->get_quiz()->timelimit;
}
if ($this->quizobj->get_quiz()->timeclose) {
$deadlines[] = $this->quizobj->get_quiz()->timeclose;
}
if ($deadlines) {
$duedate = min($deadlines);
} else {
return false;
}
switch ($attempt->state) {
switch ($this->attempt->state) {
case self::IN_PROGRESS:
$timeleft = $this->get_access_manager($timenow)->get_time_left(
$this->attempt, $timenow);
if ($timeleft === false) {
return false;
} else {
return $timenow + $timeleft;
}
return $duedate;
case self::OVERDUE:
return $this->attempt->timefinished + $this->quizobj->get_quiz()->graceperiod;
return $duedate + $this->quizobj->get_quiz()->graceperiod;
default:
throw new coding_exception('Unexpected state: ' . $attempt->state);
throw new coding_exception('Unexpected state: ' . $this->attempt->state);
}
}
@ -1473,7 +1492,7 @@ class quiz_attempt_nav_panel extends quiz_nav_panel_base {
public function render_end_bits(mod_quiz_renderer $output) {
return html_writer::link($this->attemptobj->summary_url(),
get_string('endtest', 'quiz'), array('class' => 'endtestlink')) .
$output->countdown_timer() .
$output->countdown_timer($this->attemptobj, time()) .
$this->render_restart_preview_link($output);
}
}

View File

@ -418,6 +418,7 @@ $string['moveselectedonpage'] = 'Move selected questions to page: {$a}';
$string['multichoice'] = 'Multiple choice';
$string['multipleanswers'] = 'Choose at least one answer.';
$string['multiplier'] = 'Multiplier';
$string['mustbesubmittedby'] = 'This attempt must be submitted by {$a}.';
$string['name'] = 'Name';
$string['navmethod'] = 'Navigation method';
$string['navmethod_free'] = 'Free';
@ -496,6 +497,7 @@ $string['overduehandling_desc'] = 'What should happen by default if a student do
$string['overduehandlingautosubmit'] = 'the attempt is submitted automatically';
$string['overduehandlinggraceperiod'] = 'there is a grace period in which to submit the attempt, but not answer more questions';
$string['overduehandlingautoabandon'] = 'that is it. The attempt must be submitted before time expires, or it is not counted';
$string['overduemustbesubmittedby'] = 'This attempt is now overdue. It should already have been submitted. If you would like this quiz to be graded, you must submit it by {$a}. If you not submit it by then, no marks from this attempt will be counted.';
$string['override'] = 'Override';
$string['overridedeletegroupsure'] = 'Are you sure you want to delete the override for group {$a}?';
$string['overridedeleteusersure'] = 'Are you sure you want to delete the override for user {$a}?';

View File

@ -96,7 +96,11 @@ M.mod_quiz.timer = {
Y.one('#quiz-time-left').setContent(M.str.quiz.timesup);
var input = Y.one('input[name=timeup]');
input.set('value', 1);
input.ancestor('form').submit();
var form = input.ancestor('form');
if (form.one('input[name=finishattempt]')) {
form.one('input[name=finishattempt]').set('value', 0);
}
form.submit();
return;
}

View File

@ -261,7 +261,16 @@ class mod_quiz_renderer extends plugin_renderer_base {
* Return the HTML of the quiz timer.
* @return string HTML content.
*/
public function countdown_timer() {
public function countdown_timer(quiz_attempt $attemptobj, $timenow) {
$timeleft = $attemptobj->get_time_left($timenow);
if ($timeleft !== false) {
// Make sure the timer starts just above zero. If $timeleft was <= 0, then
// this will just have the effect of causing the quiz to be submitted immediately.
$timerstartvalue = max($timeleft, 1);
$this->initialise_timer($timerstartvalue);
}
return html_writer::tag('div', get_string('timeleft', 'quiz') . ' ' .
html_writer::tag('span', '', array('id' => 'quiz-time-left')),
array('id' => 'quiz-timer'));
@ -604,8 +613,6 @@ class mod_quiz_renderer extends plugin_renderer_base {
*/
public function summary_page_controls($attemptobj) {
$output = '';
// countdown timer
$output .= $this->countdown_timer();
// Return to place button
$button = new single_button(
@ -626,11 +633,23 @@ class mod_quiz_renderer extends plugin_renderer_base {
new moodle_url($attemptobj->processattempt_url(), $options),
get_string('submitallandfinish', 'quiz'));
$button->id = 'responseform';
$button->add_action(new confirm_action(get_string('confirmclose', 'quiz'), null,
get_string('submitallandfinish', 'quiz')));
if ($attemptobj->get_state() == quiz_attempt::IN_PROGRESS) {
$button->add_action(new confirm_action(get_string('confirmclose', 'quiz'), null,
get_string('submitallandfinish', 'quiz')));
}
$output .= $this->container($this->container($this->render($button),
'controls'), 'submitbtns mdl-align');
$duedate = $attemptobj->get_due_date();
$message = '';
if ($attemptobj->get_state() == quiz_attempt::OVERDUE) {
$message = get_string('overduemustbesubmittedby', 'quiz', userdate($duedate));
} else if ($duedate) {
$message = get_string('mustbesubmittedby', 'quiz', userdate($duedate));
}
$output .= $this->countdown_timer($attemptobj, time());
$output .= $this->container($message . $this->container(
$this->render($button), 'controls'), 'submitbtns mdl-align');
return $output;
}
@ -911,7 +930,7 @@ class mod_quiz_renderer extends plugin_renderer_base {
}
}
$row[] = $this->attempt_state($attemptobj, $viewobj->timenow);
$row[] = $this->attempt_state($attemptobj);
if ($viewobj->markcolumn) {
if ($attemptoptions->marks >= question_display_options::MARK_AND_MAX &&
@ -975,7 +994,7 @@ class mod_quiz_renderer extends plugin_renderer_base {
* @param int $timenow the time to use as 'now'.
* @return string the appropriate lang string to describe the state.
*/
public function attempt_state($attemptobj, $timenow) {
public function attempt_state($attemptobj) {
switch ($attemptobj->get_state()) {
case quiz_attempt::IN_PROGRESS:
return get_string('stateinprogress', 'quiz');
@ -983,7 +1002,7 @@ class mod_quiz_renderer extends plugin_renderer_base {
case quiz_attempt::OVERDUE:
return get_string('stateoverdue', 'quiz') . html_writer::tag('span',
get_string('stateoverduedetails', 'quiz',
userdate($attemptobj->get_due_date($timenow))),
userdate($attemptobj->get_due_date())),
array('class' => 'statedetails'));
case quiz_attempt::FINISHED:

View File

@ -89,6 +89,4 @@ $PAGE->set_heading($attemptobj->get_course()->fullname);
$accessmanager->setup_attempt_page($PAGE);
// Display the page.
$accessmanager->show_attempt_timer_if_needed($attemptobj->get_attempt(), time(), $output);
echo $output->summary_page($attemptobj, $displayoptions);