MDL-15452 - Put the OU quiz navigation improvements into the Moodle codebase. I was able to factor out some commonalities with review.php along the way.
This commit is contained in:
@@ -90,6 +90,7 @@ $string['cannotloadquestion'] = 'Could not load question options';
|
||||
$string['cannotopen'] = 'Cannot open export file ($a)';
|
||||
$string['cannotread'] = 'Cannot read import file (or file is empty)';
|
||||
$string['cannotrestore'] = 'Could not restore question sessions';
|
||||
$string['cannotreviewopen'] = 'You cannot review this attempt, it is still open.';
|
||||
$string['cannotsavequestion'] = 'Cannot save question list';
|
||||
$string['cannotwrite'] = 'Cannot write to export file ($a)';
|
||||
$string['caseno'] = 'No, case is unimportant';
|
||||
@@ -524,7 +525,6 @@ $string['reviewbefore'] = 'Allow review while quiz is open';
|
||||
$string['reviewclosed'] = 'After the quiz is closed';
|
||||
$string['reviewimmediately'] = 'Immediately after the attempt';
|
||||
$string['reviewnever'] = 'Never allow review';
|
||||
$string['reviewnotallowed'] = 'You are not allowed to review other users\' attempts at this quiz.';
|
||||
$string['reviewofattempt'] = 'Review of attempt $a';
|
||||
$string['reviewofpreview'] = 'Review of preview';
|
||||
$string['reviewopen'] = 'Later, while the quiz is still open';
|
||||
|
||||
@@ -37,6 +37,10 @@ define('QUESTION_EVENTMANUALGRADE', '9'); // Grade was entered by teacher
|
||||
define('QUESTION_EVENTS_GRADED', QUESTION_EVENTGRADE.','.
|
||||
QUESTION_EVENTCLOSEANDGRADE.','.
|
||||
QUESTION_EVENTMANUALGRADE);
|
||||
global $QUESTION_EVENTS_GRADED;
|
||||
$QUESTION_EVENTS_GRADED = array(QUESTION_EVENTGRADE, QUESTION_EVENTCLOSEANDGRADE,
|
||||
QUESTION_EVENTMANUALGRADE);
|
||||
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
@@ -792,6 +796,12 @@ function question_preload_questions($questionids, $extrafields = '', $join = '',
|
||||
$question->_partiallyloaded = true;
|
||||
}
|
||||
|
||||
// Note, a possible optimisation here would be to not load the TEXT fields
|
||||
// (that is, questiontext and generalfeedback) here, and instead load them in
|
||||
// question_load_questions. That would add one DB query, but reduce the amount
|
||||
// of data transferred most of the time. I am not going to do this optimisation
|
||||
// until it is shown to be worthwhile.
|
||||
|
||||
return $questions;
|
||||
}
|
||||
|
||||
@@ -995,6 +1005,53 @@ function get_question_states(&$questions, $cmoptions, $attempt, $lastattemptid =
|
||||
return $states;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a particular previous state of a question.
|
||||
*
|
||||
* @param array $question The question to load the state for.
|
||||
* @param object $cmoptions Options from the specifica activity module, e.g. $quiz.
|
||||
* @param object $attempt The attempt for which the question sessions are to be loaded.
|
||||
* @param integer $stateid The id of a specific state of this question.
|
||||
* @return object the requested state. False on error.
|
||||
*/
|
||||
function question_load_specific_state($question, $cmoptions, $attempt, $stateid) {
|
||||
global $DB, $QUESTION_EVENTS_GRADED;
|
||||
// Load specified states for the question.
|
||||
$sql = 'SELECT st.*, sess.sumpenalty, sess.manualcomment
|
||||
FROM {question_states} st, {question_sessions} sess
|
||||
WHERE st.id = ?
|
||||
AND st.attempt = ?
|
||||
AND sess.attemptid = st.attempt
|
||||
AND st.question = ?
|
||||
AND sess.questionid = st.question';
|
||||
$state = $DB->get_record_sql($sql, array($stateid, $attempt->id, $question->id));
|
||||
if (!$state) {
|
||||
return false;
|
||||
}
|
||||
restore_question_state($question, $state);
|
||||
|
||||
// Load the most recent graded states for the questions before the specified one.
|
||||
list($eventinsql, $params) = $DB->get_in_or_equal($QUESTION_EVENTS_GRADED);
|
||||
$sql = 'SELECT st.*, sess.sumpenalty, sess.manualcomment
|
||||
FROM {question_states} st, {question_sessions} sess
|
||||
WHERE st.seq_number <= ?
|
||||
AND st.attempt = ?
|
||||
AND sess.attemptid = st.attempt
|
||||
AND st.question = ?
|
||||
AND sess.questionid = st.question
|
||||
AND st.event ' . $eventinsql .
|
||||
'ORDER BY st.seq_number DESC';
|
||||
$gradedstates = $DB->get_records_sql($sql, array_merge(
|
||||
array($state->seq_number, $attempt->id, $question->id), $params), 0, 1);
|
||||
if (empty($gradedstates)) {
|
||||
$state->last_graded = clone($state);
|
||||
} else {
|
||||
$gradedstate = reset($gradedstates);
|
||||
restore_question_state($question, $gradedstate);
|
||||
$state->last_graded = $gradedstate;
|
||||
}
|
||||
return $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the run-time fields for the states
|
||||
|
||||
+43
-6
@@ -419,6 +419,16 @@ class quiz_attempt extends quiz {
|
||||
$this->states = $newstates + $this->states;
|
||||
}
|
||||
|
||||
public function load_specific_question_state($questionid, $stateid) {
|
||||
global $DB;
|
||||
$state = question_load_specific_state($this->questions[$questionid],
|
||||
$this->quiz, $this->attempt, $stateid);
|
||||
if ($state === false) {
|
||||
throw new moodle_quiz_exception($this, 'invalidstateid');
|
||||
}
|
||||
$this->states[$questionid] = $state;
|
||||
}
|
||||
|
||||
// Simple getters ======================================================================
|
||||
/** @return integer the attempt id. */
|
||||
public function get_attemptid() {
|
||||
@@ -450,6 +460,20 @@ class quiz_attempt extends quiz {
|
||||
return $this->attempt->preview;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a student dealing with their own attempt/teacher previewing,
|
||||
* or someone with 'mod/quiz:viewreports' reviewing someone elses attempt.
|
||||
*
|
||||
* @return boolean whether this situation should be treated as someone looking at their own
|
||||
* attempt. The distinction normally only matters when an attempt is being reviewed.
|
||||
*/
|
||||
public function is_own_attempt() {
|
||||
global $USER;
|
||||
return $this->attempt->userid == $USER->id &&
|
||||
(!$this->is_preview_user() || $this->attempt->preview);
|
||||
|
||||
}
|
||||
|
||||
public function get_question_state($questionid) {
|
||||
$this->ensure_state_loaded($questionid);
|
||||
return $this->states[$questionid];
|
||||
@@ -576,12 +600,9 @@ class quiz_attempt extends quiz {
|
||||
* @param $otherattemptid if given, link to another attempt, instead of the one we represent.
|
||||
* @return string the URL to review this attempt.
|
||||
*/
|
||||
public function review_url($questionid = 0, $page = -1, $showall = false, $otherattemptid = null) {
|
||||
public function review_url($questionid = 0, $page = -1, $showall = false) {
|
||||
global $CFG;
|
||||
if (is_null($otherattemptid)) {
|
||||
$otherattemptid = $this->attempt->id;
|
||||
}
|
||||
return $CFG->wwwroot . '/mod/quiz/review.php?attempt=' . $otherattemptid .
|
||||
return $CFG->wwwroot . '/mod/quiz/review.php?attempt=' . $this->attempt->id .
|
||||
$this->page_and_question_fragment($questionid, $page, $showall);
|
||||
}
|
||||
|
||||
@@ -619,6 +640,22 @@ class quiz_attempt extends quiz {
|
||||
$panel->display();
|
||||
}
|
||||
|
||||
/// List of all this user's attempts for people who can see reports.
|
||||
public function links_to_other_attempts($url) {
|
||||
$search = '/\battempt=' . $this->attempt->id . '\b/';
|
||||
$attempts = quiz_get_user_attempts($this->quiz->id, $this->attempt->userid, 'all');
|
||||
$attemptlist = array();
|
||||
foreach ($attempts as $at) {
|
||||
if ($at->id == $this->attempt->id) {
|
||||
$attemptlist[] = '<strong>' . $at->attempt . '</strong>';
|
||||
} else {
|
||||
$changedurl = preg_replace($search, 'attempt=' . $at->id, $url);
|
||||
$attemptlist[] = '<a href="' . $changedurl . '">' . $at->attempt . '</a>';
|
||||
}
|
||||
}
|
||||
return implode(', ', $attemptlist);
|
||||
}
|
||||
|
||||
// Private methods =====================================================================
|
||||
// Check that the state of a particular question is loaded, and if not throw an exception.
|
||||
private function ensure_state_loaded($id) {
|
||||
@@ -750,7 +787,7 @@ abstract class quiz_nav_panel_base {
|
||||
abstract protected function get_end_bits();
|
||||
|
||||
protected function get_question_state($question) {
|
||||
$state = 'todo'; // TODO
|
||||
$state = 'todo'; // TODO MDL-15653
|
||||
if ($question->_page == $this->page) {
|
||||
$state .= ' thispage';
|
||||
}
|
||||
|
||||
@@ -821,7 +821,9 @@ function quiz_get_reviewoptions($quiz, $attempt, $context=null) {
|
||||
$options->readonly = true;
|
||||
|
||||
// Provide the links to the question review and comment script
|
||||
$options->questionreviewlink = '/mod/quiz/reviewquestion.php';
|
||||
if (!empty($attempt->id)) {
|
||||
$options->questionreviewlink = '/mod/quiz/reviewquestion.php?attempt=' . $attempt->id;
|
||||
}
|
||||
|
||||
// Show a link to the comment box only for closed attempts
|
||||
if ($attempt->timefinish && !is_null($context) && has_capability('mod/quiz:grade', $context)) {
|
||||
|
||||
@@ -190,6 +190,14 @@ class quiz_report_overview_table extends table_sql {
|
||||
return '-';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $colname the name of the column.
|
||||
* @param object $attempt the row of data - see the SQL in display() in
|
||||
* mod/quiz/report/overview/report.php to see what fields are present,
|
||||
* and what they are called.
|
||||
* @return string the contents of the cell.
|
||||
*/
|
||||
function other_cols($colname, $attempt){
|
||||
|
||||
if (preg_match('/^qsgrade([0-9]+)$/', $colname, $matches)){
|
||||
@@ -211,8 +219,8 @@ class quiz_report_overview_table extends table_sql {
|
||||
$grade = '<del>'.$oldgrade.'</del><br />'.
|
||||
$newgrade;
|
||||
}
|
||||
return link_to_popup_window('/mod/quiz/reviewquestion.php?state='.
|
||||
$stateforqinattempt->id.'&number='.$question->number,
|
||||
return link_to_popup_window('/mod/quiz/reviewquestion.php?attempt=' .
|
||||
$attempt->attempt . '&question=' . $question->id,
|
||||
'reviewquestion', $grade, 450, 650, get_string('reviewresponse', 'quiz'),
|
||||
'none', true);
|
||||
} else {
|
||||
|
||||
+15
-29
@@ -19,16 +19,10 @@
|
||||
/// Check login.
|
||||
require_login($attemptobj->get_courseid(), false, $attemptobj->get_cm());
|
||||
|
||||
|
||||
/// Create an object to manage all the other (non-roles) access rules.
|
||||
$accessmanager = $attemptobj->get_access_manager(time());
|
||||
$options = $attemptobj->get_review_options();
|
||||
|
||||
/// Work out if this is a student viewing their own attempt/teacher previewing,
|
||||
/// or someone with 'mod/quiz:viewreports' reviewing someone elses attempt.
|
||||
$reviewofownattempt = $attemptobj->get_userid() == $USER->id &&
|
||||
(!$attemptobj->is_preview_user() || $attemptobj->is_preview());
|
||||
|
||||
/// Permissions checks for normal users who do not have quiz:viewreports capability.
|
||||
if (!$attemptobj->has_capability('mod/quiz:viewreports')) {
|
||||
/// Can't review during the attempt - send them back to the attempt page.
|
||||
@@ -36,8 +30,8 @@
|
||||
redirect($attemptobj->attempt_url(0, $page));
|
||||
}
|
||||
/// Can't review other users' attempts.
|
||||
if (!$reviewofownattempt) {
|
||||
quiz_error($quiz, 'reviewnotallowed');
|
||||
if (!$attemptobj->is_own_attempt()) {
|
||||
quiz_error($quiz, 'notyourattempt');
|
||||
}
|
||||
/// Can't review unless Students may review -> Responses option is turned on.
|
||||
if (!$options->responses) {
|
||||
@@ -46,10 +40,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/// Log this review.
|
||||
add_to_log($attemptobj->get_courseid(), 'quiz', 'review', 'review.php?attempt=' .
|
||||
$attemptobj->get_attemptid(), $attemptobj->get_quizid(), $attemptobj->get_cmid());
|
||||
|
||||
/// load the questions and states needed by this page.
|
||||
if ($showall) {
|
||||
$questionids = $attemptobj->get_question_ids();
|
||||
@@ -59,8 +49,12 @@
|
||||
$attemptobj->load_questions($questionids);
|
||||
$attemptobj->load_question_states($questionids);
|
||||
|
||||
/// Log this review.
|
||||
add_to_log($attemptobj->get_courseid(), 'quiz', 'review', 'review.php?attempt=' .
|
||||
$attemptobj->get_attemptid(), $attemptobj->get_quizid(), $attemptobj->get_cmid());
|
||||
|
||||
/// Work out appropriate title.
|
||||
if ($attemptobj->is_preview_user() && $reviewofownattempt) {
|
||||
if ($attemptobj->is_preview_user() && $attemptobj->is_own_attempt()) {
|
||||
$strreviewtitle = get_string('reviewofpreview', 'quiz');
|
||||
} else {
|
||||
$strreviewtitle = get_string('reviewofattempt', 'quiz', $attemptobj->get_attempt_number());
|
||||
@@ -78,7 +72,7 @@
|
||||
|
||||
/// Print tabs if they should be there.
|
||||
if ($attemptobj->is_preview_user()) {
|
||||
if ($reviewofownattempt) {
|
||||
if ($attemptobj->is_own_attempt()) {
|
||||
$currenttab = 'preview';
|
||||
} else {
|
||||
$currenttab = 'reports';
|
||||
@@ -88,8 +82,8 @@
|
||||
}
|
||||
|
||||
/// Print heading.
|
||||
print_heading(format_string($quiz->name));
|
||||
if ($attemptobj->is_preview_user() && $reviewofownattempt) {
|
||||
print_heading(format_string($attemptobj->get_quiz_name()));
|
||||
if ($attemptobj->is_preview_user() && $attemptobj->is_own_attempt()) {
|
||||
$attemptobj->print_restart_preview_button();
|
||||
}
|
||||
print_heading($strreviewtitle);
|
||||
@@ -139,20 +133,12 @@
|
||||
$CFG->wwwroot . '/user/view.php?id=' . $student->id . '&course=' . $attemptobj->get_courseid() . '">' .
|
||||
fullname($student, true) . '</a></td></tr>';
|
||||
}
|
||||
if (has_capability('mod/quiz:viewreports', $context) &&
|
||||
count($attempts = $DB->get_records_select('quiz_attempts', "quiz = ? AND userid = ?", array($quiz->id, $attempt->userid), 'attempt ASC')) > 1) {
|
||||
/// List of all this user's attempts for people who can see reports.
|
||||
$attemptlist = array();
|
||||
foreach ($attempts as $at) {
|
||||
if ($at->id == $attempt->id) {
|
||||
$attemptlist[] = '<strong>' . $at->attempt . '</strong>';
|
||||
} else {
|
||||
$attemptlist[] = '<a href="' . $attemptobj->review_url(0, $page, $showall, $at->id) .
|
||||
'">' . $at->attempt . '</a>';
|
||||
}
|
||||
if ($attemptobj->has_capability('mod/quiz:viewreports')) {
|
||||
$attemptlist = $attemptobj->links_to_other_attempts($attemptobj->review_url(0, $page, $showall));
|
||||
if ($attemptlist) {
|
||||
$rows[] = '<tr><th scope="row" class="cell">' . get_string('attempts', 'quiz') .
|
||||
'</th><td class="cell">' . $attemptlist . '</td></tr>';
|
||||
}
|
||||
$rows[] = '<tr><th scope="row" class="cell">' . get_string('attempts', 'quiz') .
|
||||
'</th><td class="cell">' . implode(', ', $attemptlist) . '</td></tr>';
|
||||
}
|
||||
|
||||
/// Timing information.
|
||||
|
||||
+89
-116
@@ -1,8 +1,9 @@
|
||||
<?php // $Id$
|
||||
/**
|
||||
* This page prints a review of a particular question attempt
|
||||
* This page prints a review of a particular question attempt.
|
||||
* This page is expected to only be used in a popup window.
|
||||
*
|
||||
* @author Martin Dougiamas and many others.
|
||||
* @author Martin Dougiamas, Tim Hunt and many others.
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @package quiz
|
||||
*/
|
||||
@@ -10,137 +11,109 @@
|
||||
require_once(dirname(__FILE__) . '/../../config.php');
|
||||
require_once('locallib.php');
|
||||
|
||||
// Either stateid or (attemptid AND questionid) must be given
|
||||
$attemptid = required_param('attempt', PARAM_INT); // attempt id
|
||||
$questionid = required_param('question', PARAM_INT); // question id
|
||||
$stateid = optional_param('state', 0, PARAM_INT); // state id
|
||||
$attemptid = optional_param('attempt', 0, PARAM_INT); // attempt id
|
||||
$questionid = optional_param('question', 0, PARAM_INT); // attempt id
|
||||
$number = optional_param('number', 0, PARAM_INT); // question number
|
||||
|
||||
$attemptobj = new quiz_attempt($attemptid);
|
||||
|
||||
/// Check login.
|
||||
require_login($attemptobj->get_courseid(), false, $attemptobj->get_cm());
|
||||
|
||||
/// Create an object to manage all the other (non-roles) access rules.
|
||||
$accessmanager = $attemptobj->get_access_manager(time());
|
||||
$options = $attemptobj->get_review_options();
|
||||
|
||||
/// Permissions checks for normal users who do not have quiz:viewreports capability.
|
||||
if (!$attemptobj->has_capability('mod/quiz:viewreports')) {
|
||||
/// Can't review during the attempt - send them back to the attempt page.
|
||||
if (!$attemptobj->is_finished()) {
|
||||
notify(get_string('cannotreviewopen', 'quiz'));
|
||||
close_window_button();
|
||||
}
|
||||
/// Can't review other users' attempts.
|
||||
if (!$attemptobj->is_own_attempt()) {
|
||||
notify(get_string('notyourattempt', 'quiz'));
|
||||
close_window_button();
|
||||
}
|
||||
/// Can't review unless Students may review -> Responses option is turned on.
|
||||
if (!$options->responses) {
|
||||
notify($accessmanager->cannot_review_message($options));
|
||||
close_window_button();
|
||||
}
|
||||
}
|
||||
|
||||
/// Load the questions and states.
|
||||
$questionids = array($questionid);
|
||||
$attemptobj->load_questions($questionids);
|
||||
$attemptobj->load_question_states($questionids);
|
||||
|
||||
/// If it was asked for, load another state, instead of the latest.
|
||||
if ($stateid) {
|
||||
if (! $state = $DB->get_record('question_states', array('id' => $stateid))) {
|
||||
print_error('invalidstateid', 'quiz');
|
||||
}
|
||||
if (! $attempt = $DB->get_record('quiz_attempts', array('uniqueid' => $state->attempt))) {
|
||||
print_error('invalidattemptid', 'quiz');
|
||||
}
|
||||
} elseif ($attemptid) {
|
||||
if (! $attempt = $DB->get_record('quiz_attempts', array('id' => $attemptid))) {
|
||||
print_error('invalidattemptid', 'quiz');
|
||||
}
|
||||
if (! $neweststateid = $DB->get_field('question_sessions', 'newest', array('attemptid' => $attempt->uniqueid, 'questionid' => $questionid))) {
|
||||
// newest_state not set, probably because this is an old attempt from the old quiz module code
|
||||
if (! $state = $DB->get_record('question_states', array('question' => $questionid, 'attempt' => $attempt->uniqueid))) {
|
||||
print_error('invalidquestionid', 'quiz');
|
||||
}
|
||||
} else {
|
||||
if (! $state = $DB->get_record('question_states', array('id' => $neweststateid))) {
|
||||
print_error('invalidstateid', 'quiz');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print_error('missingparameter');
|
||||
}
|
||||
if (! $question = $DB->get_record('question', array('id' => $state->question))) {
|
||||
print_error('questionmissing', 'quiz');
|
||||
}
|
||||
if (! $quiz = $DB->get_record('quiz', array('id' => $attempt->quiz))) {
|
||||
print_error('invalidcoursemodule');
|
||||
}
|
||||
if (! $course = $DB->get_record('course', array('id' => $quiz->course))) {
|
||||
print_error('coursemisconf');
|
||||
}
|
||||
if (! $cm = get_coursemodule_from_instance('quiz', $quiz->id, $course->id)) {
|
||||
print_error('invalidcoursemodule');
|
||||
$attemptobj->load_specific_question_state($questionid, $stateid);
|
||||
}
|
||||
|
||||
require_login($course->id, false, $cm);
|
||||
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
|
||||
|
||||
if (!has_capability('mod/quiz:viewreports', $context)) {
|
||||
if (!$attempt->timefinish) {
|
||||
redirect('attempt.php?attempt='.$attempt->id);
|
||||
}
|
||||
// If not even responses are to be shown in review then we
|
||||
// don't allow any review
|
||||
if (!($quiz->review & QUIZ_REVIEW_RESPONSES)) {
|
||||
print_error("noreview", "quiz");
|
||||
}
|
||||
if ((time() - $attempt->timefinish) > 120) { // always allow review right after attempt
|
||||
if ((!$quiz->timeclose or time() < $quiz->timeclose) and !($quiz->review & QUIZ_REVIEW_OPEN)) {
|
||||
print_error("noreviewuntil", "quiz", '', userdate($quiz->timeclose));
|
||||
}
|
||||
if ($quiz->timeclose and time() >= $quiz->timeclose and !($quiz->review & QUIZ_REVIEW_CLOSED)) {
|
||||
print_error("noreview", "quiz");
|
||||
}
|
||||
}
|
||||
if ($attempt->userid != $USER->id) {
|
||||
print_error('notyourattempt', 'quiz');
|
||||
}
|
||||
}
|
||||
|
||||
//add_to_log($course->id, 'quiz', 'review', "review.php?id=$cm->id&attempt=$attempt->id", "$quiz->id", "$cm->id");
|
||||
/// Log this review.
|
||||
add_to_log($attemptobj->get_courseid(), 'quiz', 'review', 'reviewquestion.php?attempt=' .
|
||||
$attemptobj->get_attemptid() . '&question=' . $questionid .
|
||||
($stateid ? '&state=' . $stateid : ''),
|
||||
$attemptobj->get_quizid(), $attemptobj->get_cmid());
|
||||
|
||||
/// Print the page header
|
||||
|
||||
$strquizzes = get_string('modulenameplural', 'quiz');
|
||||
|
||||
print_header();
|
||||
|
||||
echo '<div id="overDiv" style="position:absolute; visibility:hidden; z-index:1000;"></div>'; // for overlib
|
||||
|
||||
/// Print heading
|
||||
print_heading(format_string($question->name));
|
||||
|
||||
$question->maxgrade = $DB->get_field('quiz_question_instances', 'grade', array('quiz' => $quiz->id, 'question' => $question->id));
|
||||
// Some of the questions code is optimised to work with several questions
|
||||
// at once so it wants the question to be in an array.
|
||||
$key = $question->id;
|
||||
$questions[$key] = &$question;
|
||||
// Add additional questiontype specific information to the question objects.
|
||||
if (!get_question_options($questions)) {
|
||||
print_error('cannotloadtypeinfo', 'quiz');
|
||||
}
|
||||
|
||||
$session = $DB->get_record('question_sessions', array('attemptid' => $attempt->uniqueid, 'questionid' => $question->id));
|
||||
$state->sumpenalty = $session->sumpenalty;
|
||||
$state->manualcomment = $session->manualcomment;
|
||||
restore_question_state($question, $state);
|
||||
$state->last_graded = $state;
|
||||
|
||||
$options = quiz_get_reviewoptions($quiz, $attempt, $context);
|
||||
|
||||
/// Print infobox
|
||||
$table->align = array("right", "left");
|
||||
if ($attempt->userid <> $USER->id) {
|
||||
$rows = array();
|
||||
|
||||
/// User picture and name.
|
||||
if ($attemptobj->get_userid() <> $USER->id) {
|
||||
// Print user picture and name
|
||||
$student = $DB->get_record('user', array('id' => $attempt->userid));
|
||||
$picture = print_user_picture($student, $course->id, $student->picture, false, true);
|
||||
$table->data[] = array($picture, fullname($student, true));
|
||||
$student = $DB->get_record('user', array('id' => $attemptobj->get_userid()));
|
||||
$picture = print_user_picture($student, $attemptobj->get_courseid(), $student->picture, false, true);
|
||||
$rows[] = '<tr><th scope="row" class="cell">' . $picture . '</th><td class="cell"><a href="' .
|
||||
$CFG->wwwroot . '/user/view.php?id=' . $student->id . '&course=' . $attemptobj->get_courseid() . '">' .
|
||||
fullname($student, true) . '</a></td></tr>';
|
||||
}
|
||||
// print quiz name
|
||||
$table->data[] = array(get_string('modulename', 'quiz').':', format_string($quiz->name));
|
||||
if (has_capability('mod/quiz:viewreports', $context) and
|
||||
count($attempts = $DB->get_records_select('quiz_attempts', "quiz = ? AND userid =?", array($quiz->id, $attempt->userid), 'attempt ASC')) > 1) {
|
||||
// print list of attempts
|
||||
$attemptlist = '';
|
||||
foreach ($attempts as $at) {
|
||||
$attemptlist .= ($at->id == $attempt->id)
|
||||
? '<b>'.$at->attempt.'</b>, '
|
||||
: '<a href="reviewquestion.php?attempt='.$at->id.'&question='.$question->id.'&number='.$number.'">'.$at->attempt.'</a>, ';
|
||||
|
||||
/// Quiz name.
|
||||
$rows[] = '<tr><th scope="row" class="cell">' . get_string('modulename', 'quiz') .
|
||||
'</th><td class="cell">' . format_string($attemptobj->get_quiz_name()) . '</td></tr>';
|
||||
|
||||
/// Question name.
|
||||
$rows[] = '<tr><th scope="row" class="cell">' . get_string('question', 'quiz') .
|
||||
'</th><td class="cell">' . format_string(
|
||||
$attemptobj->get_question($questionid)->name) . '</td></tr>';
|
||||
|
||||
/// Other attempts at the quiz.
|
||||
if ($attemptobj->has_capability('mod/quiz:viewreports')) {
|
||||
$attemptlist = $attemptobj->links_to_other_attempts(
|
||||
'reviewquestion.php?attempt=' . $attemptobj->get_attemptid() .
|
||||
'&question=' . $questionid);
|
||||
if ($attemptlist) {
|
||||
$rows[] = '<tr><th scope="row" class="cell">' . get_string('attempts', 'quiz') .
|
||||
'</th><td class="cell">' . $attemptlist . '</td></tr>';
|
||||
}
|
||||
$table->data[] = array(get_string('attempts', 'quiz').':', trim($attemptlist, ' ,'));
|
||||
}
|
||||
if ($state->timestamp) {
|
||||
// print time stamp
|
||||
$table->data[] = array(get_string("completedon", "quiz").':', userdate($state->timestamp));
|
||||
}
|
||||
// Print info box unless it is empty
|
||||
if ($table->data) {
|
||||
print_table($table);
|
||||
}
|
||||
|
||||
print_question($question, $state, $number, $quiz, $options);
|
||||
/// Timestamp of this action.
|
||||
$timestamp = $attemptobj->get_question_state($questionid)->timestamp;
|
||||
if ($timestamp) {
|
||||
$rows[] = '<tr><th scope="row" class="cell">' . get_string('completedon', 'quiz') .
|
||||
'</th><td class="cell">' . userdate($timestamp) . '</td></tr>';
|
||||
}
|
||||
|
||||
/// Now output the summary table, if there are any rows to be shown.
|
||||
if (!empty($rows)) {
|
||||
echo '<table class="generaltable generalbox quizreviewsummary"><tbody>', "\n";
|
||||
echo implode("\n", $rows);
|
||||
echo "\n</tbody></table>\n";
|
||||
}
|
||||
|
||||
/// Print the question in the requested state.
|
||||
$attemptobj->print_question($questionid);
|
||||
|
||||
/// Finish the page
|
||||
print_footer();
|
||||
|
||||
?>
|
||||
|
||||
@@ -923,8 +923,10 @@ class default_questiontype {
|
||||
$link = '<b>'.$st->seq_number.'</b>';
|
||||
} else {
|
||||
if(isset($options->questionreviewlink)) {
|
||||
$link = link_to_popup_window ($options->questionreviewlink.'?state='.$st->id.'&number='.$number,
|
||||
'reviewquestion', $st->seq_number, 450, 650, $strreviewquestion, 'none', true);
|
||||
$link = link_to_popup_window($options->questionreviewlink .
|
||||
'&question=' . $question->id . '&state=' . $st->id,
|
||||
'reviewquestion', $st->seq_number, 450, 650, $strreviewquestion,
|
||||
'none', true);
|
||||
} else {
|
||||
$link = $st->seq_number;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user