diff --git a/question/type/multianswer/question.php b/question/type/multianswer/question.php
index 1f8a572e5a6..d8f8c898ff7 100644
--- a/question/type/multianswer/question.php
+++ b/question/type/multianswer/question.php
@@ -118,7 +118,7 @@ class qtype_multianswer_question extends question_graded_automatically {
$substep = $this->get_substep(null, $i);
foreach ($subq->get_expected_data() as $name => $type) {
if ($subq->qtype->name() == 'multichoice' &&
- $subq->layout = qtype_multichoice_base::LAYOUT_DROPDOWN) {
+ $subq->layout == qtype_multichoice_base::LAYOUT_DROPDOWN) {
// Hack or MC inline does not work.
$expected[$substep->add_prefix($name)] = PARAM_RAW;
} else {
diff --git a/question/type/multianswer/questiontype.php b/question/type/multianswer/questiontype.php
index 0994d622af8..dbd0af6ea91 100644
--- a/question/type/multianswer/questiontype.php
+++ b/question/type/multianswer/questiontype.php
@@ -26,6 +26,8 @@
defined('MOODLE_INTERNAL') || die();
+require_once($CFG->dirroot . '/question/type/multichoice/question.php');
+
/**
* The multi-answer question type class.
diff --git a/question/type/multianswer/renderer.php b/question/type/multianswer/renderer.php
index 09c79cd333b..2d96dcf6004 100644
--- a/question/type/multianswer/renderer.php
+++ b/question/type/multianswer/renderer.php
@@ -227,7 +227,7 @@ class qtype_multianswer_textfield_renderer extends qtype_multianswer_subq_render
/**
* Render an embedded multiple-choice question that is displayed as a select menu.
*
- * @copyright 2010 Pierre Pichet
+ * @copyright 2011 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qtype_multianswer_multichoice_inline_renderer
@@ -285,346 +285,145 @@ class qtype_multianswer_multichoice_inline_renderer
return $output;
}
+}
+
+
+/**
+ * Render an embedded multiple-choice question vertically, like for a normal
+ * multiple-choice question.
+ *
+ * @copyright 2010 Pierre Pichet
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class qtype_multianswer_multichoice_vertical_renderer extends qtype_multianswer_subq_renderer_base {
+
+ public function subquestion(question_attempt $qa, question_display_options $options,
+ $index, question_graded_automatically $subq) {
+
+ $fieldprefix = 'sub' . $index . '_';
+ $fieldname = $fieldprefix . 'answer';
+ $response = $qa->get_last_qt_var($fieldname);
- public function formulation_and_controls(question_attempt $qa,
- question_display_options $options) {
- $questiontot = $qa->get_question();
- $subquestion = $questiontot->subquestions[$qa->subquestionindex];
- $answers = $subquestion->answers;
- $correctanswers = $subquestion->get_correct_response();
- foreach ($correctanswers as $key => $value) {
- $correct = $value;
- }
- $order = $subquestion->get_order($qa);
- $response = $this->get_response($qa);
- $currentanswer = $response;
- $answername = $subquestion->fieldid.'answer';
- $inputname = $qa->get_qt_field_name($answername);
$inputattributes = array(
- 'type' => $this->get_input_type(),
- 'name' => $inputname,
+ 'type' => 'radio',
+ 'name' => $qa->get_qt_field_name($fieldname),
);
-
if ($options->readonly) {
$inputattributes['disabled'] = 'disabled';
- $readonly = 'disabled ="disabled"';
}
- $choices = array();
- $popup = '';
- $feedback = '';
- $answer = '';
- $classes = 'control';
- $feedbackimage = '';
- $fraction = 0;
- $chosen = 0;
- foreach ($order as $value => $ansid) {
- $mcanswer = $subquestion->answers[$ansid];
- $choices[$value] = strip_tags($mcanswer->answer);
- $selected = '';
- $isselected = false;
- if ( $response != '') {
- $isselected = $this->is_choice_selected($response, $value);
- }
+ $result = $this->all_choices_wrapper_start();
+ $fraction = null;
+ foreach ($subq->get_order($qa) as $value => $ansid) {
+ $ans = $subq->answers[$ansid];
+
+ $inputattributes['value'] = $value;
+ $inputattributes['id'] = $inputattributes['name'] . $value;
+
+ $isselected = $subq->is_choice_selected($response, $value);
if ($isselected) {
- $chosen = $value;
- $answer = $mcanswer;
- $fraction = $mcanswer->fraction;
- $selected = ' selected="selected"';
- }
- }
- if ($options->feedback) {
- if ($answer) {
- $classes .= ' ' . question_get_feedback_class($fraction);
- $feedbackimage = question_get_feedback_image($answer->fraction);
- if ($answer->feedback) {
- $feedback .= $subquestion->format_text($answer->feedback);
- }
+ $inputattributes['checked'] = 'checked';
+ $fraction = $ans->fraction;
} else {
- $classes .= ' ' . question_get_feedback_class(0);
- $feedbackimage = question_get_feedback_image(0);
- }
- }
- // determine popup
- // answer feedback (specific)i.e if options->feedback already set
- // subquestion status correctness or Finished validator if correctness
- // Correct response
- // marks
- $strfeedbackwrapped = 'Response Status';
- if ($options->feedback) {
- $feedback = get_string('feedback', 'quiz').":".$feedback."
";
-
- if ($options->correctness) {
- if (!$answer) {
- $state = $qa->get_state();
- $state = question_state::$invalid;
- $strfeedbackwrapped .= ":".$state->default_string()."";
- $feedback = "".get_string('singleanswer', 'quiz') ."
";
- } else {
- $state = $qa->get_state();
- $state = question_state::graded_state_for_fraction($fraction);
- $strfeedbackwrapped .= ":".$state->default_string();
- }
+ unset($inputattributes['checked']);
}
- if ($options->correctresponse) {
- $feedback .= $this->correct_response($qa)."
";
- }
- if ($options->marks) {
- $subgrade= $fraction * $subquestion->defaultmark;
- $feedback .= $questiontot->mark_summary($options, $subquestion->defaultmark , $subgrade);
+ $class = 'r' . ($value % 2);
+ if ($options->correctness && $isselected) {
+ $feedbackimg = $this->feedback_image($ans->fraction);
+ $class .= ' ' . $this->feedback_class($ans->fraction);
+ } else {
+ $feedbackimg = '';
}
- $feedback .= '';
+ $result .= $this->choice_wrapper_start($class);
+ $result .= html_writer::empty_tag('input', $inputattributes);
+ $result .= html_writer::tag('label', $subq->format_text($ans->answer,
+ $ans->answerformat, $qa, 'question', 'answer', $ansid),
+ array('for' => $inputattributes['id']));
+ $result .= $feedbackimg;
+
+ if ($options->feedback && $isselected && trim($ans->feedback)) {
+ $result .= html_writer::tag('div',
+ $subq->format_text($ans->feedback, $ans->feedbackformat,
+ $qa, 'question', 'answerfeedback', $ansid),
+ array('class' => 'specificfeedback'));
+ }
+
+ $result .= $this->choice_wrapper_end();
}
- if ($options->feedback) {
- // need to replace ' and " as they could break the popup string
- // as the text comes from database, slashes have been removed
- // addslashes will not work as it keeps the "
- // HTML ' for ' does not work
- $feedback = str_replace("'", "\'", $feedback);
- $feedback = str_replace('"', "\'", $feedback);
- $strfeedbackwrapped = str_replace("'", "\'", $strfeedbackwrapped);
- $strfeedbackwrapped = str_replace('"', "\'", $strfeedbackwrapped);
+ $result .= $this->all_choices_wrapper_end();
- $popup = " onmouseover=\"return overlib('$feedback', STICKY, MOUSEOFF, CAPTION, '$strfeedbackwrapped', FGCOLOR, '#FFFFFF');\" ".
- " onmouseout=\"return nd();\" ";
+ if ($options->feedback && $options->marks >= question_display_options::MARK_AND_MAX &&
+ $subq->maxmark > 0) {
+ $a = new stdClass();
+ $a->mark = format_float($fraction * $subq->maxmark, $options->markdp);
+ $a->max = format_float($subq->maxmark, $options->markdp);
+
+ $result .= html_writer::tag('div', get_string('markoutofmax', 'question', $a),
+ array('class' => 'outcome'));
}
- $result = '';
-
- $result .= "";
- $result .= html_writer::start_tag('span', array('class' => $classes), '');
-
- $result .= choose_from_menu($choices, $inputname, $chosen,
- ' ', '', '', true, $options->readonly) . $feedbackimage;
- $result .= html_writer::end_tag('span');
- $result .= html_writer::end_tag('span');
return $result;
}
- protected function format_choices($question) {
- $choices = array();
- foreach ($question->get_choice_order() as $key => $choiceid) {
- $choices[$key] = strip_tags($question->format_text($question->choices[$choiceid]));
- }
- return $choices;
+ /**
+ * @param string $class class attribute value.
+ * @return string HTML to go before each choice.
+ */
+ protected function choice_wrapper_start($class) {
+ return html_writer::start_tag('div', array('class' => $class));
+ }
+
+ /**
+ * @return string HTML to go after each choice.
+ */
+ protected function choice_wrapper_end() {
+ return html_writer::end_tag('div');
+ }
+
+ /**
+ * @return string HTML to go before all the choices.
+ */
+ protected function all_choices_wrapper_start() {
+ return html_writer::start_tag('div', array('class' => 'answer'));
+ }
+
+ /**
+ * @return string HTML to go after all the choices.
+ */
+ protected function all_choices_wrapper_end() {
+ return html_writer::end_tag('div');
}
}
/**
- * As multianswer have specific display requirements for multichoice display
- * a new class was defined although largely following the multichoice one
+ * Render an embedded multiple-choice question vertically, like for a normal
+ * multiple-choice question.
*
* @copyright 2010 Pierre Pichet
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-abstract class qtype_multianswer_multichoice_renderer_base extends qtype_renderer {
- abstract protected function get_input_type();
+class qtype_multianswer_multichoice_horizontal_renderer
+ extends qtype_multianswer_multichoice_vertical_renderer {
- abstract protected function get_input_name(question_attempt $qa, $value);
-
- abstract protected function get_input_value($value);
-
- abstract protected function get_input_id(question_attempt $qa, $value);
-
- abstract protected function is_choice_selected($response, $value);
-
- abstract protected function is_right(question_answer $ans);
-
- abstract protected function get_response(question_attempt $qa);
-
- public function specific_feedback(question_attempt $qa) {
- return '';
+ protected function choice_wrapper_start($class) {
+ return html_writer::start_tag('td', array('class' => $class));
}
- public function formulation_and_controls(question_attempt $qa,
- question_display_options $options) {
-
- $questiontot = $qa->get_question();
- $subquestion = $questiontot->subquestions[$qa->subquestionindex];
- $order = $subquestion->get_order($qa);
- $response = $this->get_response($qa);
- $inputattributes = array(
- 'type' => $this->get_input_type(),
- );
-
- if ($options->readonly) {
- $inputattributes['disabled'] = 'disabled';
- }
- $radiobuttons = array();
- $feedbackimg = array();
- $feedback = array();
- $classes = array();
- $totfraction = 0;
- $nullresponse = true;
- foreach ($order as $value => $ansid) {
- $ans = $subquestion->answers[$ansid];
- $inputattributes['name'] = $this->get_input_name($qa, $value);
- $inputattributes['value'] = $this->get_input_value($value);
- $inputattributes['id'] = $this->get_input_id($qa, $value);
- if ($subquestion->single) {
- $isselected = $this->is_choice_selected($response, $value);
- } else {
- $isselected = $this->is_choice_selected($response, $value);
- }
- if ($isselected) {
- $inputattributes['checked'] = 'checked';
- $totfraction += $ans->fraction;
- $nullresponse = false;
- } else {
- unset($inputattributes['checked']);
- }
- $radiobuttons[] = html_writer::empty_tag('input', $inputattributes) .
- html_writer::tag('label', $subquestion->format_text($ans->answer), array('for' => $inputattributes['id']));
-
- if (($options->feedback || $options->correctresponse) && $response !== -1) {
- $feedbackimg[] = question_get_feedback_image($this->is_right($ans), $isselected && $options->feedback);
- } else {
- $feedbackimg[] = '';
- }
- if (($options->feedback || $options->correctresponse) && $isselected) {
- $feedback[] = $subquestion->format_text($ans->feedback);
- } else {
- $feedback[] = '';
- }
- $class = 'r' . ($value % 2);
- if ($options->correctresponse && $ans->fraction > 0) {
- $class .= ' ' . question_get_feedback_class($ans->fraction);
- }
- $classes[] = $class;
- }
-
- $result = '';
-
- $answername = 'answer';
- if ($subquestion->layout == 1) {
- $result .= html_writer::start_tag('div', array('class' => 'ablock'));
-
- $result .= html_writer::start_tag('table', array('class' => $answername));
- foreach ($radiobuttons as $key => $radio) {
- $result .= html_writer::start_tag('tr', array('class' => $answername));
- $result .= html_writer::start_tag('td', array('class' => $answername));
- $result .= html_writer::tag('span', $radio . $feedbackimg[$key] . $feedback[$key], array('class' => $classes[$key])) . "\n";
- $result .= html_writer::end_tag('td');
- $result .= html_writer::end_tag('tr');
- }
- $result .= html_writer::end_tag('table'); // answer
-
- $result .= html_writer::end_tag('div'); // ablock
- }
- if ($subquestion->layout == 2) {
- $result .= html_writer::start_tag('div', array('class' => 'ablock'));
- $result .= html_writer::start_tag('table', array('class' => $answername));
- $result .= html_writer::start_tag('tr', array('class' => $answername));
- foreach ($radiobuttons as $key => $radio) {
- $result .= html_writer::start_tag('td', array('class' => $answername));
- $result .= html_writer::tag('span', $radio . $feedbackimg[$key] . $feedback[$key]
- , array('class' => $classes[$key])) . "\n";
- $result .= html_writer::end_tag('td');
- }
- $result .= html_writer::end_tag('tr');
- $result .= html_writer::end_tag('table'); // answer
-
- $result .= html_writer::end_tag('div'); // ablock
- }
-
- if ($options->feedback) {
- $result .= html_writer::start_tag('div', array('class' => 'outcome'));
-
- if ($options->correctness) {
- if ( $nullresponse) {
- $state = $qa->get_state();
- $state = question_state::$invalid;
- $result1 = $state->default_string();
- $result .= html_writer::nonempty_tag('div', $result1,
- array('class' => 'validationerror'));
- $result1 = ($subquestion->single) ? get_string('singleanswer', 'quiz') : get_string('multipleanswers', 'quiz');
- $result .= html_writer::nonempty_tag('div', $result1,
- array('class' => 'validationerror'));
- } else {
- $state = $qa->get_state();
- $state = question_state::graded_state_for_fraction($totfraction);
- $result1 = $state->default_string();
- $result .= html_writer::nonempty_tag('div', $result1,
- array('class' => 'outcome'));
- }
- }
-
- if ($options->correctresponse) {
- $result1 = $this->correct_response($qa);
- $result .= html_writer::nonempty_tag('div', $result1, array('class' => 'outcome'));
- }
- if ($options->marks) {
- $subgrade= $totfraction * $subquestion->defaultmark;
- $result .= $questiontot->mark_summary($options, $subquestion->defaultmark , $subgrade);
- }
-
- if ($qa->get_state() == question_state::$invalid) {
- $result .= html_writer::nonempty_tag('div', array('class' => 'validationerror'),
- $subquestion->get_validation_error($qa->get_last_qt_data()));
- }
- $result .= html_writer::end_tag('div');
-
- }
- return $result;
+ protected function choice_wrapper_end() {
+ return html_writer::end_tag('td');
}
-
-}
-
-
-class qtype_multianswer_multichoice_single_renderer extends qtype_multianswer_multichoice_renderer_base {
- protected function get_input_type() {
- return 'radio';
+ protected function all_choices_wrapper_start() {
+ return html_writer::start_tag('table', array('class' => 'answer')) .
+ html_writer::start_tag('tbody') . html_writer::start_tag('tr');
}
- protected function is_choice_selected($response, $value) {
- return $response == $value;
- }
-
- protected function is_right(question_answer $ans) {
- return $ans->fraction > 0.9999999;
- }
-
- protected function get_input_name(question_attempt $qa, $value) {
- $questiontot = $qa->get_question();
- $subquestion = $questiontot->subquestions[$qa->subquestionindex];
- $answername = $subquestion->fieldid.'answer';
- return $qa->get_qt_field_name($answername);
- }
-
- protected function get_input_value($value) {
- return $value;
- }
-
- protected function get_input_id(question_attempt $qa, $value) {
- $questiontot = $qa->get_question();
- $subquestion = $questiontot->subquestions[$qa->subquestionindex];
- $answername = $subquestion->fieldid.'answer';
- return $qa->get_qt_field_name($answername);
- }
-
- protected function get_response(question_attempt $qa) {
- $questiontot = $qa->get_question();
- $subquestion = $questiontot->subquestions[$qa->subquestionindex];
- return $qa->get_last_qt_var($subquestion->fieldid.'answer', -1);
-
- }
-
- public function correct_response(question_attempt $qa) {
- $questiontot = $qa->get_question();
- $subquestion = $questiontot->subquestions[$qa->subquestionindex];
-
- foreach ($subquestion->answers as $ans) {
- if ($ans->fraction > 0.9999999) {
- return get_string('correctansweris', 'qtype_multichoice',
- $subquestion->format_text($ans->answer));
- }
- }
-
- return '';
+ protected function all_choices_wrapper_end() {
+ return html_writer::end_tag('tr') . html_writer::end_tag('tbody') .
+ html_writer::end_tag('table');
}
}
diff --git a/question/type/multianswer/simpletest/helper.php b/question/type/multianswer/simpletest/helper.php
index 4541a61b87d..bd828749b59 100644
--- a/question/type/multianswer/simpletest/helper.php
+++ b/question/type/multianswer/simpletest/helper.php
@@ -87,7 +87,7 @@ class qtype_multianswer_test_helper extends question_test_helper {
$mc->shuffleanswers = 1;
$mc->answernumbering = 'none';
- $mc->layout = 1;
+ $mc->layout = qtype_multichoice_base::LAYOUT_DROPDOWN;
$mc->answers = array(
13 => new question_answer(13, 'Bow-wow', 0,
diff --git a/question/type/multianswer/simpletest/testquestion.php b/question/type/multianswer/simpletest/testquestion.php
index a22971b0de2..0550b776922 100644
--- a/question/type/multianswer/simpletest/testquestion.php
+++ b/question/type/multianswer/simpletest/testquestion.php
@@ -37,8 +37,8 @@ require_once($CFG->dirroot . '/question/engine/simpletest/helpers.php');
class qtype_multianswer_question_test extends UnitTestCase {
public function test_get_expected_data() {
$question = test_question_maker::make_question('multianswer');
- $this->assertEqual(array('sub1_answer' => PARAM_RAW_TRIMMED, 'sub2_answer' => PARAM_RAW),
- $question->get_expected_data());
+ $this->assertEqual(array('sub1_answer' => PARAM_RAW_TRIMMED,
+ 'sub2_answer' => PARAM_RAW), $question->get_expected_data());
}
public function test_is_complete_response() {
diff --git a/question/type/multianswer/styles.css b/question/type/multianswer/styles.css
index 0bc1b7ed8d1..fbeb0fe0065 100644
--- a/question/type/multianswer/styles.css
+++ b/question/type/multianswer/styles.css
@@ -5,3 +5,20 @@
margin-top: 1em;
box-shadow: 0.5em 0.5em 1em #000000;
}
+.que.multianswer .answer .specificfeedback {
+ display: inline;
+ padding: 0 0.7em;
+ background: #FFF3BF;
+}
+.que.multianswer .answer .specificfeedback * {
+ display: inline;
+ background: #FFF3BF;
+}
+.que.multianswer .answer div.r0,
+.que.multianswer .answer div.r1 {
+ padding: 0.3em;
+}
+.que.multianswer table.answer {
+ margin-bottom: 0;
+ width: 100%;
+}