Comparing sensitive data, confidential files or internal emails?

Most legal and privacy policies prohibit uploading sensitive data online. Diffchecker Desktop ensures your confidential information never leaves your computer. Work offline and compare documents securely.

Untitled diff

Created Diff never expires
56 removals
641 lines
70 additions
654 lines
<?php
<?php
//Original Moodle 2.7.2 /mod/quiz/renderer.php
//Modified Moodle 2.7.2 /mod/quiz/renderer.php
// This file is part of Moodle - http://moodle.org/
// This file is part of Moodle - http://moodle.org/
//
//
// Moodle is free software: you can redistribute it and/or modify
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// (at your option) any later version.
//
//
// Moodle is distributed in the hope that it will be useful,
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// GNU General Public License for more details.
//
//
// You should have received a copy of the GNU General Public License
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.


/**
/**
* Defines the renderer for the quiz module.
* Defines the renderer for the quiz module.
*
*
* @package mod_quiz
* @package mod_quiz
* @copyright 2011 The Open University
* @copyright 2011 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
*/




defined('MOODLE_INTERNAL') || die();
defined('MOODLE_INTERNAL') || die();




/**
/**
* The renderer for the quiz module.
* The renderer for the quiz module.
*
*
* @copyright 2011 The Open University
* @copyright 2011 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
*/
class mod_quiz_renderer extends plugin_renderer_base {
class mod_quiz_renderer extends plugin_renderer_base {
/**
/**
* Builds the review page
* Builds the review page
*
*
* @param quiz_attempt $attemptobj an instance of quiz_attempt.
* @param quiz_attempt $attemptobj an instance of quiz_attempt.
* @param array $slots an array of intgers relating to questions.
* @param array $slots an array of intgers relating to questions.
* @param int $page the current page number
* @param int $page the current page number
* @param bool $showall whether to show entire attempt on one page.
* @param bool $showall whether to show entire attempt on one page.
* @param bool $lastpage if true the current page is the last page.
* @param bool $lastpage if true the current page is the last page.
* @param mod_quiz_display_options $displayoptions instance of mod_quiz_display_options.
* @param mod_quiz_display_options $displayoptions instance of mod_quiz_display_options.
* @param array $summarydata contains all table data
* @param array $summarydata contains all table data
* @return $output containing html data.
* @return $output containing html data.
*/
*/
public function review_page(quiz_attempt $attemptobj, $slots, $page, $showall,
public function review_page(quiz_attempt $attemptobj, $slots, $page, $showall,
$lastpage, mod_quiz_display_options $displayoptions,
$lastpage, mod_quiz_display_options $displayoptions,
$summarydata) {
$summarydata) {


$output = '';
$output = '';
$output .= $this->header();
$output .= $this->header();
$output .= $this->review_summary_table($summarydata, $page);
$output .= $this->review_summary_table($summarydata, $page);
$output .= $this->review_form($page, $showall, $displayoptions,
$output .= $this->review_form($page, $showall, $displayoptions,
$this->questions($attemptobj, true, $slots, $page, $showall, $displayoptions),
$this->questions($attemptobj, true, $slots, $page, $showall, $displayoptions),
$attemptobj);
$attemptobj);


$output .= $this->review_next_navigation($attemptobj, $page, $lastpage);
$output .= $this->review_next_navigation($attemptobj, $page, $lastpage);
$output .= $this->footer();
$output .= $this->footer();
return $output;
return $output;
}
}


/**
/**
* Renders the review question pop-up.
* Renders the review question pop-up.
*
*
* @param quiz_attempt $attemptobj an instance of quiz_attempt.
* @param quiz_attempt $attemptobj an instance of quiz_attempt.
* @param int $slot which question to display.
* @param int $slot which question to display.
* @param int $seq which step of the question attempt to show. null = latest.
* @param int $seq which step of the question attempt to show. null = latest.
* @param mod_quiz_display_options $displayoptions instance of mod_quiz_display_options.
* @param mod_quiz_display_options $displayoptions instance of mod_quiz_display_options.
* @param array $summarydata contains all table data
* @param array $summarydata contains all table data
* @return $output containing html data.
* @return $output containing html data.
*/
*/
public function review_question_page(quiz_attempt $attemptobj, $slot, $seq,
public function review_question_page(quiz_attempt $attemptobj, $slot, $seq,
mod_quiz_display_options $displayoptions, $summarydata) {
mod_quiz_display_options $displayoptions, $summarydata) {


$output = '';
$output = '';
$output .= $this->header();
$output .= $this->header();
$output .= $this->review_summary_table($summarydata, 0);
$output .= $this->review_summary_table($summarydata, 0);


if (!is_null($seq)) {
if (!is_null($seq)) {
$output .= $attemptobj->render_question_at_step($slot, $seq, true);
$output .= $attemptobj->render_question_at_step($slot, $seq, true);
} else {
} else {
$output .= $attemptobj->render_question($slot, true);
$output .= $attemptobj->render_question($slot, true);
}
}


$output .= $this->close_window_button();
$output .= $this->close_window_button();
$output .= $this->footer();
$output .= $this->footer();
return $output;
return $output;
}
}


/**
/**
* Renders the review question pop-up.
* Renders the review question pop-up.
*
*
* @param string $message Why the review is not allowed.
* @param string $message Why the review is not allowed.
* @return string html to output.
* @return string html to output.
*/
*/
public function review_question_not_allowed($message) {
public function review_question_not_allowed($message) {
$output = '';
$output = '';
$output .= $this->header();
$output .= $this->header();
$output .= $this->heading(format_string($attemptobj->get_quiz_name(), true,
$output .= $this->heading(format_string($attemptobj->get_quiz_name(), true,
array("context" => $attemptobj->get_quizobj()->get_context())));
array("context" => $attemptobj->get_quizobj()->get_context())));
$output .= $this->notification($message);
$output .= $this->notification($message);
$output .= $this->close_window_button();
$output .= $this->close_window_button();
$output .= $this->footer();
$output .= $this->footer();
return $output;
return $output;
}
}


/**
/**
* Filters the summarydata array.
* Filters the summarydata array.
*
*
* @param array $summarydata contains row data for table
* @param array $summarydata contains row data for table
* @param int $page the current page number
* @param int $page the current page number
* @return $summarydata containing filtered row data
* @return $summarydata containing filtered row data
*/
*/
protected function filter_review_summary_table($summarydata, $page) {
protected function filter_review_summary_table($summarydata, $page) {
if ($page == 0) {
if ($page == 0) {
return $summarydata;
return $summarydata;
}
}


// Only show some of summary table on subsequent pages.
// Only show some of summary table on subsequent pages.
foreach ($summarydata as $key => $rowdata) {
foreach ($summarydata as $key => $rowdata) {
if (!in_array($key, array('user', 'attemptlist'))) {
if (!in_array($key, array('user', 'attemptlist'))) {
unset($summarydata[$key]);
unset($summarydata[$key]);
}
}
}
}


return $summarydata;
return $summarydata;
}
}


/**
/**
* Outputs the table containing data from summary data array
* Outputs the table containing data from summary data array
*
*
* @param array $summarydata contains row data for table
* @param array $summarydata contains row data for table
* @param int $page contains the current page number
* @param int $page contains the current page number
*/
*/
public function review_summary_table($summarydata, $page) {
public function review_summary_table($summarydata, $page) {
$summarydata = $this->filter_review_summary_table($summarydata, $page);
$summarydata = $this->filter_review_summary_table($summarydata, $page);
if (empty($summarydata)) {
if (empty($summarydata)) {
return '';
return '';
}
}


$output = '';
$output = '';
$output .= html_writer::start_tag('table', array(
$output .= html_writer::start_tag('table', array(
'class' => 'generaltable generalbox quizreviewsummary'));
'class' => 'generaltable generalbox quizreviewsummary'));
$output .= html_writer::start_tag('tbody');
$output .= html_writer::start_tag('tbody');
foreach ($summarydata as $rowdata) {
foreach ($summarydata as $rowdata) {
if ($rowdata['title'] instanceof renderable) {
if ($rowdata['title'] instanceof renderable) {
$title = $this->render($rowdata['title']);
$title = $this->render($rowdata['title']);
} else {
} else {
$title = $rowdata['title'];
$title = $rowdata['title'];
}
}


if ($rowdata['content'] instanceof renderable) {
if ($rowdata['content'] instanceof renderable) {
$content = $this->render($rowdata['content']);
$content = $this->render($rowdata['content']);
} else {
} else {
$content = $rowdata['content'];
$content = $rowdata['content'];
}
}


$output .= html_writer::tag('tr',
$output .= html_writer::tag('tr',
html_writer::tag('th', $title, array('class' => 'cell', 'scope' => 'row')) .
html_writer::tag('th', $title, array('class' => 'cell', 'scope' => 'row')) .
html_writer::tag('td', $content, array('class' => 'cell'))
html_writer::tag('td', $content, array('class' => 'cell'))
);
);
}
}


$output .= html_writer::end_tag('tbody');
$output .= html_writer::end_tag('tbody');
$output .= html_writer::end_tag('table');
$output .= html_writer::end_tag('table');
return $output;
return $output;
}
}


/**
/**
* Renders each question
* Renders each question
*
*
* @param quiz_attempt $attemptobj instance of quiz_attempt
* @param quiz_attempt $attemptobj instance of quiz_attempt
* @param bool $reviewing
* @param bool $reviewing
* @param array $slots array of intgers relating to questions
* @param array $slots array of intgers relating to questions
* @param int $page current page number
* @param int $page current page number
* @param bool $showall if true shows attempt on single page
* @param bool $showall if true shows attempt on single page
* @param mod_quiz_display_options $displayoptions instance of mod_quiz_display_options
* @param mod_quiz_display_options $displayoptions instance of mod_quiz_display_options
*/
*/
public function questions(quiz_attempt $attemptobj, $reviewing, $slots, $page, $showall,
public function questions(quiz_attempt $attemptobj, $reviewing, $slots, $page, $showall,
mod_quiz_display_options $displayoptions) {
mod_quiz_display_options $displayoptions) {
$output = '';
$output = '';
foreach ($slots as $slot) {
foreach ($slots as $slot) {
$output .= $attemptobj->render_question($slot, $reviewing,
$output .= $attemptobj->render_question($slot, $reviewing,
$attemptobj->review_url($slot, $page, $showall));
$attemptobj->review_url($slot, $page, $showall));
}
}
return $output;
return $output;
}
}


/**
/**
* Renders the main bit of the review page.
* Renders the main bit of the review page.
*
*
* @param array $summarydata contain row data for table
* @param array $summarydata contain row data for table
* @param int $page current page number
* @param int $page current page number
* @param mod_quiz_display_options $displayoptions instance of mod_quiz_display_options
* @param mod_quiz_display_options $displayoptions instance of mod_quiz_display_options
* @param $content contains each question
* @param $content contains each question
* @param quiz_attempt $attemptobj instance of quiz_attempt
* @param quiz_attempt $attemptobj instance of quiz_attempt
* @param bool $showall if true display attempt on one page
* @param bool $showall if true display attempt on one page
*/
*/
public function review_form($page, $showall, $displayoptions, $content, $attemptobj) {
public function review_form($page, $showall, $displayoptions, $content, $attemptobj) {
if ($displayoptions->flags != question_display_options::EDITABLE) {
if ($displayoptions->flags != question_display_options::EDITABLE) {
return $content;
return $content;
}
}


$this->page->requires->js_init_call('M.mod_quiz.init_review_form', null, false,
$this->page->requires->js_init_call('M.mod_quiz.init_review_form', null, false,
quiz_get_js_module());
quiz_get_js_module());


$output = '';
$output = '';
$output .= html_writer::start_tag('form', array('action' => $attemptobj->review_url(null,
$output .= html_writer::start_tag('form', array('action' => $attemptobj->review_url(null,
$page, $showall), 'method' => 'post', 'class' => 'questionflagsaveform'));
$page, $showall), 'method' => 'post', 'class' => 'questionflagsaveform'));
$output .= html_writer::start_tag('div');
$output .= html_writer::start_tag('div');
$output .= $content;
$output .= $content;
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey',
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey',
'value' => sesskey()));
'value' => sesskey()));
$output .= html_writer::start_tag('div', array('class' => 'submitbtns'));
$output .= html_writer::start_tag('div', array('class' => 'submitbtns'));
$output .= html_writer::empty_tag('input', array('type' => 'submit',
$output .= html_writer::empty_tag('input', array('type' => 'submit',
'class' => 'questionflagsavebutton', 'name' => 'savingflags',
'class' => 'questionflagsavebutton', 'name' => 'savingflags',
'value' => get_string('saveflags', 'question')));
'value' => get_string('saveflags', 'question')));
$output .= html_writer::end_tag('div');
$output .= html_writer::end_tag('div');
$output .= html_writer::end_tag('div');
$output .= html_writer::end_tag('div');
$output .= html_writer::end_tag('form');
$output .= html_writer::end_tag('form');


return $output;
return $output;
}
}


/**
/**
* Returns either a liink or button
* Returns either a liink or button
*
*
* @param quiz_attempt $attemptobj instance of quiz_attempt
* @param quiz_attempt $attemptobj instance of quiz_attempt
*/
*/
public function finish_review_link(quiz_attempt $attemptobj) {
public function finish_review_link(quiz_attempt $attemptobj) {
$url = $attemptobj->view_url();
$url = $attemptobj->view_url();


if ($attemptobj->get_access_manager(time())->attempt_must_be_in_popup()) {
if ($attemptobj->get_access_manager(time())->attempt_must_be_in_popup()) {
$this->page->requires->js_init_call('M.mod_quiz.secure_window.init_close_button',
$this->page->requires->js_init_call('M.mod_quiz.secure_window.init_close_button',
array($url), quiz_get_js_module());
array($url), quiz_get_js_module());
return html_writer::empty_tag('input', array('type' => 'button',
return html_writer::empty_tag('input', array('type' => 'button',
'value' => get_string('finishreview', 'quiz'),
'value' => get_string('finishreview', 'quiz'),
'id' => 'secureclosebutton'));
'id' => 'secureclosebutton'));


} else {
} else {
return html_writer::link($url, get_string('finishreview', 'quiz'));
return html_writer::link($url, get_string('finishreview', 'quiz'));
}
}
}
}


/**
/**
* Creates a next page arrow or the finishing link
* Creates a next page arrow or the finishing link
*
*
* @param quiz_attempt $attemptobj instance of quiz_attempt
* @param quiz_attempt $attemptobj instance of quiz_attempt
* @param int $page the current page
* @param int $page the current page
* @param bool $lastpage if true current page is the last page
* @param bool $lastpage if true current page is the last page
*/
*/
public function review_next_navigation(quiz_attempt $attemptobj, $page, $lastpage) {
public function review_next_navigation(quiz_attempt $attemptobj, $page, $lastpage) {
if ($lastpage) {
if ($lastpage) {
$nav = $this->finish_review_link($attemptobj);
$nav = $this->finish_review_link($attemptobj);
} else {
} else {
$nav = link_arrow_right(get_string('next'), $attemptobj->review_url(null, $page + 1));
$nav = link_arrow_right(get_string('next'), $attemptobj->review_url(null, $page + 1));
}
}
return html_writer::tag('div', $nav, array('class' => 'submitbtns'));
return html_writer::tag('div', $nav, array('class' => 'submitbtns'));
}
}


/**
/**
* Return the HTML of the quiz timer.
* Return the HTML of the quiz timer.
* @return string HTML content.
* @return string HTML content.
*/
*/
public function countdown_timer(quiz_attempt $attemptobj, $timenow) {
public function countdown_timer(quiz_attempt $attemptobj, $timenow) {


$timeleft = $attemptobj->get_time_left_display($timenow);
$timeleft = $attemptobj->get_time_left_display($timenow);
if ($timeleft !== false) {
if ($timeleft !== false) {
$ispreview = $attemptobj->is_preview();
$ispreview = $attemptobj->is_preview();
$timerstartvalue = $timeleft;
$timerstartvalue = $timeleft;
if (!$ispreview) {
if (!$ispreview) {
// Make sure the timer starts just above zero. If $timeleft was <= 0, then
// 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.
// this will just have the effect of causing the quiz to be submitted immediately.
$timerstartvalue = max($timerstartvalue, 1);
$timerstartvalue = max($timerstartvalue, 1);
}
}
$this->initialise_timer($timerstartvalue, $ispreview);
$this->initialise_timer($timerstartvalue, $ispreview);
}
}


return html_writer::tag('div', get_string('timeleft', 'quiz') . ' ' .
return html_writer::tag('div', get_string('timeleft', 'quiz') . ' ' .
html_writer::tag('span', '', array('id' => 'quiz-time-left')),
html_writer::tag('span', '', array('id' => 'quiz-time-left')),
array('id' => 'quiz-timer', 'role' => 'timer',
array('id' => 'quiz-timer', 'role' => 'timer',
'aria-atomic' => 'true', 'aria-relevant' => 'text'));
'aria-atomic' => 'true', 'aria-relevant' => 'text'));
}
}


/**
/**
* Create a preview link
* Create a preview link
*
*
* @param $url contains a url to the given page
* @param $url contains a url to the given page
*/
*/
public function restart_preview_button($url) {
public function restart_preview_button($url) {
return $this->single_button($url, get_string('startnewpreview', 'quiz'));
return $this->single_button($url, get_string('startnewpreview', 'quiz'));
}
}


/**
/**
* Outputs the navigation block panel
* Outputs the navigation block panel
*
*
* @param quiz_nav_panel_base $panel instance of quiz_nav_panel_base
* @param quiz_nav_panel_base $panel instance of quiz_nav_panel_base
*/
*/
public function navigation_panel(quiz_nav_panel_base $panel) {
public function navigation_panel(quiz_nav_panel_base $panel) {


$output = '';
$output = '';
$userpicture = $panel->user_picture();
$userpicture = $panel->user_picture();
if ($userpicture) {
if ($userpicture) {
$fullname = fullname($userpicture->user);
$fullname = fullname($userpicture->user);
if ($userpicture->size === true) {
if ($userpicture->size === true) {
$fullname = html_writer::div($fullname);
$fullname = html_writer::div($fullname);
}
}
$output .= html_writer::tag('div', $this->render($userpicture) . $fullname,
$output .= html_writer::tag('div', $this->render($userpicture) . $fullname,
array('id' => 'user-picture', 'class' => 'clearfix'));
array('id' => 'user-picture', 'class' => 'clearfix'));
}
}
$output .= $panel->render_before_button_bits($this);
$output .= $panel->render_before_button_bits($this);


$bcc = $panel->get_button_container_class();
$bcc = $panel->get_button_container_class();
$output .= html_writer::start_tag('div', array('class' => "qn_buttons $bcc"));
$output .= html_writer::start_tag('div', array('class' => "qn_buttons $bcc"));
foreach ($panel->get_question_buttons() as $button) {
foreach ($panel->get_question_buttons() as $button) {
$output .= $this->render($button);
$output .= $this->render($button);
}
}
$output .= html_writer::end_tag('div');
$output .= html_writer::end_tag('div');


$output .= html_writer::tag('div', $panel->render_end_bits($this),
$output .= html_writer::tag('div', $panel->render_end_bits($this),
array('class' => 'othernav'));
array('class' => 'othernav'));


$this->page->requires->js_init_call('M.mod_quiz.nav.init', null, false,
$this->page->requires->js_init_call('M.mod_quiz.nav.init', null, false,
quiz_get_js_module());
quiz_get_js_module());


return $output;
return $output;
}
}


/**
/**
* Returns the quizzes navigation button
* Returns the quizzes navigation button
*
*
* @param quiz_nav_question_button $button
* @param quiz_nav_question_button $button
*/
*/
protected function render_quiz_nav_question_button(quiz_nav_question_button $button) {
protected function render_quiz_nav_question_button(quiz_nav_question_button $button) {
$classes = array('qnbutton', $button->stateclass, $button->navmethod);
$classes = array('qnbutton', $button->stateclass, $button->navmethod);
$attributes = array();
$attributes = array();


if ($button->currentpage) {
if ($button->currentpage) {
$classes[] = 'thispage';
$classes[] = 'thispage';
$attributes[] = get_string('onthispage', 'quiz');
$attributes[] = get_string('onthispage', 'quiz');
}
}


// Flagged?
// Flagged?
if ($button->flagged) {
if ($button->flagged) {
$classes[] = 'flagged';
$classes[] = 'flagged';
$flaglabel = get_string('flagged', 'question');
$flaglabel = get_string('flagged', 'question');
} else {
} else {
$flaglabel = '';
$flaglabel = '';
}
}
$attributes[] = html_writer::tag('span', $flaglabel, array('class' => 'flagstate'));
$attributes[] = html_writer::tag('span', $flaglabel, array('class' => 'flagstate'));


if (is_numeric($button->number)) {
if (is_numeric($button->number)) {
$qnostring = 'questionnonav';
$qnostring = 'questionnonav';
} else {
} else {
$qnostring = 'questionnonavinfo';
$qnostring = 'questionnonavinfo';
}
}


$a = new stdClass();
$a = new stdClass();
$a->number = $button->number;
$a->number = $button->number;
$a->attributes = implode(' ', $attributes);
$a->attributes = implode(' ', $attributes);
$tagcontents = html_writer::tag('span', '', array('class' => 'thispageholder')) .
$tagcontents = html_writer::tag('span', '', array('class' => 'thispageholder')) .
html_writer::tag('span', '', array('class' => 'trafficlight')) .
html_writer::tag('span', '', array('class' => 'trafficlight')) .
get_string($qnostring, 'quiz', $a);
get_string($qnostring, 'quiz', $a);
$tagattributes = array('class' => implode(' ', $classes), 'id' => $button->id,
$tagattributes = array('class' => implode(' ', $classes), 'id' => $button->id,
'title' => $button->statestring);
'title' => $button->statestring);


if ($button->url) {
if ($button->url) {
return html_writer::link($button->url, $tagcontents, $tagattributes);
return html_writer::link($button->url, $tagcontents, $tagattributes);
} else {
} else {
return html_writer::tag('span', $tagcontents, $tagattributes);
return html_writer::tag('span', $tagcontents, $tagattributes);
}
}
}
}


/**
/**
* outputs the link the other attempts.
* outputs the link the other attempts.
*
*
* @param mod_quiz_links_to_other_attempts $links
* @param mod_quiz_links_to_other_attempts $links
*/
*/
protected function render_mod_quiz_links_to_other_attempts(
protected function render_mod_quiz_links_to_other_attempts(
mod_quiz_links_to_other_attempts $links) {
mod_quiz_links_to_other_attempts $links) {
$attemptlinks = array();
$attemptlinks = array();
foreach ($links->links as $attempt => $url) {
foreach ($links->links as $attempt => $url) {
if ($url) {
if ($url) {
$attemptlinks[] = html_writer::link($url, $attempt);
$attemptlinks[] = html_writer::link($url, $attempt);
} else {
} else {
$attemptlinks[] = html_writer::tag('strong', $attempt);
$attemptlinks[] = html_writer::tag('strong', $attempt);
}
}
}
}
return implode(', ', $attemptlinks);
return implode(', ', $attemptlinks);
}
}


public function start_attempt_page(quiz $quizobj, mod_quiz_preflight_check_form $mform) {
public function start_attempt_page(quiz $quizobj, mod_quiz_preflight_check_form $mform) {
$output = '';
$output = '';
$output .= $this->header();
$output .= $this->header();
$output .= $this->heading(format_string($quizobj->get_quiz_name(), true,
$output .= $this->heading(format_string($quizobj->get_quiz_name(), true,
array("context" => $quizobj->get_context())));
array("context" => $quizobj->get_context())));
$output .= $this->quiz_intro($quizobj->get_quiz(), $quizobj->get_cm());
$output .= $this->quiz_intro($quizobj->get_quiz(), $quizobj->get_cm());
ob_start();
ob_start();
$mform->display();
$mform->display();
$output .= ob_get_clean();
$output .= ob_get_clean();
$output .= $this->footer();
$output .= $this->footer();
return $output;
return $output;
}
}


/**
/**
* Attempt Page
* Attempt Page
*
*
* @param quiz_attempt $attemptobj Instance of quiz_attempt
* @param quiz_attempt $attemptobj Instance of quiz_attempt
* @param int $page Current page number
* @param int $page Current page number
* @param quiz_access_manager $accessmanager Instance of quiz_access_manager
* @param quiz_access_manager $accessmanager Instance of quiz_access_manager
* @param array $messages An array of messages
* @param array $messages An array of messages
* @param array $slots Contains an array of integers that relate to questions
* @param array $slots Contains an array of integers that relate to questions
* @param int $id The ID of an attempt
* @param int $id The ID of an attempt
* @param int $nextpage The number of the next page
* @param int $nextpage The number of the next page
*/
*/
public function attempt_page($attemptobj, $page, $accessmanager, $messages, $slots, $id,
public function attempt_page($attemptobj, $page, $accessmanager, $messages, $slots, $id,
$nextpage) {
$nextpage) {
$output = '';
$output = '';
$output .= $this->header();
$output .= $this->header();
$output .= $this->quiz_notices($messages);
$output .= $this->quiz_notices($messages);
$output .= $this->attempt_form($attemptobj, $page, $slots, $id, $nextpage);
$output .= $this->attempt_form($attemptobj, $page, $slots, $id, $nextpage);
$output .= $this->footer();
$output .= $this->footer();
return $output;
return $output;
}
}


/**
/**
* Returns any notices.
* Returns any notices.
*
*
* @param array $messages
* @param array $messages
*/
*/
public function quiz_notices($messages) {
public function quiz_notices($messages) {
if (!$messages) {
if (!$messages) {
return '';
return '';
}
}
return $this->box($this->heading(get_string('accessnoticesheader', 'quiz'), 3) .
return $this->box($this->heading(get_string('accessnoticesheader', 'quiz'), 3) .
$this->access_messages($messages), 'quizaccessnotices');
$this->access_messages($messages), 'quizaccessnotices');
}
}


/**
/**
* Ouputs the form for making an attempt
* Ouputs the form for making an attempt
*
*
* @param quiz_attempt $attemptobj
* @param quiz_attempt $attemptobj
* @param int $page Current page number
* @param int $page Current page number
* @param array $slots Array of integers relating to questions
* @param array $slots Array of integers relating to questions
* @param int $id ID of the attempt
* @param int $id ID of the attempt
* @param int $nextpage Next page number
* @param int $nextpage Next page number
*/
*/
public function attempt_form($attemptobj, $page, $slots, $id, $nextpage) {
public function attempt_form($attemptobj, $page, $slots, $id, $nextpage) {
$output = '';
$output = '';


// Start the form.
// Start the form.
$output .= html_writer::start_tag('form',
$output .= html_writer::start_tag('form',
array('action' => $attemptobj->processattempt_url(), 'method' => 'post',
array('action' => $attemptobj->processattempt_url(), 'method' => 'post',
'enctype' => 'multipart/form-data', 'accept-charset' => 'utf-8',
'enctype' => 'multipart/form-data', 'accept-charset' => 'utf-8',
'id' => 'responseform'));
'id' => 'responseform'));
$output .= html_writer::start_tag('div');
$output .= html_writer::start_tag('div');


// Print all the questions.
// Print all the questions.
foreach ($slots as $slot) {
foreach ($slots as $slot) {
$output .= $attemptobj->render_question($slot, false,
$output .= $attemptobj->render_question($slot, false,
$attemptobj->attempt_url($slot, $page));
$attemptobj->attempt_url($slot, $page));
}
}


$output .= html_writer::start_tag('div', array('class' => 'submitbtns'));
$output .= html_writer::start_tag('div', array('class' => 'submitbtns'));
$output .= html_writer::empty_tag('input', array('type' => 'submit', 'name' => 'next',
$output .= html_writer::empty_tag('input', array('type' => 'submit', 'name' => 'next',
'value' => get_string('next')));
'value' => get_string('next')));
$output .= html_writer::end_tag('div');
$output .= html_writer::end_tag('div');


// Some hidden fields to trach what is going on.
// Some hidden fields to trach what is going on.
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'attempt',
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'attempt',
'value' => $attemptobj->get_attemptid()));
'value' => $attemptobj->get_attemptid()));
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'thispage',
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'thispage',
'value' => $page, 'id' => 'followingpage'));
'value' => $page, 'id' => 'followingpage'));
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'nextpage',
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'nextpage',
'value' => $nextpage));
'value' => $nextpage));
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'timeup',
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'timeup',
'value' => '0', 'id' => 'timeup'));
'value' => '0', 'id' => 'timeup'));
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey',
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey',
'value' => sesskey()));
'value' => sesskey()));
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'scrollpos',
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'scrollpos',
'value' => '', 'id' => 'scrollpos'));
'value' => '', 'id' => 'scrollpos'));


// Add a hidden field with questionids. Do this at the end of the form, so
// Add a hidden field with questionids. Do this at the end of the form, so
// if you navigate before the form has finished loading, it does not wipe all
// if you navigate before the form has finished loading, it does not wipe all
// the student's answers.
// the student's answers.
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'slots',
$output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'slots',
'value' => implode(',', $slots)));
'value' => implode(',', $slots)));


// Finish the form.
// Finish the form.
$output .= html_writer::end_tag('div');
$output .= html_writer::end_tag('div');
$output .= html_writer::end_tag('form');
$output .= html_writer::end_tag('form');


$output .= $this->connection_warning();
$output .= $this->connection_warning();


return $output;
return $output;
}
}


/**
/**
* Output the JavaScript required to initialise the countdown timer.
* Output the JavaScript required to initialise the countdown timer.
* @param int $timerstartvalue time remaining, in seconds.
* @param int $timerstartvalue time remaining, in seconds.
*/
*/
public function initialise_timer($timerstartvalue, $ispreview) {
public function initialise_timer($timerstartvalue, $ispreview) {
$options = array($timerstartvalue, (bool)$ispreview);
$options = array($timerstartvalue, (bool)$ispreview);
$this->page->requires->js_init_call('M.mod_quiz.timer.init', $options, false, quiz_get_js_module());
$this->page->requires->js_init_call('M.mod_quiz.timer.init', $options, false, quiz_get_js_module());
}
}


/**
/**
* Output a page with an optional message, and JavaScript code to close the
* Output a page with an optional message, and JavaScript code to close the
* current window and redirect the parent window to a new URL.
* current window and redirect the parent window to a new URL.
* @param moodle_url $url the URL to redirect the parent window to.
* @param moodle_url $url the URL to redirect the parent window to.
* @param string $message message to display before closing the window. (optional)
* @param string $message message to display before closing the window. (optional)
* @return string HTML to output.
* @return string HTML to output.
*/
*/
public function close_attempt_popup($url, $message = '') {
public function close_attempt_popup($url, $message = '') {
$output = '';
$output = '';
$output .= $this->header();
$output .= $this->header();
$output .= $this->box_start();
$output .= $this->box_start();


if ($message) {
if ($message) {
$output .= html_writer::tag('p', $message);
$output .= html_writer::tag('p', $message);
$output .= html_writer::tag('p', get_string('windowclosing', 'quiz'));
$output .= html_writer::tag('p', get_string('windowclosing', 'quiz'));
$delay = 5;
$delay = 5;
} else {
} else {
$output .= html_writer::tag('p', get_string('pleaseclose', 'quiz'));
$output .= html_writer::tag('p', get_string('pleaseclose', 'quiz'));
$delay = 0;
$delay = 0;
}
}
$this->page->requires->js_init_call('M.mod_quiz.secure_window.close',
$this->page->requires->js_init_call('M.mod_quiz.secure_window.close',
array($url, $delay), false, quiz_get_js_module());
array($url, $delay), false, quiz_get_js_module());


$output .= $this->box_end();
$output .= $this->box_end();
$output .= $this->footer();
$output .= $this->footer();
return $output;
return $output;
}
}


/**
/**
* Print each message in an array, surrounded by &lt;p>, &lt;/p> tags.
* Print each message in an array, surrounded by &lt;p>, &lt;/p> tags.
*
*
* @param array $messages the array of message strings.
* @param array $messages the array of message strings.
* @param bool $return if true, return a string, instead of outputting.
* @param bool $return if true, return a string, instead of outputting.
*
*
* @return string HTML to output.
* @return string HTML to output.
*/
*/
public function access_messages($messages) {
public function access_messages($messages) {
$output = '';
$output = '';
foreach ($messages as $message) {
foreach ($messages as $message) {
$output .= html_writer::tag('p', $message) . "\n";
$output .= html_writer::tag('p', $message) . "\n";
}
}
return $output;
return $output;
}
}


/*
/*
* Summary Page
* Summary Page
*/
*/
/**
/**
* Create the summary page
* Create the summary page
*
*
* @param quiz_attempt $attemptobj
* @param quiz_attempt $attemptobj
* @param mod_quiz_display_options $displayoptions
* @param mod_quiz_display_options $displayoptions
*/
*/
public function summary_page($attemptobj, $displayoptions) {
public function summary_page($attemptobj, $displayoptions) {
$output = '';
$output = '';
$output .= $this->header();
$output .= $this->header();
$output .= $this->heading(format_string($attemptobj->get_quiz_name()));
$output .= $this->heading(format_string($attemptobj->get_quiz_name()));
$output .= $this->heading(get_string('summaryofattempt', 'quiz'), 3);
$output .= $this->heading(get_string('summaryofattempt', 'quiz'), 3);
$output .= $this->summary_table($attemptobj, $displayoptions);
$output .= $this->summary_table($attemptobj, $displayoptions);
$output .= $this->summary_page_controls($attemptobj);
$output .= $this->summary_page_controls($attemptobj);
$output .= $this->footer();
$output .= $this->footer();
return $output;
return $output;
}
}


/**
/**
* Generates the table of summarydata
* Generates the table of summarydata
*
*
* @param quiz_attempt $attemptobj
* @param quiz_attempt $attemptobj
* @param mod_quiz_display_options $displayoptions
* @param mod_quiz_display_options $displayoptions
*/
*/
public function summary_table($attemptobj, $displayoptions) {
public function summary_table($attemptobj, $displayoptions) {
// Prepare the summary table header.
// Prepare the summary table header.
$table = new html_table();
$table = new html_table();
$table->attributes['class'] = 'generaltable quizsummaryofattempt boxaligncenter';
$table->attributes['class'] = 'generaltable quizsummaryofattempt boxaligncenter';
$table->head = array(get_string('question', 'quiz'), get_string('status', 'quiz'));
//$table->align = array('left', 'left');
$table->align = array('center', 'center', 'center');
// Get the summary info for each question.
$slots = $attemptobj->get_slots();
//Make a copy of the $slots array into $slots_ques array, but the difference is that $slots_ques array contains only bona-fide questions,
//not description questions!
//Frankie Kam, 29th April 2015
//
$slots_ques = array();

foreach ($slots as $slot) {
if (!$attemptobj->is_real_question($slot)) {
//Is the current question a description question? Skip it and don't copy it inside $slots_ques array!
continue;
}
//Make a copy of the question inside $slots_ques
$slots_ques[] = $slot;
}
$MAXVAL = sizeof($slots_ques);
$COLS=3;
if ($MAXVAL % $COLS > 0)
$nearest3 = $MAXVAL + ($COLS - $MAXVAL % $COLS);
else
$nearest3 = $MAXVAL;
$ROWS = $nearest3/$COLS;

if($MAXVAL>2)
$table->head = array(get_string('question', 'quiz'), get_string('status', 'quiz'), get_string('question', 'quiz'), get_string('status', 'quiz'), get_string('question', 'quiz'), get_string('status', 'quiz'));
else if($MAXVAL==2)
$table->head = array(get_string('question', 'quiz'), get_string('status', 'quiz'), get_string('question', 'quiz'), get_string('status', 'quiz'));
else if($MAXVAL==1)
$table->head = array(get_string('question', 'quiz'),get_string('status', 'quiz'));
else if($MAXVAL<=0)
$table->head = get_string('huh', 'what');
//This makes the first column of question number links, aligned to theright
//Frankie Kam, 29th April 2015
//Original was: $table->align = array('left', 'left');
$table->align = array('right', 'right','right', 'right', 'right', 'right');
$table->size = array('', '');
$table->size = array('', '');
$markscolumn = $displayoptions->marks >= question_display_options::MARK_AND_MAX;
$markscolumn = $displayoptions->marks >= question_display_options::MARK_AND_MAX;
if ($markscolumn) {
if ($markscolumn) {
$table->head[] = get_string('marks', 'quiz');
$table->head[] = get_string('marks', 'quiz');
$table->align[] = 'left';
$table->align[] = 'left';
$table->size[] = '';
$table->size[] = '';
}
}
$table->data = array();
$table->data = array();


// Get the summary info for each question.
$slots = $attemptobj->get_slots();
for($r = 1; $r <= $ROWS; $r++)
foreach ($slots as $slot) {
{
if (!$attemptobj->is_real_question($slot)) {
continue;
}
$flag = '';
if ($attemptobj->is_question_flagged($slot)) {
$flag = html_writer::empty_tag('img', array('src' => $this->pix_url('i/flagged'),
'alt' => get_string('flagged', 'question'), 'class' => 'questionflag icon-post'));
}
if ($attemptobj->can_navigate_to($slot)) {
$row = array(html_writer::link($attemptobj->attempt_url($slot),
$attemptobj->get_question_number($slot) . $flag),
$attemptobj->get_question_status($slot, $displayoptions->correctness),array('text-align' => 'center'));
} else {
$row = array($attemptobj->get_question_number($slot) . $flag,
$attemptobj->get_question_status($slot, $displayoptions->correctness));
}
if ($markscolumn) {
$row[] = $attemptobj->get_question_mark($slot);
}
$table->data[] = $row;
$table->rowclasses[] = $attemptobj->get_question_state_class(
$slot, $displayoptions->correctness);
}

// Print the summary table.
$output = html_writer::table($table);

return $output;
}

/**
* Creates any controls a the page should have.
*
* @param quiz_attempt $attemptobj
*/
public function summary_page_controls($attemptobj) {
$output = '';


// Return to place button.
$column1 = '';
if ($attemptobj->get_state() == quiz_attempt::IN_PROGRESS) {
$column2 = '';
$button = new single_button(
$column3 = '';
new moodle_url($attemptobj->attempt_url(null, $attemptobj->get_currentpage())),
get_string('returnattempt', 'qu
if($r+($nearest3/$COLS)*2 <= $MAXVAL)
{
$flag1 = '';
if ($attemptobj->is_real_question($slots_ques[$r-1])) {
if ($attemptobj->is_question_flagged($slots_ques[$r-1])) {
$flag1 = html_writer::empty_tag('img', array('src' => $this->pix_url('i/flagged'),
'alt' =