From b3782c71bfce8b0be00e7a3c4ba2abf40abc81fa Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Fri, 15 Apr 2011 18:26:35 +0100 Subject: [PATCH] MDL-20636 My go and creating a renderer for mod/quiz/review.php. Note that this breaks the attempt.php page; there are a lot of methods that are missing PHPdoc comment; there are probably now some unused methods that could be deleted; and there are a couple of places which could be handled a bit better. But, overall, I think this way makes sense. --- mod/quiz/attemptlib.php | 212 +++++++++++++++++------------------------ mod/quiz/module.js | 6 ++ mod/quiz/renderer.php | 248 ++++++++++++++++++++++++++++++++++++++++++++++++ mod/quiz/review.php | 195 ++++++++++++++++++------------------- 4 files changed, 431 insertions(+), 230 deletions(-) create mode 100644 mod/quiz/renderer.php diff --git a/mod/quiz/attemptlib.php b/mod/quiz/attemptlib.php index 0c830d1a907..008f18fe2b9 100644 --- a/mod/quiz/attemptlib.php +++ b/mod/quiz/attemptlib.php @@ -1,5 +1,4 @@ attempt->userid == $USER->id && + $this->is_preview_user() && $this->attempt->preview; + } + + /** * Is the current user allowed to review this attempt. This applies when * {@link is_own_attempt()} returns false. * @return bool whether the review should be allowed. @@ -862,15 +870,6 @@ class quiz_attempt { } /** - * Return the HTML of the quiz timer. - * @return string HTML content. - */ - public function get_timer_html() { - return '
' . get_string('timeleft', 'quiz') . - '
'; - } - - /** * Generate the HTML that displayes the question in its current state, with * the appropriate display options. * @@ -945,34 +944,39 @@ class quiz_attempt { * @param $showall whether we are showing the whole quiz on one page. (Used by review.php) * @return quiz_nav_panel_base the requested object. */ - public function get_navigation_panel($panelclass, $page, $showall = false) { + public function get_navigation_panel(mod_quiz_renderer $output, + $panelclass, $page, $showall = false) { $panel = new $panelclass($this, $this->get_display_options(true), $page, $showall); - return $panel->get_contents(); + + $bc = new block_contents(); + $bc->id = 'quiznavigation'; + $bc->title = get_string('quiznavigation', 'quiz'); + $bc->content = $output->navigation_panel($panel); + return $bc; } /** * Given a URL containing attempt={this attempt id}, return an array of variant URLs - * @param $url a URL. + * @param moodle_url $url a URL. * @return string HTML fragment. Comma-separated list of links to the other * attempts with the attempt number as the link text. The curent attempt is * included but is not a link. */ - public function links_to_other_attempts($url) { - $search = '/\battempt=' . $this->attempt->id . '\b/'; + public function links_to_other_attempts(moodle_url $url) { $attempts = quiz_get_user_attempts($this->get_quiz()->id, $this->attempt->userid, 'all'); if (count($attempts) <= 1) { return false; } - $attemptlist = array(); + + $links = new mod_quiz_links_to_other_attempts(); foreach ($attempts as $at) { if ($at->id == $this->attempt->id) { - $attemptlist[] = '' . $at->attempt . ''; + $links->links[$at->attempt] = null; } else { - $changedurl = preg_replace($search, 'attempt=' . $at->id, $url); - $attemptlist[] = '' . $at->attempt . ''; + $links->links[$at->attempt] = new moodle_url($url, array('attempt' => $at->id)); } } - return implode(', ', $attemptlist); + return $links; } // Methods for processing ================================================== @@ -1101,6 +1105,24 @@ class quiz_attempt { /** + * Represents a single link in the navigation panel. + * + * @copyright 2011 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.1 + */ +class quiz_nav_question_button implements renderable { + public $id; + public $number; + public $stateclass; + public $statestring; + public $currentpage; + public $flagged; + public $url; +} + + +/** * Represents the navigation panel, and builds a {@link block_contents} to allow * it to be output. * @@ -1126,113 +1148,49 @@ abstract class quiz_nav_panel_base { $this->showall = $showall; } - protected function get_question_buttons() { - $html = '
' . "\n"; + public function get_question_buttons() { + $buttons = array(); foreach ($this->attemptobj->get_slots() as $slot) { $qa = $this->attemptobj->get_question_attempt($slot); $showcorrectness = $this->options->correctness && $qa->has_marks(); - $html .= $this->get_question_button($qa, $qa->get_question()->_number, - $showcorrectness) . "\n"; - } - $html .= "
\n"; - return $html; - } - - protected function get_button_id(question_attempt $qa) { - // The id to put on the button element in the HTML. - return 'quiznavbutton' . $qa->get_slot(); - } - - protected function get_question_button(question_attempt $qa, $number, $showcorrectness) { - $attributes = $this->get_attributes($qa, $showcorrectness); - if (is_numeric($number)) { - $qnostring = 'questionnonav'; - } else { - $qnostring = 'questionnonavinfo'; - } - - $a = new stdClass(); - $a->number = $number; - $a->attributes = implode(' ', $attributes); - - return '' . - '' . - get_string($qnostring, 'quiz', $a) . ''; - } - - /** - * @param question_attempt $qa - * @param bool $showcorrectness - * @return array class name => descriptive string. - */ - protected function get_attributes(question_attempt $qa, $showcorrectness) { - // The current status of the question. - $attributes = array(); - - // On the current page? - if ($qa->get_question()->_page == $this->page) { - $attributes['thispage'] = get_string('onthispage', 'quiz'); - } - - // Question state. - $stateclass = $qa->get_state()->get_state_class($showcorrectness); - if (!$showcorrectness && $stateclass == 'notanswered') { - $stateclass = 'complete'; - } - $attributes[$stateclass] = $qa->get_state_string($showcorrectness); - - // Flagged? - if ($qa->is_flagged()) { - $attributes['flagged'] = '' . - get_string('flagged', 'question') . ''; - } else { - $attributes[''] = ''; + $button = new quiz_nav_question_button(); + $button->id = 'quiznavbutton' . $slot; + $button->number = $qa->get_question()->_number; + $button->stateclass = $qa->get_state()->get_state_class($showcorrectness); + if (!$showcorrectness && $button->stateclass == 'notanswered') { + $button->stateclass = 'complete'; + } + $button->statestring = $qa->get_state_string($showcorrectness); + $button->currentpage = $qa->get_question()->_page == $this->page; + $button->flagged = $qa->is_flagged(); + $button->url = $this->get_question_url($slot); + $buttons[] = $button; } - return $attributes; + return $buttons; } - protected function get_before_button_bits() { + public function render_before_button_bits(mod_quiz_renderer $output) { return ''; } - protected abstract function get_end_bits(); + public function render_end_bits(mod_quiz_renderer $output) { + if (!$this->attemptobj->is_own_preview()) { + return ''; + } + return $output->restart_preview_button(new moodle_url( + $this->attemptobj->start_attempt_url(), array('forcenew' => true))); + } protected abstract function get_question_url($slot); - protected function get_user_picture() { - global $DB, $OUTPUT; + public function user_picture() { + global $DB; $user = $DB->get_record('user', array('id' => $this->attemptobj->get_userid())); - $output = ''; - $output .= '
'; - $output .= $OUTPUT->user_picture($user, array('courseid'=>$this->attemptobj->get_courseid())); - $output .= ' ' . fullname($user); - $output .= '
'; - return $output; - } - - public function get_contents() { - global $PAGE; - $PAGE->requires->js_init_call('M.mod_quiz.nav.init', null, false, quiz_get_js_module()); - - $content = ''; - if (!empty($this->attemptobj->get_quiz()->showuserpicture)) { - $content .= $this->get_user_picture() . "\n"; - } - $content .= $this->get_before_button_bits(); - $content .= $this->get_question_buttons() . "\n"; - $content .= '
' . "\n" . $this->get_end_bits() . - $this->attemptobj->restart_preview_button() . "\n
\n"; - - $bc = new block_contents(); - $bc->id = 'quiznavigation'; - $bc->title = get_string('quiznavigation', 'quiz'); - $bc->content = $content; - return $bc; + $userpicture = new user_picture($user); + $userpicture->courseid = $this->attemptobj->get_courseid(); + return $userpicture; } } @@ -1245,20 +1203,19 @@ abstract class quiz_nav_panel_base { * @since Moodle 2.0 */ class quiz_attempt_nav_panel extends quiz_nav_panel_base { - protected function get_question_url($slot) { + public function get_question_url($slot) { return $this->attemptobj->attempt_url($slot, -1, $this->page); } - protected function get_before_button_bits() { - return '
' . get_string('navnojswarning', 'quiz') . "
\n"; + public function render_before_button_bits(mod_quiz_renderer $output) { + return html_writer::tag('div', get_string('navnojswarning', 'quiz'), + array('id' => 'quiznojswarning')); } - protected function get_end_bits() { - global $PAGE; - $output = ''; - $output .= '' . get_string('endtest', 'quiz') . ''; - $output .= $this->attemptobj->get_timer_html(); - return $output; + public function render_end_bits(mod_quiz_renderer $output) { + return html_writer::link($this->attemptobj->summary_url(), + get_string('endtest', 'quiz'), array('id' => 'endtestlink')) . + $output->countdown_timer(); } } @@ -1271,21 +1228,22 @@ class quiz_attempt_nav_panel extends quiz_nav_panel_base { * @since Moodle 2.0 */ class quiz_review_nav_panel extends quiz_nav_panel_base { - protected function get_question_url($slot) { + public function get_question_url($slot) { return $this->attemptobj->review_url($slot, -1, $this->showall, $this->page); } - protected function get_end_bits() { + public function render_end_bits(mod_quiz_renderer $output) { $html = ''; if ($this->attemptobj->get_num_pages() > 1) { if ($this->showall) { - $html .= '' . get_string('showeachpage', 'quiz') . ''; + $html .= html_writer::link($this->attemptobj->review_url(null, 0, false), + get_string('showeachpage', 'quiz')); } else { - $html .= '' . get_string('showall', 'quiz') . ''; + $html .= html_writer::link($this->attemptobj->review_url(null, 0, true), + get_string('showall', 'quiz')); } } - $accessmanager = $this->attemptobj->get_access_manager(time()); - $html .= $accessmanager->print_finish_review_link($this->attemptobj->is_preview_user(), true); + $html .= $output->finish_review_link($this->attemptobj->view_url()); return $html; } } diff --git a/mod/quiz/module.js b/mod/quiz/module.js index f119e328871..1f64df02307 100644 --- a/mod/quiz/module.js +++ b/mod/quiz/module.js @@ -216,6 +216,12 @@ M.mod_quiz.secure_window = { e.halt(); }, + init_close_button: function(Y, url) { + Y.on('click', function(e) { + M.mod_quiz.secure_window.close(url, 0) + }, '#secureclosebutton'); + }, + close: function(url, delay) { setTimeout(function() { if (window.opener) { diff --git a/mod/quiz/renderer.php b/mod/quiz/renderer.php new file mode 100644 index 00000000000..75a862dd48f --- /dev/null +++ b/mod/quiz/renderer.php @@ -0,0 +1,248 @@ +. + +/** + * Defines the renderer for the quiz module. + * + * @package mod + * @subpackage quiz + * @copyright 2011 The Open University + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + + +/** + * The renderer for the quiz module. + * + * @copyright 2008 onwards Tim Hunt + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class mod_quiz_renderer extends plugin_renderer_base { + public function review_page(quiz_attempt $attemptobj, $slots, $page, $showall, + $lastpage, mod_quiz_display_options $displayoptions, $summarydata) { + + $output = ''; + $output .= $this->header(); + $output .= $this->review_summary_table($summarydata, $page); + $output .= $this->review_form($page, $showall, $displayoptions, + $this->questions($attemptobj, true, $slots, $page, $showall, $displayoptions)); + + $output .= $this->review_next_navigation($attemptobj, $page, $lastpage); + $output .= $this->footer(); + return $output; + } + + protected function filter_summary_table($summarydata, $page) { + if ($page == 0) { + return $summarydata; + } + + // Only show some of summary table on subsequent pages. + foreach ($summarydata as $key => $rowdata) { + if (!in_array($key, array('user', 'attemptlist'))) { + unset($summarydata[$key]); + } + } + + return $summarydata; + } + + public function review_summary_table($summarydata, $page) { + $summarydata = $this->filter_summary_table($summarydata, $page); + if (empty($summarydata)) { + return ''; + } + + $output = ''; + $output .= html_writer::start_tag('table', array( + 'class' => 'generaltable generalbox quizreviewsummary')); + $output .= html_writer::start_tag('tbody'); + foreach ($summarydata as $rowdata) { + if ($rowdata['title'] instanceof renderable) { + $title = $this->render($rowdata['title']); + } else { + $title = $rowdata['title']; + } + + if ($rowdata['content'] instanceof renderable) { + $content = $this->render($rowdata['content']); + } else { + $content = $rowdata['content']; + } + + $output .= html_writer::tag('tr', + html_writer::tag('th', $title, array('class' => 'cell', 'scope' => 'row')) . + html_writer::tag('td', $content, array('class' => 'cell')) + ); + } + + $output .= html_writer::end_tag('tbody'); + $output .= html_writer::end_tag('table'); + return $output; + } + + public function questions(quiz_attempt $attemptobj, $reviewing, $slots, $page, $showall, + mod_quiz_display_options $displayoptions) { + $output = ''; + foreach ($slots as $slot) { + $output .= $attemptobj->render_question($slot, $reviewing, + $attemptobj->review_url($slot, $page, $showall)); + } + return $output; + } + + public function review_form($summarydata, $page, $displayoptions, $content) { + if ($displayoptions->flags != question_display_options::EDITABLE) { + return $content; + } + + $this->page->requires->js_init_call('M.mod_quiz.init_review_form', null, false, quiz_get_js_module()); + + // TODO fix this to use html_writer. + $output = ''; + $output .= '
'; + $output .= ''; + $output .= $content; + $output .= '
' . "\n" . + '' . + "
\n" . + "\n
\n"; + + return $output; + } + + public function finish_review_link($url) { + if ($this->page->pagelayout == 'popup') { + // In a 'secure' popup window. + $this->page->requires->js_init_call('M.mod_quiz.secure_window.init_close_button', + array($url), quiz_get_js_module()); + return html_writer::empty_tag('input', array('type' => 'button', + 'value' => get_string('finishreview', 'quiz'), + 'id' => 'secureclosebutton')); + } else { + return html_writer::link($url, get_string('finishreview', 'quiz')); + } + + } + + public function review_next_navigation(quiz_attempt $attemptobj, $page, $lastpage) { + if ($lastpage) { + $nav = $this->finish_review_link($attemptobj->view_url()); + } else { + $nav = link_arrow_right(get_string('next'), $attemptobj->review_url(0, $page + 1)); + } + return html_writer::tag('div', $nav, array('class' => 'submitbtns')); + } + + /** + * Return the HTML of the quiz timer. + * @return string HTML content. + */ + public function countdown_timer() { + return html_writer::tag('div', get_string('timeleft', 'quiz') . + html_writer::tag('span', '', array('id' => 'quiz-time-left')), + array('id' => 'quiz-timer')); + } + + public function restart_preview_button($url) { + return $this->single_button($url, get_string('startnewpreview', 'quiz')); + } + + public function navigation_panel(quiz_nav_panel_base $panel) { + + $output = ''; + $userpicture = $panel->user_picture(); + if ($userpicture) { + $output .= html_writer::tag('div', $this->render($userpicture), + array('id' => 'user-picture', 'class' => 'clearfix')); + } + $output .= $panel->render_before_button_bits($this); + + $output = html_writer::start_tag('div', array('class' => 'qn_buttons')); + foreach ($panel->get_question_buttons() as $button) { + $output .= $this->render($button); + } + $output .= html_writer::end_tag('div'); + + $output .= html_writer::tag('div', $panel->render_end_bits($this), + array('class' => 'othernav')); + + $this->page->requires->js_init_call('M.mod_quiz.nav.init', null, false, quiz_get_js_module()); + + return $output; + } + + protected function render_quiz_nav_question_button(quiz_nav_question_button $button) { + $classes = array('qnbutton', $button->stateclass); + $attributes = array(); + + if ($button->currentpage) { + $classes[] = 'thispage'; + $attributes[] = get_string('onthispage', 'quiz'); + } + + $attributes[] = $button->statestring; + + // Flagged? + if ($button->flagged) { + $classes[] = 'flagged'; + $flaglabel = get_string('flagged', 'question'); + } else { + $flaglabel = ''; + } + $attributes[] = html_writer::tag('span', $flaglabel, array('class' => 'flagstate')); + + if (is_numeric($button->number)) { + $qnostring = 'questionnonav'; + } else { + $qnostring = 'questionnonavinfo'; + } + + $a = new stdClass(); + $a->number = $button->number; + $a->attributes = implode(' ', $attributes); + + return html_writer::link($button->url, + html_writer::tag('span', '', array('class' => 'thispageholder')) . + html_writer::tag('span', '', array('class' => 'trafficlight')) . + get_string($qnostring, 'quiz', $a), + array('class' => implode(' ', $classes), 'id' => $button->id, + 'title' => $button->statestring)); + } + + protected function render_mod_quiz_links_to_other_attempts( + mod_quiz_links_to_other_attempts $links) { + $attemptlinks = array(); + foreach ($links->links as $attempt => $url) { + if ($url) { + $attemptlinks[] = html_writer::link($url, $attempt); + } else { + $attemptlinks[] = html_writer::tag('strong', $attempt); + } + } + return implode(', ', $attemptlinks); + } +} + + +class mod_quiz_links_to_other_attempts implements renderable { + /** + * @var array string attempt number => url, or null for the current attempt. + */ + public $links = array(); +} \ No newline at end of file diff --git a/mod/quiz/review.php b/mod/quiz/review.php index fbce4af15d9..9310fe2bf9b 100644 --- a/mod/quiz/review.php +++ b/mod/quiz/review.php @@ -1,5 +1,4 @@ is_preview_user() && $attemptobj->is_own_attempt()) { } } -// Arrange for the navigation to be displayed. -$navbc = $attemptobj->get_navigation_panel('quiz_review_nav_panel', $page, $showall); -$firstregion = reset($PAGE->blocks->get_regions()); -$PAGE->blocks->add_fake_block($navbc, $firstregion); - -// Print the page header +// Set up the page header $headtags = $attemptobj->get_html_head_contributions($page, $showall); if ($accessmanager->securewindow_required($attemptobj->is_preview_user())) { $accessmanager->setup_secure_page($attemptobj->get_course()->shortname.': '.format_string($attemptobj->get_quiz_name()), $headtags); -} elseif ($accessmanager->safebrowser_required($attemptobj->is_preview_user())) { +} else if ($accessmanager->safebrowser_required($attemptobj->is_preview_user())) { $PAGE->set_title($attemptobj->get_course()->shortname . ': '.format_string($attemptobj->get_quiz_name())); $PAGE->set_heading($attemptobj->get_course()->fullname); $PAGE->set_cacheable(false); - echo $OUTPUT->header(); } else { $PAGE->navbar->add($strreviewtitle); $PAGE->set_title(format_string($attemptobj->get_quiz_name())); $PAGE->set_heading($attemptobj->get_course()->fullname); - echo $OUTPUT->header(); } // Summary table start ============================================================================ @@ -128,7 +120,7 @@ $overtime = 0; if ($attempt->timefinish) { if ($timetaken = ($attempt->timefinish - $attempt->timestart)) { - if($quiz->timelimit && $timetaken > ($quiz->timelimit + 60)) { + if ($quiz->timelimit && $timetaken > ($quiz->timelimit + 60)) { $overtime = $timetaken - $quiz->timelimit; $overtime = format_time($overtime); } @@ -143,126 +135,123 @@ if ($attempt->timefinish) { // Print summary table about the whole attempt. // First we assemble all the rows that are appopriate to the current situation in // an array, then later we only output the table if there are any rows to show. -$rows = array(); +$summarydata = array(); if (!$attemptobj->get_quiz()->showuserpicture && $attemptobj->get_userid() != $USER->id) { // If showuserpicture is true, the picture is shown elsewhere, so don't repeat it. $student = $DB->get_record('user', array('id' => $attemptobj->get_userid())); - $picture = $OUTPUT->user_picture($student, array('courseid'=>$attemptobj->get_courseid())); - $rows[] = '' . $picture . '' . - fullname($student, true) . ''; + $usrepicture = new user_picture($student); + $usrepicture->courseid = $attemptobj->get_courseid(); + $summarydata['user'] = array( + 'title' => $usrepicture, + 'content' => new action_link(new moodle_url('/user/view.php', array( + 'id' => $student->id, 'course' => $attemptobj->get_courseid())), + fullname($student, true)), + ); } if ($attemptobj->has_capability('mod/quiz:viewreports')) { $attemptlist = $attemptobj->links_to_other_attempts($attemptobj->review_url(0, $page, $showall)); if ($attemptlist) { - $rows[] = '' . get_string('attempts', 'quiz') . - '' . $attemptlist . ''; + $summarydata['attemptlist'] = array( + 'title' => get_string('attempts', 'quiz'), + 'content' => $attemptlist, + ); } } -if ($page == 0) { - // Timing information. - $rows[] = '' . get_string('startedon', 'quiz') . - '' . userdate($attempt->timestart) . ''; - if ($attempt->timefinish) { - $rows[] = '' . get_string('completedon', 'quiz') . '' . - userdate($attempt->timefinish) . ''; - $rows[] = '' . get_string('timetaken', 'quiz') . '' . - $timetaken . ''; - } - if (!empty($overtime)) { - $rows[] = '' . get_string('overdue', 'quiz') . '' . $overtime . ''; - } +// Timing information. +$summarydata['startedon'] = array( + 'title' => get_string('startedon', 'quiz'), + 'content' => userdate($attempt->timestart), +); - // Show marks (if the user is allowed to see marks at the moment). - $grade = quiz_rescale_grade($attempt->sumgrades, $quiz, false); - if ($options->marks >= question_display_options::MARK_AND_MAX && quiz_has_grades($quiz)) { +if ($attempt->timefinish) { + $summarydata['completedon'] = array( + 'title' => get_string('completedon', 'quiz'), + 'content' => userdate($attempt->timefinish), + ); + $summarydata['timetaken'] = array( + 'title' => get_string('timetaken', 'quiz'), + 'content' => userdate($timetaken), + ); +} - if (!$attempt->timefinish) { - $rows[] = '' . get_string('grade') . '' . - get_string('attemptstillinprogress', 'quiz') . ''; +if (!empty($overtime)) { + $summarydata['overdue'] = array( + 'title' => get_string('overdue', 'quiz'), + 'content' => userdate($overtime), + ); +} - } else if (is_null($grade)) { - $rows[] = '' . get_string('grade') . '' . - quiz_format_grade($quiz, $grade) . ''; +// Show marks (if the user is allowed to see marks at the moment). +$grade = quiz_rescale_grade($attempt->sumgrades, $quiz, false); +if ($options->marks >= question_display_options::MARK_AND_MAX && quiz_has_grades($quiz)) { - } else { - // Show raw marks only if they are different from the grade (like on the view page). - if ($quiz->grade != $quiz->sumgrades) { - $a = new stdClass(); - $a->grade = quiz_format_grade($quiz, $attempt->sumgrades); - $a->maxgrade = quiz_format_grade($quiz, $quiz->sumgrades); - $rows[] = '' . get_string('marks', 'quiz') . '' . - get_string('outofshort', 'quiz', $a) . ''; - } - - // Now the scaled grade. + if (!$attempt->timefinish) { + $summarydata['grade'] = array( + 'title' => get_string('grade', 'quiz'), + 'content' => get_string('attemptstillinprogress', 'quiz'), + ); + + } else if (is_null($grade)) { + $summarydata['grade'] = array( + 'title' => get_string('grade', 'quiz'), + 'content' => quiz_format_grade($quiz, $grade), + ); + + } else { + // Show raw marks only if they are different from the grade (like on the view page). + if ($quiz->grade != $quiz->sumgrades) { $a = new stdClass(); - $a->grade = '' . quiz_format_grade($quiz, $grade) . ''; - $a->maxgrade = quiz_format_grade($quiz, $quiz->grade); - if ($quiz->grade != 100) { - $a->percent = '' . round($attempt->sumgrades * 100 / $quiz->sumgrades, 0) . ''; - $formattedgrade = get_string('outofpercent', 'quiz', $a); - } else { - $formattedgrade = get_string('outof', 'quiz', $a); - } - $rows[] = '' . get_string('grade') . '' . - $formattedgrade . ''; + $a->grade = quiz_format_grade($quiz, $attempt->sumgrades); + $a->maxgrade = quiz_format_grade($quiz, $quiz->sumgrades); + $summarydata['marks'] = array( + 'title' => get_string('marks', 'quiz'), + 'content' => get_string('outofshort', 'quiz', $a), + ); } - } - // Feedback if there is any, and the user is allowed to see it now. - $feedback = $attemptobj->get_overall_feedback($grade); - if ($options->overallfeedback && $feedback) { - $rows[] = '' . get_string('feedback', 'quiz') . - '' . $feedback . ''; + // Now the scaled grade. + $a = new stdClass(); + $a->grade = html_writer::tag('b', quiz_format_grade($quiz, $grade)); + $a->maxgrade = quiz_format_grade($quiz, $quiz->grade); + if ($quiz->grade != 100) { + $a->percent = html_writer::tag('b', format_float( + $attempt->sumgrades * 100 / $quiz->sumgrades, 0)); + $formattedgrade = get_string('outofpercent', 'quiz', $a); + } else { + $formattedgrade = get_string('outof', 'quiz', $a); + } + $summarydata['grade'] = array( + 'title' => get_string('grade', 'quiz'), + 'content' => $formattedgrade, + ); } } -// Now output the summary table, if there are any rows to be shown. -if (!empty($rows)) { - echo '', "\n"; - echo implode("\n", $rows); - echo "\n
\n"; +// Feedback if there is any, and the user is allowed to see it now. +$feedback = $attemptobj->get_overall_feedback($grade); +if ($options->overallfeedback && $feedback) { + $summarydata['feedback'] = array( + 'title' => get_string('feedback', 'quiz'), + 'content' => $feedback, + ); } // Summary table end ============================================================================== -// Form for saving flags if necessary. -if ($options->flags == question_display_options::EDITABLE) { - echo '
'; - echo ''; -} - -// Print all the questions. if ($showall) { - $thispage = 'all'; + $slots = $attemptobj->get_slots(); $lastpage = true; } else { - $thispage = $page; + $slots = $attemptobj->get_slots($page); $lastpage = $attemptobj->is_last_page($page); } -foreach ($attemptobj->get_slots($thispage) as $slot) { - echo $attemptobj->render_question($slot, true, $attemptobj->review_url($slot, $page, $showall)); -} -// Close form if we opened it. -if ($options->flags == question_display_options::EDITABLE) { - echo '
' . "\n" . - '' . - "
\n" . - "\n
\n"; - $PAGE->requires->js_init_call('M.mod_quiz.init_review_form', null, false, quiz_get_js_module()); -} +$output = $PAGE->get_renderer('mod_quiz'); -// Print a link to the next page. -echo '
'; -if ($lastpage) { - $accessmanager->print_finish_review_link($attemptobj->is_preview_user()); -} else { - echo link_arrow_right(get_string('next'), $attemptobj->review_url(0, $page + 1)); -} -echo '
'; -echo $OUTPUT->footer(); +// Arrange for the navigation to be displayed. +$navbc = $attemptobj->get_navigation_panel($output, 'quiz_review_nav_panel', $page, $showall); +$firstregion = reset($PAGE->blocks->get_regions()); +$PAGE->blocks->add_fake_block($navbc, $firstregion); + +echo $output->review_page($attemptobj, $slots, $page, $showall, $lastpage, $options, $summarydata); -- 2.11.4.GIT