reordered according to the line numbers you specified.</p>
<p>Line numbers do not have to be integers, you can also use numbers with
- a decimal point if you find that convenient</p>
+ a decimal point if you find that convenient.</p>
<p>Page breaks are given line numbers as well, to allow you to move them
around in the same manner. If you have unticked the "Show page breaks"
$string['minutes'] = 'Minutes';
$string['missinganswer'] = 'Too few :ANSWER, :Lx, :Rx statements for question line $a. You must define at last 2 possible answers';
$string['missingcorrectanswer'] = 'Correct answer must be specified';
+$string['missingformula'] = 'Missing formula';
$string['missingitemtypename'] = 'Missing name';
$string['missingname'] = 'Missing question name';
$string['missingquestion'] = 'Missing question label after line $a';
*
* TODO: Make sure this is not quiz-specific
*
-* @return boolean Indicates success/failure
+* @return boolean Indicates whether the grade has changed
* @param object $question A question object
* @param object $attempt The attempt, in which the question needs to be regraded.
* @param object $cmoptions
$replaystate = clone($state);
$replaystate->last_graded = $state;
- $changed = 0;
+ $changed = false;
for($j = 1; $j < count($states); $j++) {
restore_question_state($question, $states[$j]);
$action = new stdClass;
$action->responses = $states[$j]->responses;
$action->timestamp = $states[$j]->timestamp;
- // Close the last state of a finished attempt
- if (((count($states) - 1) === $j) && ($attempt->timefinish > 0)) {
- $action->event = QUESTION_EVENTCLOSE;
-
// Change event to submit so that it will be reprocessed
- } else if (QUESTION_EVENTCLOSE == $states[$j]->event
+ if (QUESTION_EVENTCLOSE == $states[$j]->event
or QUESTION_EVENTGRADE == $states[$j]->event
or QUESTION_EVENTCLOSEANDGRADE == $states[$j]->event) {
$action->event = QUESTION_EVENTSUBMIT;
// We need rounding here because grades in the DB get truncated
// e.g. 0.33333 != 0.3333333, but we want them to be equal here
- if (round((float)$replaystate->grade, 5) != round((float)$states[$j]->grade, 5)) {
- $changed++;
+ if ((round((float)$replaystate->raw_grade, 5) != round((float)$states[$j]->raw_grade, 5))
+ or (round((float)$replaystate->penalty, 5) != round((float)$states[$j]->penalty, 5))
+ or (round((float)$replaystate->grade, 5) != round((float)$states[$j]->grade, 5))) {
+ $changed = true;
}
$replaystate->id = $states[$j]->id;
$replaystate->update = true; // This will ensure that the existing database entry is updated rather than a new one created
save_question_session($question, $replaystate);
}
- if ($verbose) {
- if ($changed) {
- link_to_popup_window ('/question/reviewquestion.php?attempt='.$attempt->id.'&question='.$question->id,
- 'reviewquestion', ' #'.$attempt->id, 450, 550, get_string('reviewresponse', 'quiz'));
- update_record('quiz_attempts', $attempt);
- } else {
- echo ' #'.$attempt->id;
- }
- echo "\n"; @flush(); @ob_flush();
+ if ($changed) {
+ update_record('quiz_attempts', $attempt);
}
- return true;
+ return $changed;
}
- return true;
+ return false;
}
/**
return array('request'=>$connection->__getLastRequest(), 'response'=>$connection->__getLastResponse());
}
-// Fix simple type encoding - work around a bug in PHP
+// Fix simple type encoding - work around a bug in early versions of PHP5 < 5.0.3, see http://bugs.php.net/bug.php?id=31832
function soap_encode($value, $name, $type, $namespace, $encode=XSD_STRING) {
$value = new SoapVar($value, $encode, $type, $namespace);
if ('' === $name)
return new SoapParam($value, $name);
}
-// Fix complex type encoding - work around a bug in PHP
+// Fix complex type encoding - work around a bug in early versions of PHP5 < 5.0.3, see http://bugs.php.net/bug.php?id=31832
function soap_encode_object($value, $name, $type, $namespace) {
if (!is_object($value))
return $value;
return new SoapParam($value, $name);
}
-// Fix array encoding - work around a bug in PHP
+// Fix array encoding - work around a bug in early versions of PHP5 < 5.0.3, see http://bugs.php.net/bug.php?id=31832
function soap_encode_array($value, $name, $type, $namespace) {
if (!is_array($value))
return $value;
return new SoapParam($value, $name);
}
-?>
+?>
\ No newline at end of file
if (!set_field('quiz', 'questions', $modform->questions, 'id', $modform->instance)) {
error('Could not save question list');
}
+ delete_records('quiz_question_instances', 'quiz', $modform->instance, 'question', $question);
+ return true;
}
return true;
}
- function print_header_and_tabs($cm, $course, $quiz, $reportmode="overview"){
+ function print_header_and_tabs($cm, $course, $quiz, $reportmode="overview", $meta=""){
global $CFG;
/// Define some strings
$strquizzes = get_string("modulenameplural", "quiz");
print_header_simple(format_string($quiz->name), "",
"<a href=\"index.php?id=$course->id\">$strquizzes</a>
-> ".format_string($quiz->name),
- "", "", true, update_module_button($cm->id, $course->id, $strquiz), navmenu($course, $cm));
+ '', $meta, true, update_module_button($cm->id, $course->id, $strquiz), navmenu($course, $cm));
/// Print the tabs
$currenttab = 'reports';
$mode = $reportmode;
restore_question_state($question, $state);
$state->last_graded = $state;
- $options = quiz_get_reviewoptions($quiz, $attempt, isteacher());
+ $options = quiz_get_reviewoptions($quiz, $attempt, true);
$options->validation = ($state->event == QUESTION_EVENTVALIDATE); // not sure what this is
//$options->history = 'all'; // had this on, but seemed confusing for this
get_question_options($questions);
/// Print heading
- print_heading(get_string('regradingquiz', 'quiz', $quiz->name));
+ print_heading(get_string('regradingquiz', 'quiz', format_string($quiz->name)));
echo '<center>';
print_string('regradedisplayexplanation', 'quiz');
echo '<center>';
echo '<b>'.get_string('regradingquestion', 'quiz', $question->name).'</b> '.get_string('attempts', 'quiz').": \n";
foreach ($attempts as $attempt) {
set_time_limit(30);
- regrade_question_in_attempt($question, $attempt, $quiz, true);
+ $changed = regrade_question_in_attempt($question, $attempt, $quiz, true);
+ if ($changed) {
+ link_to_popup_window ('/mod/quiz/reviewquestion.php?attempt='.$attempt->id.'&question='.$question->id,
+ 'reviewquestion', ' #'.$attempt->id, 450, 550, get_string('reviewresponse', 'quiz'));
+ } else {
+ echo ' #'.$attempt->id;
+ }
}
echo '<br/ >';
// the following makes sure that the output is sent immediately.
/// Print heading and tabs if this is part of a preview
if ($isteacher) {
- $currenttab = ($attempt->userid == $USER->id) ? 'preview' : '';
+ if ($attempt->userid == $USER->id) { // this is the report on a preview
+ $currenttab = 'preview';
+ } else {
+ $currenttab = 'reports';
+ $mode = '';
+ }
include('tabs.php');
} else {
print_heading(format_string($quiz->name));
if (! $state = get_record('question_states', 'id', $stateid)) {
error('Invalid state id');
}
- if (! $attempt = get_record('quiz_attempts', 'id', $state->attempt)) {
+ if (! $attempt = get_record('quiz_attempts', 'uniqueid', $state->attempt)) {
error('No such attempt ID exists');
}
} elseif ($attemptid) {
$row[] = new tabobject('info', "$CFG->wwwroot/mod/quiz/view.php?q=$quiz->id", get_string('info', 'quiz'));
$row[] = new tabobject('reports', "$CFG->wwwroot/mod/quiz/report.php?q=$quiz->id", get_string('results', 'quiz'));
- $row[] = new tabobject('preview', "$CFG->wwwroot/mod/quiz/attempt.php?q=$quiz->id", get_string('preview', 'quiz'), get_string('previewquiz', 'quiz', format_string($quiz->name)));
+ $row[] = new tabobject('preview', "$CFG->wwwroot/mod/quiz/attempt.php?q=$quiz->id", get_string('preview', 'quiz'));
if (isteacheredit($course->id)) {
- $row[] = new tabobject('edit', "$CFG->wwwroot/mod/quiz/edit.php?quizid=$quiz->id", get_string('edit'), get_string('editquizquestions', 'quiz'));
+ $row[] = new tabobject('edit', "$CFG->wwwroot/mod/quiz/edit.php?quizid=$quiz->id", get_string('edit'));
}
$tabs[] = $row;
$row[] = new tabobject('categories', "$CFG->wwwroot/question/category.php?id=$course->id", get_string('categories', 'quiz'), get_string('editqcats', 'quiz'));
$row[] = new tabobject('import', "$CFG->wwwroot/question/import.php?course=$course->id", get_string('import', 'quiz'), get_string('importquestions', 'quiz'));
$row[] = new tabobject('export', "$CFG->wwwroot/question/export.php?courseid=$course->id", get_string('export', 'quiz'), get_string('exportquestions', 'quiz'));
- $row[] = new tabobject('update', "$CFG->wwwroot/course/mod.php?update=$cm->id&sesskey=$USER->sesskey", get_string('settings'), get_string('updatesettings'));
+ $row[] = new tabobject('update', "$CFG->wwwroot/course/mod.php?update=$cm->id&sesskey=$USER->sesskey", get_string('settings'), get_string('updatesettings', 'quiz'));
$tabs[] = $row;
}
/// Now print table with existing attempts
- if ($numattempts) {
+ if ($attempts) {
/// prepare table header
+ $table->head = array($strattempt, $strtimecompleted);
+ $table->align = array("center", "left");
+ $table->size = array("", "");
if ($quiz->grade and $quiz->sumgrades) { // Grades used so have more columns in table
if ($quiz->grade <> $quiz->sumgrades) {
- $table->head = array($strattempt, $strtimetaken, $strtimecompleted, "$strmarks / $quiz->sumgrades", "$strgrade / $quiz->grade");
- $table->align = array("center", "center", "left", "right", "right");
- $table->size = array("", "", "", "", "");
- } else {
- $table->head = array($strattempt, $strtimetaken, $strtimecompleted, "$strgrade / $quiz->grade");
- $table->align = array("center", "center", "left", "right");
- $table->size = array("", "", "", "");
+ $table->head[] = "$strmarks / $quiz->sumgrades";
+ $table->align[] = 'right';
+ $table->size[] = '';
}
-
- } else { // No grades are being used
- $table->head = array($strattempt, $strtimetaken, $strtimecompleted);
- $table->align = array("center", "center", "left");
- $table->size = array("", "", "");
+ $table->head[] = "$strgrade / $quiz->grade";
+ $table->align[] = 'right';
+ $table->size[] = '';
+ }
+ if (isset($quiz->showtimetaken)) {
+ $table->head[] = $strtimetaken;
+ $table->align[] = 'center';
+ $table->size[] = '';
}
/// One row for each attempt
if ($quiz->grade <> $quiz->sumgrades) {
$table->data[] = array( $attempt->attempt,
- $timetaken,
$datecompleted,
$attemptmark, $attemptgrade);
} else {
$table->data[] = array( $attempt->attempt,
- $timetaken,
$datecompleted,
$attemptgrade);
}
}
}
$table->data[] = array( $attempt->attempt,
- $timetaken,
$datecompleted);
}
+ if (isset($quiz->showtimetaken)) {
+ $table->data[] = $timetaken;
+ }
}
print_table($table);
}
return parent::grade_responses($numericalquestion, $state, $cmoptions);
}
- function response_summary($state, $length=80) {
+ function response_summary($question, $state, $length=80) {
// The actual response is the bit after the hyphen
return substr($state->answer, strpos($state->answer, '-')+1, $length);
}
</div>
<?php if ($image) { ?>
- <img class="qimage" src="<?php echo $q->imageurl; ?>" alt="" />
+ <img class="qimage" src="<?php echo $image; ?>" alt="" />
<?php } ?>
</div>
</td></tr></table>
</div>
<?php if ($image) { ?>
- <img class="qimage" src="<?php echo $q->imageurl; ?>" alt="" />
+ <img class="qimage" src="<?php echo $image; ?>" alt="" />
<?php } ?>
<div class="ablock clearfix">
and $options->correct_responses
and isset($correctanswers[$subquestion->id])
and ($correctanswers[$subquestion->id] == $response)) {
- $a->class = ' class="highlight" ';
+ $a->class = ' highlight ';
} else {
$a->class = '';
}
return null;
}
}
+
+ function response_summary($question, $state, $length=80) {
+ // This should almost certainly be overridden
+ return substr(implode(',', $this->get_actual_response($question, $state)), 0, $length);
+ }
/// BACKUP FUNCTIONS ////////////////////////////
</div>
<?php if ($image) { ?>
- <img class="qimage" src="<?php echo $q->imageurl; ?>" alt="" />
+ <img class="qimage" src="<?php echo $image; ?>" alt="" />
<?php } ?>
<div class="ablock clearfix">
</tr>
<?php } ?>
</table>
-</div>
\ No newline at end of file
+</div>
// will also create difficulties if questiontype specific tables reference the id.
// First we get all the existing wrapped questions
- if (!$oldwrappedids = get_records('question', 'parent', $question->id, '', 'id, id')) {
- // We need to select 'id, id' because the first one is consumed by
- // get_records.
+ if (!$oldwrappedids = get_field('question_multianswers', 'sequence', 'question', $question->id)) {
$oldwrappedids = array();
+ } else {
+ $oldwrappedids = explode(',', $oldwrappedids);
}
- $oldwrappedids = array_keys($oldwrappedids);
$sequence = array();
foreach($question->options->questions as $wrapped) {
// if we still have some old wrapped question ids, reuse the next of them
</div>
<?php if ($image) { ?>
- <img class="qimage" src="<?php echo $q->imageurl; ?>" alt="" />
+ <img class="qimage" src="<?php echo $image; ?>" alt="" />
<?php } ?>
<div class="ablock clearfix">
$table->size = array ('', '', '', '', '', '', '');
$table->width = '100%';
foreach ($states as $st) {
+ $st->responses[''] = $st->answer;
+ $this->restore_session_and_responses($question, $st);
$b = ($state->id == $st->id) ? '<b>' : '';
$be = ($state->id == $st->id) ? '</b>' : '';
if ($state->id == $st->id) {
$table->data[] = array (
$link,
$b.get_string('event'.$st->event, 'quiz').$be,
- $b.$this->response_summary($st).$be,
+ $b.$this->response_summary($question, $st).$be,
$b.userdate($st->timestamp, get_string('timestr', 'quiz')).$be,
$b.round($st->raw_grade, $cmoptions->decimalpoints).$be,
$b.round($st->penalty, $cmoptions->decimalpoints).$be,
* summarizes the student's response in the given $state. This is used for
* example in the response history table
* @return string The summary of the student response
+ * @param object $question
* @param object $state The state whose responses are to be summarized
* @param int $length The maximum length of the returned string
*/
- function response_summary($state, $length=80) {
+ function response_summary($question, $state, $length=80) {
// This should almost certainly be overridden
return substr($state->answer, 0, $length);
}
/// QUESTION TYPE CLASS //////////////////
class random_qtype extends default_questiontype {
- var $excludedtypes = array('random', 'randomsamatch', 'essay', 'description');
+ var $excludedtypes = array("'random'", "'randomsamatch'", "'essay'", "'description'");
// Carries questions available as randoms sorted by category
// This array is used when needed only
</div>
<?php if ($image) { ?>
- <img class="qimage" src="<?php echo $q->imageurl; ?>" alt="" />
+ <img class="qimage" src="<?php echo $imagel; ?>" alt="" />
<?php } ?>
<div class="ablock clearfix">
}
}
+ $emptyanswer->answer = '';
$i = count($answers);
$limit = QUESTION_NUMANS;
$limit = $limit <= $i ? $i+1 : $limit;
for (; $i < $limit; $i++) {
- $answers[] = ""; // Make answer slots, default as blank
+ $answers[] = $emptyanswer; // Make answer slots, default as blank
}
print_heading_with_help(get_string("editingshortanswer", "quiz"), "shortanswer", "quiz");
</div>
<?php if ($image) { ?>
- <img class="qimage" src="<?php echo $q->imageurl; ?>" alt="" />
+ <img class="qimage" src="<?php echo $image; ?>" alt="" />
<?php } ?>
<div class="ablock clearfix">
return true;
}
+ function response_summary($question, $state, $length=80) {
+ if (isset($question->options->answers[$state->answer])) {
+ $responses = $question->options->answers[$state->answer]->answer;
+ } else {
+ $responses = '';
+ }
+ return $responses;
+ }
+
function get_actual_response($question, $state) {
if (isset($question->options->answers[$state->responses['']])) {
$responses[] = $question->options->answers[$state->responses['']]->answer;