/** * Override default behaviour so that we can use a specialised behaviour * that caches test results returned by the call to grade_response(). * * @param question_attempt $qa the attempt we are creating an behaviour for. * @param string $preferredbehaviour the requested type of behaviour. * @return question_behaviour the new behaviour object. */ public function make_behaviour(question_attempt $qa, $preferredbehaviour) { // TODO: see if there's some way or issuing a warning message when // coderunner questions aren't being used in an adaptive mode. if ($preferredbehaviour == 'adaptive') { return new qbehaviour_adaptive_adapted_for_coderunner($qa, $preferredbehaviour); } else { return parent::make_behaviour($qa, $preferredbehaviour); } }
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); $inputattributes = array( 'type' => 'radio', 'name' => $qa->get_qt_field_name($fieldname), ); if ($options->readonly) { $inputattributes['disabled'] = 'disabled'; } $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) { $inputattributes['checked'] = 'checked'; $fraction = $ans->fraction; } else { unset($inputattributes['checked']); } $class = 'r' . ($value % 2); if ($options->correctness && $isselected) { $feedbackimg = $this->feedback_image($ans->fraction); $class .= ' ' . $this->feedback_class($ans->fraction); } else { $feedbackimg = ''; } $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(); } $result .= $this->all_choices_wrapper_end(); $feedback = array(); 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); $feedback[] = html_writer::tag('div', get_string('markoutofmax', 'question', $a)); } if ($options->rightanswer) { foreach ($subq->answers as $ans) { if (question_state::graded_state_for_fraction($ans->fraction) == question_state::$gradedright) { $feedback[] = get_string('correctansweris', 'qtype_multichoice', $subq->format_text($ans->answer, $ans->answerformat, $qa, 'question', 'answer', $ansid)); break; } } } $result .= html_writer::nonempty_tag('div', implode('<br />', $feedback), array('class' => 'outcome')); return $result; }
public function check_file_access($qa, $options, $component, $filearea, $args, $forcedownload) { if ($component == 'question' && in_array($filearea, array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback'))) { return $this->check_combined_feedback_file_access($qa, $options, $filearea); } else { if ($component == 'question' && $filearea == 'answer') { $answerid = reset($args); // Itemid is answer id. return in_array($answerid, $this->order); } else { if ($component == 'question' && $filearea == 'answerfeedback') { $answerid = reset($args); // Itemid is answer id. $response = $this->get_response($qa); $isselected = false; foreach ($this->order as $value => $ansid) { if ($ansid == $answerid) { $isselected = $this->is_choice_selected($response, $value); break; } } // Param $options->suppresschoicefeedback is a hack specific to the // oumultiresponse question type. It would be good to refactor to // avoid refering to it here. return $options->feedback && empty($options->suppresschoicefeedback) && $isselected; } else { if ($component == 'question' && $filearea == 'hint') { return $this->check_hint_file_access($qa, $options, $args); } else { return parent::check_file_access($qa, $options, $component, $filearea, $args, $forcedownload); } } } } }
public function check_file_access($qa, $options, $component, $filearea, $args, $forcedownload) { return parent::check_file_access($qa, $options, $component, $filearea, $args, $forcedownload); }
public function check_file_access($qa, $options, $component, $filearea, $args, $forcedownload) { if ($component == 'question' && $filearea == 'answerfeedback') { $currentanswer = $qa->get_last_qt_var('answer'); if ($this->has_separate_unit_field()) { $selectedunit = $qa->get_last_qt_var('unit'); } else { $selectedunit = null; } list($value, $unit, $multiplier) = $this->ap->apply_units($currentanswer, $selectedunit); $answer = $this->get_matching_answer($value, $multiplier); $answerid = reset($args); // Itemid is answer id. return $options->feedback && $answer && $answerid == $answer->id; } else { if ($component == 'question' && $filearea == 'hint') { return $this->check_hint_file_access($qa, $options, $args); } else { return parent::check_file_access($qa, $options, $component, $filearea, $args, $forcedownload); } } }
/** @param question_grading_strategy $strategy the strategy to use for grading. */ public function __construct(question_grading_strategy $strategy) { parent::__construct(); $this->gradingstrategy = $strategy; }
public function check_file_access($qa, $options, $component, $filearea, $args, $forcedownload) { if ($component == 'question' && $filearea == 'answerfeedback') { $answerid = reset($args); // itemid is answer id. $response = $qa->get_last_qt_var('answer', ''); return $options->feedback && ($answerid == $this->trueanswerid && $response || $answerid == $this->falseanswerid && $response !== ''); } else { return parent::check_file_access($qa, $options, $component, $filearea, $args, $forcedownload); } }
/** * Output the content of the subquestion. * * @param question_attempt $qa * @param question_display_options $options * @param int $index * @param question_graded_automatically $subq * @return string */ public function subquestion(question_attempt $qa, question_display_options $options, $index, question_graded_automatically $subq) { if (!$subq instanceof qtype_multichoice_multi_question) { throw new coding_exception('Expecting subquestion of type qtype_multichoice_multi_question'); } $fieldprefix = 'sub' . $index . '_'; $fieldname = $fieldprefix . 'choice'; // Extract the responses that related to this question + strip off the prefix. $fieldprefixlen = strlen($fieldprefix); $response = []; foreach ($qa->get_last_qt_data() as $name => $val) { if (substr($name, 0, $fieldprefixlen) == $fieldprefix) { $name = substr($name, $fieldprefixlen); $response[$name] = $val; } } $basename = $qa->get_qt_field_name($fieldname); $inputattributes = array( 'type' => 'checkbox', 'value' => 1, ); if ($options->readonly) { $inputattributes['disabled'] = 'disabled'; } $result = $this->all_choices_wrapper_start(); // Calculate the total score (as we need to know if choices should be marked as 'correct' or 'partial'). $fraction = 0; foreach ($subq->get_order($qa) as $value => $ansid) { $ans = $subq->answers[$ansid]; if ($subq->is_choice_selected($response, $value)) { $fraction += $ans->fraction; } } // Display 'correct' answers as correct, if we are at 100%, otherwise mark them as 'partial'. $answerfraction = ($fraction > 0.999) ? 1.0 : 0.5; foreach ($subq->get_order($qa) as $value => $ansid) { $ans = $subq->answers[$ansid]; $name = $basename.$value; $inputattributes['name'] = $name; $inputattributes['id'] = $name; $isselected = $subq->is_choice_selected($response, $value); if ($isselected) { $inputattributes['checked'] = 'checked'; } else { unset($inputattributes['checked']); } $class = 'r' . ($value % 2); if ($options->correctness && $isselected) { $thisfrac = ($ans->fraction > 0) ? $answerfraction : 0; $feedbackimg = $this->feedback_image($thisfrac); $class .= ' ' . $this->feedback_class($thisfrac); } else { $feedbackimg = ''; } $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(); } $result .= $this->all_choices_wrapper_end(); $feedback = array(); 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); $feedback[] = html_writer::tag('div', get_string('markoutofmax', 'question', $a)); } if ($options->rightanswer) { $correct = []; foreach ($subq->answers as $ans) { if (question_state::graded_state_for_fraction($ans->fraction) != question_state::$gradedwrong) { $correct[] = $subq->format_text($ans->answer, $ans->answerformat, $qa, 'question', 'answer', $ans->id); } } $correct = '<ul><li>'.implode('</li><li>', $correct).'</li></ul>'; $feedback[] = get_string('correctansweris', 'qtype_multichoice', $correct); } $result .= html_writer::nonempty_tag('div', implode('<br />', $feedback), array('class' => 'outcome')); return $result; }
public function check_file_access($qa, $options, $component, $filearea, $args, $forcedownload) { if ($component == 'question' && $filearea == 'answer') { return true; } else if ($component == 'question' && $filearea == 'answerfeedback') { // Full logic to control which feedbacks a student can see is too complex. // Just allow access to all images. There is a theoretical chance the // students could see files they are not meant to see by guessing URLs, // but it is remote. return $options->feedback; } else if ($component == 'question' && $filearea == 'hint') { return $this->check_hint_file_access($qa, $options, $args); } else { return parent::check_file_access($qa, $options, $component, $filearea, $args, $forcedownload); } }
public function check_file_access($qa, $options, $component, $filearea, $args, $forcedownload) { if ($component == 'question' && $filearea == 'answerfeedback') { $currentanswer = $qa->get_last_qt_var('answer'); $answer = $qa->get_question()->get_matching_answer(array('answer' => $currentanswer)); $answerid = reset($args); // itemid is answer id. return $options->feedback && $answerid == $answer->id; } else { if ($component == 'question' && $filearea == 'hint') { return $this->check_hint_file_access($qa, $options, $args); } else { return parent::check_file_access($qa, $options, $component, $filearea, $args, $forcedownload); } } }