/**
  * Renders hint button. Could be used by behaviour or question renderer to avoid code duplication while rendering it.
  * @param hintobj object an object of a child of qtype_specific_hint class
  */
 public function render_hint_button(question_attempt $qa, question_display_options $options, $hintobj)
 {
     $question = $qa->get_question();
     $hintkey = $hintobj->hint_key();
     // Render button.
     $attributes = array('type' => 'submit', 'id' => $qa->get_behaviour_field_name($hintkey . 'btn'), 'name' => $qa->get_behaviour_field_name($hintkey . 'btn'), 'value' => get_string('hintbtn', 'qbehaviour_adaptivehints', $hintobj->hint_description()), 'class' => 'submit btn');
     if ($options->readonly) {
         $attributes['disabled'] = 'disabled';
     }
     $output = html_writer::empty_tag('input', $attributes);
     // Cost message.
     if ($hintobj->penalty_response_based()) {
         // If penalty is response-based.
         // Try to get last response.
         $response = $qa->get_last_qt_data();
         if (empty($response)) {
             $response = null;
         }
         $penalty = $hintobj->penalty_for_specific_hint($response);
         if ($penalty != 0) {
             $output .= $this->button_cost('withpenaltyapprox', $penalty, $options);
             // Note that reported penalty is approximation since user could change response in adaptive.
         }
     } else {
         $penalty = $hintobj->penalty_for_specific_hint(null);
         if ($penalty != 0) {
             $output .= $this->button_cost('withpenalty', $penalty, $options);
         }
     }
     if (!$options->readonly) {
         $this->page->requires->js_init_call('M.core_question_engine.init_submit_button', array($attributes['id'], $qa->get_slot()));
     }
     return $output;
 }
Ejemplo n.º 2
0
 public function subquestion(question_attempt $qa, question_display_options $options, qtype_combined_combinable_base $subq, $placeno)
 {
     $question = $subq->question;
     $place = $placeno + 1;
     $group = $question->places[$place];
     $fieldname = $subq->step_data_name($question->field($place));
     $value = $qa->get_last_qt_var($fieldname);
     $attributes = array('id' => str_replace(':', '_', $qa->get_qt_field_name($fieldname)));
     if ($options->readonly) {
         $attributes['disabled'] = 'disabled';
     }
     $orderedchoices = $question->get_ordered_choices($group);
     $selectoptions = array();
     foreach ($orderedchoices as $orderedchoicevalue => $orderedchoice) {
         $selectoptions[$orderedchoicevalue] = $orderedchoice->text;
     }
     $feedbackimage = '';
     if ($options->correctness) {
         $response = $qa->get_last_qt_data();
         if (array_key_exists($fieldname, $response)) {
             $fraction = (int) ($response[$fieldname] == $question->get_right_choice_for($place));
             $attributes['class'] = $this->feedback_class($fraction);
             $feedbackimage = $this->feedback_image($fraction);
         }
     }
     $selecthtml = html_writer::select($selectoptions, $qa->get_qt_field_name($fieldname), $value, get_string('choosedots'), $attributes) . ' ' . $feedbackimage;
     return html_writer::tag('span', $selecthtml, array('class' => 'control'));
 }
Ejemplo n.º 3
0
 public function formulation_and_controls(question_attempt $qa, question_display_options $options)
 {
     global $PAGE;
     $question = $qa->get_question();
     $response = $qa->get_last_qt_data();
     $questiontext = $question->format_questiontext($qa);
     $output = html_writer::tag('div', $questiontext, array('class' => 'qtext'));
     $bgimage = self::get_url_for_image($qa, 'bgimage');
     $img = html_writer::empty_tag('img', array('src' => $bgimage, 'class' => 'dropbackground', 'alt' => get_string('dropbackground', 'qtype_ddimageortext')));
     $droparea = html_writer::tag('div', $img, array('class' => 'droparea'));
     $dragimagehomes = '';
     foreach ($question->choices as $groupno => $group) {
         $dragimagehomesgroup = '';
         $orderedgroup = $question->get_ordered_choices($groupno);
         foreach ($orderedgroup as $choiceno => $dragimage) {
             $dragimageurl = self::get_url_for_image($qa, 'dragimage', $dragimage->id);
             $classes = array("group{$groupno}", 'draghome', "dragitemhomes{$dragimage->no}", "choice{$choiceno}");
             if ($dragimage->infinite) {
                 $classes[] = 'infinite';
             }
             if ($dragimageurl === null) {
                 $classes[] = 'yui3-cssfonts';
                 $dragimagehomesgroup .= html_writer::tag('div', $dragimage->text, array('src' => $dragimageurl, 'class' => join(' ', $classes)));
             } else {
                 $dragimagehomesgroup .= html_writer::empty_tag('img', array('src' => $dragimageurl, 'alt' => $dragimage->text, 'class' => join(' ', $classes)));
             }
         }
         $dragimagehomes .= html_writer::tag('div', $dragimagehomesgroup, array('class' => 'dragitemgroup' . $groupno));
     }
     $dragitemsclass = 'dragitems';
     if ($options->readonly) {
         $dragitemsclass .= ' readonly';
     }
     $dragitems = html_writer::tag('div', $dragimagehomes, array('class' => $dragitemsclass));
     $dropzones = html_writer::tag('div', '', array('class' => 'dropzones'));
     $hiddens = '';
     foreach ($question->places as $placeno => $place) {
         $varname = $question->field($placeno);
         list($fieldname, $html) = $this->hidden_field_for_qt_var($qa, $varname);
         $hiddens .= $html;
         $question->places[$placeno]->fieldname = $fieldname;
     }
     $output .= html_writer::tag('div', $droparea . $dragitems . $dropzones . $hiddens, array('class' => 'ddarea'));
     $topnode = 'div#q' . $qa->get_slot() . ' div.ddarea';
     $params = array('drops' => $question->places, 'topnode' => $topnode, 'readonly' => $options->readonly);
     $PAGE->requires->string_for_js('blank', 'qtype_ddimageortext');
     $PAGE->requires->yui_module('moodle-qtype_ddimageortext-dd', 'M.qtype_ddimageortext.init_question', array($params));
     if ($qa->get_state() == question_state::$invalid) {
         $output .= html_writer::nonempty_tag('div', $question->get_validation_error($qa->get_last_qt_data()), array('class' => 'validationerror'));
     }
     return $output;
 }
 /**
  * Generate the display of the formulation part of the question. This is the
  * area that contains the quetsion text, and the controls for students to
  * input their answers. Some question types also embed bits of feedback, for
  * example ticks and crosses, in this area.
  *
  * @param question_attempt $qa the question attempt to display.
  * @param question_display_options $options controls what should and should not be displayed.
  * @return string HTML fragment.
  */
 public function formulation_and_controls(question_attempt $qa, question_display_options $options)
 {
     $question = $qa->get_question();
     $response = $qa->get_last_qt_data();
     $table = new html_table();
     $table->attributes['class'] = 'matrix';
     $table->head = array();
     $table->head[] = '';
     foreach ($question->cols as $col) {
         $table->head[] = self::matrix_header($col);
     }
     if ($options->correctness) {
         $table->head[] = '';
     }
     foreach ($question->rows as $row) {
         $row_data = array();
         $row_data[] = self::matrix_header($row);
         foreach ($question->cols as $col) {
             $key = $question->key($row, $col);
             $cell_name = $qa->get_field_prefix() . $key;
             $is_readonly = $options->readonly;
             $is_checked = $question->is_answered($response, $row, $col);
             if ($question->multiple) {
                 $cell = self::checkbox($cell_name, $is_checked, $is_readonly);
             } else {
                 $cell = self::radio($cell_name, $col->id, $is_checked, $is_readonly);
             }
             if ($options->correctness) {
                 $weight = $question->weight($row, $col);
                 $cell .= $this->feedback_image($weight);
             }
             $row_data[] = $cell;
         }
         if ($options->correctness) {
             $row_grade = $question->grading()->grade_row($question, $row, $response);
             $feedback = $row->feedback;
             $feedback = strip_tags($feedback) ? $feedback : '';
             $row_data[] = $this->feedback_image($row_grade) . $feedback;
         }
         $table->data[] = $row_data;
         //$row_index++;
     }
     $result = $question->questiontext;
     $result .= html_writer::table($table, true);
     return $result;
 }
Ejemplo n.º 5
0
 public function formulation_and_controls(question_attempt $qa, question_display_options $options)
 {
     $question = $qa->get_question();
     $stemorder = $question->get_stem_order();
     $response = $qa->get_last_qt_data();
     $choices = $this->format_choices($question);
     $result = '';
     $result .= html_writer::tag('div', $question->format_questiontext($qa), array('class' => 'qtext'));
     $result .= html_writer::start_tag('div', array('class' => 'ablock'));
     $result .= html_writer::start_tag('table', array('class' => 'answer'));
     $result .= html_writer::start_tag('tbody');
     $parity = 0;
     $i = 1;
     foreach ($stemorder as $key => $stemid) {
         $result .= html_writer::start_tag('tr', array('class' => 'r' . $parity));
         $fieldname = 'sub' . $key;
         $result .= html_writer::tag('td', $this->format_stem_text($qa, $stemid), array('class' => 'text'));
         $classes = 'control';
         $feedbackimage = '';
         if (array_key_exists($fieldname, $response)) {
             $selected = $response[$fieldname];
         } else {
             $selected = 0;
         }
         $fraction = (int) ($selected && $selected == $question->get_right_choice_for($stemid));
         if ($options->correctness && $selected) {
             $classes .= ' ' . $this->feedback_class($fraction);
             $feedbackimage = $this->feedback_image($fraction);
         }
         $result .= html_writer::tag('td', html_writer::label(get_string('answer', 'qtype_match', $i), 'menu' . $qa->get_qt_field_name('sub' . $key), false, array('class' => 'accesshide')) . html_writer::select($choices, $qa->get_qt_field_name('sub' . $key), $selected, array('0' => 'choose'), array('disabled' => $options->readonly)) . ' ' . $feedbackimage, array('class' => $classes));
         $result .= html_writer::end_tag('tr');
         $parity = 1 - $parity;
         $i++;
     }
     $result .= html_writer::end_tag('tbody');
     $result .= html_writer::end_tag('table');
     $result .= html_writer::end_tag('div');
     // Closes <div class="ablock">.
     if ($qa->get_state() == question_state::$invalid) {
         $result .= html_writer::nonempty_tag('div', $question->get_validation_error($response), array('class' => 'validationerror'));
     }
     return $result;
 }
Ejemplo n.º 6
0
    /**
     * Check a request for access to a file belonging to a combined feedback field.
     * @param question_attempt $qa the question attempt being displayed.
     * @param question_display_options $options the options that control display of the question.
     * @param string $filearea the name of the file area.
     * @return bool whether access to the file should be allowed.
     */
    protected function check_combined_feedback_file_access($qa, $options, $filearea) {
        $state = $qa->get_state();

        if (!$state->is_finished()) {
            $response = $qa->get_last_qt_data();
            if (!$this->is_gradable_response($response)) {
                return false;
            }
            list($notused, $state) = $this->grade_response($response);
        }

        return $options->feedback && $state->get_feedback_class() . 'feedback' == $filearea;
    }
Ejemplo n.º 7
0
 protected function hint(question_attempt $qa, question_hint $hint)
 {
     $output = '';
     $question = $qa->get_question();
     $response = $qa->get_last_qt_data();
     if ($hint->statewhichincorrect) {
         $wrongdrags = $question->get_wrong_drags($response);
         $wrongparts = array();
         foreach ($wrongdrags as $wrongdrag) {
             $wrongparts[] = html_writer::nonempty_tag('span', $wrongdrag, array('class' => 'wrongpart'));
         }
         $output .= html_writer::nonempty_tag('div', get_string('followingarewrong', 'qtype_ddmarker', join(', ', $wrongparts)), array('class' => 'wrongparts'));
     }
     $output .= parent::hint($qa, $hint);
     return $output;
 }
Ejemplo n.º 8
0
 /**
  * Actually, this question type abuses this method to always ouptut the
  * hidden fields it needs.
  */
 public function clear_wrong(question_attempt $qa, $reallyclear = true)
 {
     $question = $qa->get_question();
     $response = $qa->get_last_qt_data();
     if (!empty($response) && $reallyclear) {
         $cleanresponse = $question->clear_wrong_from_response($response);
     } else {
         $cleanresponse = $response;
     }
     $output = '';
     foreach ($question->places as $place => $group) {
         $fieldname = $question->field($place);
         if (array_key_exists($fieldname, $response)) {
             $value = $response[$fieldname];
         } else {
             $value = '0';
         }
         if (array_key_exists($fieldname, $cleanresponse)) {
             $cleanvalue = $cleanresponse[$fieldname];
         } else {
             $cleanvalue = '0';
         }
         if ($cleanvalue != $value) {
             $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'id' => $this->box_id($qa, 'p' . $place), 'value' => s($value))) . html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $qa->get_qt_field_name($fieldname), 'value' => s($cleanvalue)));
         } else {
             $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'id' => $this->box_id($qa, 'p' . $place), 'name' => $qa->get_qt_field_name($fieldname), 'value' => s($value)));
         }
     }
     return $output;
 }
Ejemplo n.º 9
0
 public function formulation_and_controls(question_attempt $qa, question_display_options $options)
 {
     global $CFG, $DB;
     $question = $qa->get_question();
     $response = $qa->get_last_qt_data();
     $question->update_current_response($response);
     $currentresponse = $question->currentresponse;
     $correctresponse = $question->correctresponse;
     // generate fieldnames and ids
     //   response_fieldname : 1_response_319
     //   response_name      : q27:1_response_319
     //   response_id        : id_q27_1_response_319
     //   sortable_id        : id_sortable_q27_1_response_319
     $response_fieldname = $question->get_response_fieldname();
     $response_name = $qa->get_qt_field_name($response_fieldname);
     $response_id = 'id_' . preg_replace('/[^a-zA-Z0-9]+/', '_', $response_name);
     $sortable_id = 'id_sortable_' . $question->id;
     $result = '';
     if ($options->readonly || $options->correctness) {
         // don't allow items to be dragged and dropped
     } else {
         $script = "\n";
         $script .= "//<![CDATA[\n";
         $script .= "if (window.\$) {\n";
         // $ is an alias for jQuery
         $script .= "    \$(function() {\n";
         $script .= "        \$('#{$sortable_id}').sortable({\n";
         $script .= "            update: function(event, ui) {\n";
         $script .= "                var ItemsOrder = \$(this).sortable('toArray').toString();\n";
         $script .= "                \$('#{$response_id}').attr('value', ItemsOrder);\n";
         $script .= "            },\n";
         $script .= "            opacity: 0.6\n";
         $script .= "        });\n";
         $script .= "        \$('#{$sortable_id}').disableSelection();\n";
         $script .= "    });\n";
         $script .= "    \$(document).ready(function() {\n";
         $script .= "        var ItemsOrder = \$('#{$sortable_id}').sortable('toArray').toString();\n";
         $script .= "        \$('#{$response_id}').attr('value', ItemsOrder);\n";
         $script .= "    });\n";
         $script .= "}\n";
         $script .= "//]]>\n";
         $result .= html_writer::tag('script', $script, array('type' => 'text/javascript'));
     }
     $result .= html_writer::tag('div', $question->format_questiontext($qa), array('class' => 'qtext'));
     $printeditems = false;
     if (count($currentresponse)) {
         // generate ordering items
         foreach ($currentresponse as $position => $answerid) {
             if (!array_key_exists($answerid, $question->answers)) {
                 continue;
                 // shouldn't happen !!
             }
             if (!array_key_exists($position, $correctresponse)) {
                 continue;
                 // shouldn't happen !!
             }
             if ($printeditems == false) {
                 $printeditems = true;
                 $result .= html_writer::start_tag('div', array('class' => 'ablock'));
                 $result .= html_writer::start_tag('div', array('class' => 'answer'));
                 $result .= html_writer::start_tag('ul', array('class' => 'sortablelist', 'id' => $sortable_id));
             }
             if ($options->correctness) {
                 if ($correctresponse[$position] == $answerid) {
                     $class = 'correctposition';
                     $img = $this->feedback_image(1);
                 } else {
                     $class = 'wrongposition';
                     $img = $this->feedback_image(0);
                 }
                 $img = "{$img} ";
             } else {
                 $class = 'sortableitem';
                 $img = '';
             }
             // the original "id" revealed the correct order of the answers
             // because $answer->fraction holds the correct order number
             // $id = 'ordering_item_'.$answerid.'_'.intval($question->answers[$answerid]->fraction);
             $answer = $question->answers[$answerid];
             $params = array('class' => $class, 'id' => $answer->md5key);
             $result .= html_writer::tag('li', $img . $answer->answer, $params);
         }
     }
     if ($printeditems) {
         $result .= html_writer::end_tag('ul');
         $result .= html_writer::end_tag('div');
         // answer
         $result .= html_writer::end_tag('div');
         // ablock
         $result .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => $response_name, 'id' => $response_id, 'value' => ''));
         $result .= html_writer::tag('div', '', array('style' => 'clear:both;'));
     }
     return $result;
 }
Ejemplo n.º 10
0
 public function get_response(question_attempt $qa)
 {
     return $qa->get_last_qt_data();
 }
Ejemplo n.º 11
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;
    }
Ejemplo n.º 12
0
 /**
  * Construct the answer block area
  *
  * @param question_attempt $qa
  */
 public function construct_answerblock($qa, $question, $options)
 {
     $stemorder = $question->get_stem_order();
     $response = $qa->get_last_qt_data();
     $choices = $this->format_choices($qa);
     $o = html_writer::start_tag('div', array('class' => 'ablock'));
     $o .= html_writer::start_tag('table', array('class' => 'answer'));
     $o .= html_writer::start_tag('tbody');
     $parity = 0;
     $curfieldname = null;
     foreach ($stemorder as $key => $stemid) {
         $o .= html_writer::start_tag('tr', array('class' => 'r' . $parity));
         $o .= html_writer::tag('td', $this->construct_stem_cell($qa, $question, $stemid), array('class' => 'text'));
         $classes = array('control');
         $feedbackimage = '';
         $curfieldname = $question->get_field_name($key);
         if (array_key_exists($curfieldname, $response)) {
             $selected = (int) $response[$curfieldname];
         } else {
             $selected = 0;
         }
         $fraction = (int) ($selected && $selected == $question->get_right_choice_for($stemid));
         if ($options->correctness && $selected) {
             $classes[] = $this->feedback_class($fraction);
             $feedbackimage = $this->feedback_image($fraction);
         }
         $dragdropclasses = $classes;
         $classes[] = 'hiddenifjs';
         $dragdropclasses[] = 'visibleifjs';
         $o .= html_writer::tag('td', $this->construct_choice_cell_select($qa, $options, $choices, $stemid, $curfieldname, $selected) . ' ' . $feedbackimage, array('class' => implode(' ', $classes)));
         $o .= html_writer::tag('td', $this->construct_choice_cell_dragdrop($qa, $options, $choices, $stemid, $curfieldname, $selected) . ' ' . $feedbackimage, array('class' => implode(' ', $dragdropclasses)));
         $o .= html_writer::end_tag('tr');
         $parity = 1 - $parity;
     }
     $o .= html_writer::end_tag('tbody');
     $o .= html_writer::end_tag('table');
     $o .= $this->construct_available_dragdrop_choices($qa, $question);
     $o .= html_writer::end_tag('div');
     $o .= html_writer::tag('div', '', array('class' => 'clearer'));
     return $o;
 }
Ejemplo n.º 13
0
 public function num_parts_correct(question_attempt $qa)
 {
     $a = new stdClass();
     list($a->num, $a->outof) = $qa->get_question()->get_num_parts_right($qa->get_last_qt_data());
     if (is_null($a->outof)) {
         return '';
     } else {
         return get_string('correctanswersno', 'qtype_omeromultichoice') . '<span class="font-weight: bold">' . $a->num . '</span>';
     }
 }
Ejemplo n.º 14
0
 private function get_feedback_class_image(question_attempt $qa, question_display_options $options, $key)
 {
     $question = $qa->get_question();
     $response = $qa->get_last_qt_data();
     $stemorder = $question->get_stem_order();
     $stemid = $stemorder[$key];
     $ret = new stdClass();
     $ret->class = null;
     $ret->image = '';
     $selected = $this->get_selected($question, $response, $key);
     $fraction = (int) ($selected && $selected == $question->get_right_choice_for($stemid));
     if ($options->correctness && $selected) {
         $ret->class = $this->feedback_class($fraction);
         $ret->image = $this->feedback_image($fraction);
     }
     return $ret;
 }
Ejemplo n.º 15
0
 /**
  * Generate the specific feedback. This has to be a stack-specific method
  * since the standard specific_feedback method does not get given $options.
  * @param question_attempt $qa the question attempt to display.
  * @param question_display_options $options controls what should and should not be displayed.
  * @return string HTML fragment.
  */
 protected function stack_specific_feedback(question_attempt $qa, question_display_options $options)
 {
     $question = $qa->get_question();
     $response = $qa->get_last_qt_data();
     $feedbacktext = $question->specificfeedbackinstantiated;
     if (!$feedbacktext) {
         return '';
     }
     $feedbacktext = stack_maths::process_display_castext($feedbacktext, $this);
     $feedbacktext = $question->format_text($feedbacktext, $question->specificfeedbackformat, $qa, 'qtype_stack', 'specificfeedback', $question->id);
     $individualfeedback = count($question->prts) == 1;
     if ($individualfeedback) {
         $overallfeedback = '';
     } else {
         $overallfeedback = $this->overall_standard_prt_feedback($qa, $question, $response);
     }
     // Replace any PRT feedback.
     $allempty = true;
     foreach ($question->prts as $index => $prt) {
         $feedback = $this->prt_feedback($index, $response, $qa, $options, $individualfeedback);
         $allempty = $allempty && !$feedback;
         $feedbacktext = str_replace("[[feedback:{$index}]]", stack_maths::process_display_castext($feedback, $this), $feedbacktext);
     }
     if ($allempty && !$overallfeedback) {
         return '';
     }
     return $overallfeedback . $feedbacktext;
 }
Ejemplo n.º 16
0
 protected function num_parts_correct(question_attempt $qa)
 {
     $a = new stdClass();
     list($a->num, $a->outof) = $qa->get_question()->get_num_parts_right($qa->get_last_qt_data());
     if (is_null($a->outof)) {
         return '';
     } else {
         return get_string('yougotnrightcount', 'qtype_gapfill', $a);
     }
 }
Ejemplo n.º 17
0
 public function get_marked_gaps(question_attempt $qa, question_display_options $options)
 {
     $marked_gaps = array();
     $question = $qa->get_question();
     $correct_gaps = array();
     foreach ($question->textfragments as $place => $fragment) {
         if ($place < 1) {
             continue;
         }
         $fieldname = $question->field($place);
         $rightanswer = $question->get_right_choice_for($place);
         if ($options->correctness or $options->numpartscorrect) {
             $response = $qa->get_last_qt_data();
             if (array_key_exists($fieldname, $response)) {
                 if ($question->is_correct_response($response[$fieldname], $rightanswer)) {
                     $marked_gaps[$fieldname]['value'] = $response[$fieldname];
                     $marked_gaps[$fieldname]['fraction'] = 1;
                     $correct_gaps[] = $response[$fieldname];
                 } else {
                     $marked_gaps[$fieldname]['value'] = $response[$fieldname];
                     $marked_gaps[$fieldname]['fraction'] = 0;
                 }
             }
         }
     }
     $arr_unique = array_unique($correct_gaps);
     $arr_duplicates = array_diff_assoc($correct_gaps, $arr_unique);
     foreach ($marked_gaps as $fieldname => $gap) {
         if (in_array($gap['value'], $arr_duplicates)) {
             $marked_gaps[$fieldname]['duplicate'] = 'true';
         } else {
             $marked_gaps[$fieldname]['duplicate'] = 'false';
         }
     }
     return $marked_gaps;
 }
Ejemplo n.º 18
0
 protected function combined_feedback(question_attempt $qa)
 {
     $question = $qa->get_question();
     $state = $qa->get_state();
     if (!$state->is_finished()) {
         $response = $qa->get_last_qt_data();
         if (!$qa->get_question()->is_gradable_response($response)) {
             return '';
         }
         list($notused, $state) = $qa->get_question()->grade_response($response);
     }
     $feedback = '';
     $field = $state->get_feedback_class() . 'feedback';
     $format = $state->get_feedback_class() . 'feedbackformat';
     if ($question->{$field}) {
         $feedback .= $question->format_text($question->{$field}, $question->{$format}, $qa, 'question', $field, $question->id);
     }
     return $feedback;
 }
Ejemplo n.º 19
0
    protected function num_parts_correct(question_attempt $qa) {
        if ($qa->get_question()->get_num_selected_choices($qa->get_last_qt_data()) >
                $qa->get_question()->get_num_correct_choices()) {
            return get_string('toomanyselected', 'qtype_multichoice');
        }

        return parent::num_parts_correct($qa);
    }
Ejemplo n.º 20
0
 public function formulation_and_controls(question_attempt $qa, question_display_options $options)
 {
     global $CFG, $currentanswerwithhint;
     require_once $CFG->dirroot . '/question/type/regexp/locallib.php';
     $question = $qa->get_question();
     $inputname = $qa->get_qt_field_name('answer');
     $ispreview = !isset($options->attempt);
     $currentanswer = remove_blanks($qa->get_last_qt_var('answer'));
     $response = $qa->get_last_qt_data();
     $laststep = $qa->get_reverse_step_iterator();
     $hintadded = false;
     foreach ($qa->get_reverse_step_iterator() as $step) {
         $hintadded = $step->has_behaviour_var('_helps') === true;
         break;
     }
     $closest = find_closest($question, $currentanswer, $correct_response = false, $hintadded);
     $question->closest = $closest;
     $currentanswer = $closest[0];
     //js script for showing / hiding regexp generated alternative sentences (for teacher only)
     if ($ispreview) {
         $alternateanswers = get_alternateanswers($question);
         $response = $question->get_correct_response();
         $correctanswer = $response['answer'];
         $id = "showhidebutton";
         echo html_writer::start_tag('div');
         echo html_writer::empty_tag('input', array('type' => 'button', 'value' => get_string("showalternate", "qtype_regexp"), 'id' => $id, 'name' => $id));
         echo html_writer::end_tag('div');
         $this->page->requires->js_init_call('M.qtype_regexp.showhidealternate', array('#' . $id, '#alternateanswers'), false, array('name' => 'qtype_regexp', 'fullpath' => '/question/type/regexp/module.js', 'requires' => array('base', 'node', 'event'), 'strings' => array(array('showalternate', 'qtype_regexp'), array('hidealternate', 'qtype_regexp'))));
         echo html_writer::start_tag('div', array('id' => 'alternateanswers', 'style' => 'display:none;'));
         echo '<hr />';
         if ($question->usecase) {
             $case = get_string('caseyes', 'qtype_regexp');
         } else {
             $case = get_string('caseno', 'qtype_regexp');
         }
         echo get_string('casesensitive', 'qtype_regexp') . ' : <b>' . $case . '</b><hr />';
         foreach ($alternateanswers as $key => $alternateanswer) {
             echo get_string('answer') . ' ' . $key . ' (' . $alternateanswer['fraction'] . ') ', '<span class="regexp">' . $alternateanswer['regexp'] . '</span>';
             $list = '';
             foreach ($alternateanswer['answers'] as $alternate) {
                 $list .= '<li>' . $alternate . '</li>';
             }
             echo '<ul class="square">' . $list . '</ul>';
         }
         echo "<hr />";
         echo html_writer::end_tag('div');
     }
     $inputattributes = array('type' => 'text', 'name' => $inputname, 'value' => $currentanswer, 'id' => $inputname, 'size' => 80);
     if ($options->readonly) {
         $inputattributes['readonly'] = 'readonly';
     }
     $feedbackimg = '';
     if ($options->correctness) {
         $answer = $question->get_matching_answer(array('answer' => $currentanswer));
         if ($answer) {
             $fraction = $answer->fraction;
         } else {
             $fraction = 0;
         }
         $inputattributes['class'] = $this->feedback_class($fraction);
         $feedbackimg = $this->feedback_image($fraction);
     }
     $questiontext = $question->format_questiontext($qa);
     $placeholder = false;
     if (preg_match('/_____+/', $questiontext, $matches)) {
         $placeholder = $matches[0];
         $inputattributes['size'] = round(strlen($placeholder) * 1.1);
     }
     $input = html_writer::empty_tag('input', $inputattributes) . $feedbackimg;
     if ($placeholder) {
         $questiontext = substr_replace($questiontext, $input, strpos($questiontext, $placeholder), strlen($placeholder));
     }
     $result = html_writer::tag('div', $questiontext, array('class' => 'qtext'));
     if (!$placeholder) {
         $result .= html_writer::start_tag('div', array('class' => 'ablock'));
         $result .= get_string('answer', 'qtype_shortanswer', html_writer::tag('div', $input, array('class' => 'answer')));
         $result .= html_writer::end_tag('div');
     }
     if ($qa->get_state() == question_state::$invalid) {
         $result .= html_writer::nonempty_tag('div', $question->get_validation_error(array('answer' => $currentanswer)), array('class' => 'validationerror'));
     }
     return $result;
 }