MDL-5969 Let multiple choice questions have feedback that does not depend on the chosen answer

In passing, I fixed MDL-6297 Export of multichoice questions in Moodle XML format doesn't save shuffle option too.
This commit is contained in:
tjhunt 2006-08-24 10:22:43 +00:00
parent 6e557c0806
commit 307f045f07
14 changed files with 184 additions and 38 deletions

View File

@ -0,0 +1,25 @@
<?php
/*
* Created on Aug 20, 2006
*
* To change the template for this generated file go to
* Window - Preferences - PHPeclipse - PHP - Code Templates
*/
$string['answersingleno'] = 'Multiple answers allowed';
$string['answersingleyes'] = 'One answer only';
$string['choiceno'] = 'Choice $a';
$string['choices'] = 'Available choices';
$string['editingmultichoice'] = 'Editing a Multiple Choice question';
$string['fillouttwochoices'] = 'You must fill out at least two choices. Choices left blank will not be used.';
$string['fractionsaddwrong'] = 'The positive grades you have chosen do not add up to 100%%<br />Instead, they add up to $a%%<br />Do you want to go back and fix this question?';
$string['fractionsnomax'] = 'One of the answers should be 100%%, so that it is<br />possible to get a full grade for this question.<br />Do you want to go back and fix this question?';
$string['feedback'] = 'Feedback';
$string['notenoughanswers'] = 'This type of question requires at least $a answers';
$string['overallcorrectfeedback'] = 'Feedback for any correct answer';
$string['overallpartiallycorrectfeedback'] = 'Feedback for any partially correct answer';
$string['overallincorrectfeedback'] = 'Feedback for any incorrect answer';
$string['shuffleanswers'] = 'Shuffle answers';
$string['singleanswer'] = 'Choose one answer.';
?>

View File

@ -82,6 +82,21 @@ class qformat_xml extends qformat_default {
return addslashes(trim( $data ));
}
/**
* Process text from an element in the XML that may or not be there.
* @param string $subelement the name of the element which is either present or missing.
* @param array $question a bit of xml tree, this method looks for $question['#'][$subelement][0]['#']['text'].
* @return string If $subelement is present, return the content of the text tag inside it.
* Otherwise returns an empty string.
*/
function import_optional_text($subelement, $question) {
if (array_key_exists($subelement, $question['#'])) {
return $this->import_text($question['#'][$subelement][0]['#']['text']);
} else {
return '';
}
}
/**
* import parts of question common to all types
* @param array question question array from xml tree
@ -149,7 +164,16 @@ class qformat_xml extends qformat_default {
$qo->qtype = MULTICHOICE;
$single = $question['#']['single'][0]['#'];
$qo->single = $this->trans_single( $single );
if (array_key_exists('shuffleanswers', $question['#'])) {
$shuffleanswers = $question['#']['shuffleanswers'][0]['#'];
} else {
$shuffleanswers = 'false';
}
$qo->$shuffleanswers = $this->trans_single($shuffleanswers);
$qo->correctfeedback = $this->import_optional_text('correctfeedback', $question);
$qo->partiallycorrectfeedback = $this->import_optional_text('partiallycorrectfeedback', $question);
$qo->incorrectfeedback = $this->import_optional_text('incorrectfeedback', $question);
// run through the answers
$answers = $question['#']['answer'];
$a_count = 0;
@ -671,6 +695,10 @@ class qformat_xml extends qformat_default {
break;
case MULTICHOICE:
$expout .= " <single>".$this->get_single($question->options->single)."</single>\n";
$expout .= " <shuffleanswers>".$this->get_single($question->options->shuffleanswers)."</shuffleanswers>\n";
$expout .= " <correctfeedback>".$this->writetext($question->options->correctfeedback, 3)."</correctfeedback>\n";
$expout .= " <partiallycorrectfeedback>".$this->writetext($question->options->partiallycorrectfeedback, 3)."</partiallycorrectfeedback>\n";
$expout .= " <incorrectfeedback>".$this->writetext($question->options->incorrectfeedback, 3)."</incorrectfeedback>\n";
foreach($question->options->answers as $answer) {
$percent = $answer->fraction * 100;
$expout .= " <answer fraction=\"$percent\">\n";

View File

@ -614,6 +614,7 @@
$state->grade = backup_todb($res_info['#']['GRADE']['0']['#']);
$state->raw_grade = backup_todb($res_info['#']['RAW_GRADE']['0']['#']);
$state->penalty = backup_todb($res_info['#']['PENALTY']['0']['#']);
$state->oldid = $oldid; // So it is available to restore_recode_answer.
//We have to recode the question field
$question = backup_getid($restore->backup_unique_code,"question",$state->question);

View File

@ -4,8 +4,15 @@
function qtype_multichoice_upgrade($oldversion=0) {
global $CFG;
return true;
$success = true;
if ($success && $oldversion < 2006081900) {
$success = $success && table_column('question_multichoice', '', 'correctfeedback', 'text', '', '', '');
$success = $success && table_column('question_multichoice', '', 'partiallycorrectfeedback', 'text', '', '', '');
$success = $success && table_column('question_multichoice', '', 'incorrectfeedback', 'text', '', '', '');
}
return $success;
}
?>

View File

@ -11,6 +11,9 @@ CREATE TABLE prefix_question_multichoice (
answers varchar(255) NOT NULL default '',
single tinyint(4) NOT NULL default '0',
shuffleanswers tinyint(4) NOT NULL default '1',
correctfeedback text NOT NULL default '',
partiallycorrectfeedback text NOT NULL default '',
incorrectfeedback text NOT NULL default '',
PRIMARY KEY (id),
KEY question (question)
) TYPE=MyISAM COMMENT='Options for multiple choice questions';

View File

@ -4,8 +4,15 @@
function qtype_multichoice_upgrade($oldversion=0) {
global $CFG;
return true;
$success = true;
if ($success && $oldversion < 2006081900) {
$success = $success && table_column('question_multichoice', '', 'correctfeedback', 'text', '', '', '');
$success = $success && table_column('question_multichoice', '', 'partiallycorrectfeedback', 'text', '', '', '');
$success = $success && table_column('question_multichoice', '', 'incorrectfeedback', 'text', '', '', '');
}
return $success;
}
?>

View File

@ -11,7 +11,10 @@ CREATE TABLE prefix_question_multichoice (
layout integer NOT NULL default '0',
answers varchar(255) NOT NULL default '',
single integer NOT NULL default '0',
shuffleanswers integer NOT NULL default '1'
shuffleanswers integer NOT NULL default '1',
correctfeedback text NOT NULL default '',
partiallycorrectfeedback text NOT NULL default '',
incorrectfeedback text NOT NULL default ''
);
CREATE INDEX prefix_question_multichoice_question_idx ON prefix_question_multichoice (question);

View File

@ -28,5 +28,10 @@
</tr>
<?php } ?>
</table>
<?php if ($feedback) { ?>
<div class="feedback">
<?php echo $feedback ?>
</div>
<?php } ?>
<?php $this->print_question_submit_buttons($question, $state, $cmoptions, $options); ?>
</div>

View File

@ -2,28 +2,28 @@
$QTYPES[$question->qtype]->print_question_form_start($question, array(), $course, $usehtmleditor);
?>
<tr valign="top">
<td align="right"><b><?php print_string("answerhowmany", "quiz") ?>:</b></td>
<td align="right"><b><?php print_string("answerhowmany", "qtype_multichoice") ?>:</b></td>
<td align="left">
<?php
$menu[0] = get_string("answersingleno", "quiz");
$menu[1] = get_string("answersingleyes", "quiz");
$menu[0] = get_string("answersingleno", "qtype_multichoice");
$menu[1] = get_string("answersingleyes", "qtype_multichoice");
choose_from_menu($menu, "single", "$options->single", "");
unset($menu);
?>
</td>
</tr>
<tr valign="top">
<td align="right"><b><?php print_string("shuffleanswers", "quiz") ?>:</b></td>
<td align="right"><b><?php print_string("shuffleanswers", "qtype_multichoice") ?>:</b></td>
<td align="left">
<?php
choose_from_menu($yesnooptions, "shuffleanswers", "$options->shuffleanswers", "");
helpbutton("multichoiceshuffle", get_string("shuffleanswers","quiz"), "quiz");
helpbutton("multichoiceshuffle", get_string("shuffleanswers","qtype_multichoice"), "quiz");
?>
</td>
</tr>
<tr valign="top">
<td align="right"><b><?php print_string("choices", "quiz") ?></b>:</td>
<td align="left"><?php print_string("fillouttwochoices", "quiz") ?></td>
<td align="right"><b><?php print_string("choices", "qtype_multichoice") ?></b>:</td>
<td align="left"><?php print_string("fillouttwochoices", "qtype_multichoice") ?></td>
</tr>
<?php
@ -36,9 +36,9 @@ for ($i=1; $i<=count($answers); $i++) {
?>
<tr valign="top">
<td align="right"><b><?php echo get_string("choice", "quiz")." $i"; ?>:</b></td>
<td align="right"><b><?php print_string("choiceno", "qtype_multichoice", $i); ?>:</b></td>
<td align="left">
<input type="text" name="answer[]" size="50" value="<?php p($answers[$i-1]->answer) ?>" alt="<?php echo get_string("choice", "quiz")." $i"; ?>"/>&nbsp;&nbsp;
<input type="text" name="answer[]" size="50" value="<?php p($answers[$i-1]->answer) ?>" />&nbsp;&nbsp;
<?php
print_string("grade");
echo ":&nbsp;";
@ -49,7 +49,7 @@ for ($i=1; $i<=count($answers); $i++) {
</tr>
<tr valign="top">
<td align="right"><b><?php print_string("feedback", "quiz") ?>:</b></td>
<td align="right"><b><?php print_string("feedback", "qtype_multichoice") ?>:</b></td>
<td align="left">
<textarea name="feedback[]" rows="2" cols="50"><?php p($answers[$i-1]->feedback) ?></textarea>
</td>
@ -61,7 +61,33 @@ for ($i=1; $i<=count($answers); $i++) {
<?php
} /// End of loop, printing answers
?>
<tr valign="top">
<td align="right"><b><?php print_string("overallcorrectfeedback", "qtype_multichoice") ?>:</b></td>
<td align="left">
<textarea name="correctfeedback" rows="4" cols="50"><?php p($options->correctfeedback) ?></textarea>
</td>
</tr>
<tr valign="top">
<td align="right"><b><?php print_string("overallpartiallycorrectfeedback", "qtype_multichoice") ?>:</b></td>
<td align="left">
<textarea name="partiallycorrectfeedback" rows="4" cols="50"><?php p($options->partiallycorrectfeedback) ?></textarea>
</td>
</tr>
<tr valign="top">
<td align="right"><b><?php print_string("overallincorrectfeedback", "qtype_multichoice") ?>:</b></td>
<td align="left">
<textarea name="incorrectfeedback" rows="4" cols="50"><?php p($options->incorrectfeedback) ?></textarea>
</td>
</tr>
<tr valign="top">
<td colspan="2">&nbsp;</td>
</tr>
<?php
$QTYPES[$question->qtype]->print_replacement_options($question, $course, $contextquiz);
$QTYPES[$question->qtype]->print_question_form_end($question);
?>

View File

@ -5,6 +5,9 @@
} else {
$options->single = 1;
$options->shuffleanswers = 1;
$options->correctfeedback = '';
$options->partiallycorrectfeedback = '';
$options->incorrectfeedback = '';
}
if (!empty($options->answers)) {
$answersraw = get_records_list("question_answers", "id", $options->answers);
@ -29,7 +32,7 @@
$yesnooptions[0] = get_string("no");
$yesnooptions[1] = get_string("yes");
print_heading_with_help(get_string("editingmultichoice", "quiz"), "multichoice", "quiz");
print_heading_with_help(get_string("editingmultichoice", "qtype_multichoice"), "multichoice", "quiz");
require("$CFG->dirroot/question/type/multichoice/editquestion.html");
?>

View File

@ -35,7 +35,7 @@ class question_multichoice_qtype extends default_questiontype {
}
function save_question_options($question) {
$result = new stdClass;
if (!$oldanswers = get_records("question_answers", "question",
$question->id, "id ASC")) {
$oldanswers = array();
@ -50,7 +50,7 @@ class question_multichoice_qtype extends default_questiontype {
}
$answercount += count($oldanswers);
if ($answercount < 2) { // check there are at lest 2 answers for multiple choice
$result->notice = get_string("notenoughanswers", "quiz", "2");
$result->notice = get_string("notenoughanswers", "qtype_multichoice", "2");
return $result;
}
@ -93,20 +93,26 @@ class question_multichoice_qtype extends default_questiontype {
}
}
if ($options = get_record("question_multichoice", "question", $question->id)) {
$options->answers = implode(",",$answers);
$options->single = $question->single;
$options->shuffleanswers = $question->shuffleanswers;
$update = true;
$options = get_record("question_multichoice", "question", $question->id);
if (!$options) {
$update = false;
$options = new stdClass;
$options->question = $question->id;
}
$options->answers = implode(",",$answers);
$options->single = $question->single;
$options->shuffleanswers = $question->shuffleanswers;
$options->correctfeedback = trim($question->correctfeedback);
$options->partiallycorrectfeedback = trim($question->partiallycorrectfeedback);
$options->incorrectfeedback = trim($question->incorrectfeedback);
if ($update) {
if (!update_record("question_multichoice", $options)) {
$result->error = "Could not update quiz multichoice options! (id=$options->id)";
return $result;
}
} else {
unset($options);
$options->question = $question->id;
$options->answers = implode(",",$answers);
$options->single = $question->single;
$options->shuffleanswers = $question->shuffleanswers;
if (!insert_record("question_multichoice", $options)) {
$result->error = "Could not insert quiz multichoice options!";
return $result;
@ -124,14 +130,14 @@ class question_multichoice_qtype extends default_questiontype {
if ($options->single) {
if ($maxfraction != 1) {
$maxfraction = $maxfraction * 100;
$result->noticeyesno = get_string("fractionsnomax", "quiz", $maxfraction);
$result->noticeyesno = get_string("fractionsnomax", "qtype_multichoice", $maxfraction);
return $result;
}
} else {
$totalfraction = round($totalfraction,2);
if ($totalfraction != 1) {
$totalfraction = $totalfraction * 100;
$result->noticeyesno = get_string("fractionsaddwrong", "quiz", $totalfraction);
$result->noticeyesno = get_string("fractionsaddwrong", "qtype_multichoice", $totalfraction);
return $result;
}
}
@ -291,6 +297,7 @@ class question_multichoice_qtype extends default_questiontype {
? 'checked="checked"' : '';
}
$a = new stdClass;
$a->id = $question->name_prefix . $aid;
// Print the control
@ -314,6 +321,21 @@ class question_multichoice_qtype extends default_questiontype {
$anss[] = clone($a);
}
$feedback = '';
if ($options->feedback) {
if ($state->raw_grade >= $question->maxgrade/1.01) {
$feedback = $question->options->correctfeedback;
} else if ($state->raw_grade > 0) {
$feedback = $question->options->partiallycorrectfeedback;
} else {
$feedback = $question->options->incorrectfeedback;
}
$feedback = format_text($feedback,
$question->questiontextformat,
$formatoptions, $cmoptions->course);
}
include("$CFG->dirroot/question/type/multichoice/display.html");
}
@ -392,6 +414,9 @@ class question_multichoice_qtype extends default_questiontype {
fwrite ($bf,full_tag("ANSWERS",$level+1,false,$multichoice->answers));
fwrite ($bf,full_tag("SINGLE",$level+1,false,$multichoice->single));
fwrite ($bf,full_tag("SHUFFLEANSWERS",$level+1,false,$multichoice->shuffleanswers));
fwrite ($bf,full_tag("CORRECTFEEDBACK",$level+1,false,$multichoice->correctfeedback));
fwrite ($bf,full_tag("PARTIALLYCORRECTFEEDBACK",$level+1,false,$multichoice->partiallycorrectfeedback));
fwrite ($bf,full_tag("INCORRECTFEEDBACK",$level+1,false,$multichoice->incorrectfeedback));
$status = fwrite ($bf,end_tag("MULTICHOICE",$level,true));
}
@ -420,11 +445,27 @@ class question_multichoice_qtype extends default_questiontype {
$mul_info = $multichoices[$i];
//Now, build the question_multichoice record structure
$multichoice = new stdClass;
$multichoice->question = $new_question_id;
$multichoice->layout = backup_todb($mul_info['#']['LAYOUT']['0']['#']);
$multichoice->answers = backup_todb($mul_info['#']['ANSWERS']['0']['#']);
$multichoice->single = backup_todb($mul_info['#']['SINGLE']['0']['#']);
$multichoice->shuffleanswers = backup_todb($mul_info['#']['SHUFFLEANSWERS']['0']['#']);
if (array_key_exists("CORRECTFEEDBACK", $mul_info['#'])) {
$multichoice->correctfeedback = backup_todb($mul_info['#']['CORRECTFEEDBACK']['0']['#']);
} else {
$multichoice->correctfeedback = '';
}
if (array_key_exists("PARTIALLYCORRECTFEEDBACK", $mul_info['#'])) {
$multichoice->partiallycorrectfeedback = backup_todb($mul_info['#']['PARTIALLYCORRECTFEEDBACK']['0']['#']);
} else {
$multichoice->partiallycorrectfeedback = '';
}
if (array_key_exists("INCORRECTFEEDBACK", $mul_info['#'])) {
$multichoice->incorrectfeedback = backup_todb($mul_info['#']['INCORRECTFEEDBACK']['0']['#']);
} else {
$multichoice->incorrectfeedback = '';
}
//We have to recode the answers field (a list of answers id)
//Extracts answer id from sequence
@ -490,7 +531,7 @@ class question_multichoice_qtype extends default_questiontype {
if ($answer) {
$order[$key] = $answer->new_id;
} else {
echo 'Could not recode multichoice answer id '.$oldansid.' for state '.$oldid.'<br />';
echo 'Could not recode multichoice answer id '.$oldansid.' for state '.$state->oldid.'<br />';
}
}
}
@ -500,7 +541,7 @@ class question_multichoice_qtype extends default_questiontype {
if ($answer) {
$responses[$key] = $answer->new_id;
} else {
echo 'Could not recode multichoice response answer id '.$oldansid.' for state '.$oldid.'<br />';
echo 'Could not recode multichoice response answer id '.$oldansid.' for state '.$state->oldid.'<br />';
}
}
}

View File

@ -1,6 +1,6 @@
<?PHP // $Id$
$plugin->version = 2006032200;
$plugin->version = 2006081900;
$plugin->requires = 2006032200;
?>

View File

@ -615,10 +615,7 @@ table.message_search_results td {
.truefalse .answer {
background-color: #EEE;
}
.calculated .feedback,
.numerical .feedback,
.shortanswer .feedback,
.truefalse .feedback {
.que .feedback {
border-color: #DDD;
}
.que.multianswer .incorrect {

View File

@ -1208,7 +1208,7 @@ body#message-messages {
padding: 0 0 0.3em 0.3em;
border: 1px solid;
}
.multichoice .feedback {
.multichoice td.feedback {
width: auto;
vertical-align: top;
padding-top: 0.3em;