Example #1
0
 /**
  * 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);
     }
 }
Example #2
0
    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;
    }
Example #3
0
 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);
 }
Example #5
0
 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);
         }
     }
 }
Example #6
0
 /** @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);
     }
 }
Example #8
0
    /**
     * 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;
    }
Example #9
0
    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);
         }
     }
 }