| 1 | efrain | 1 | <?php
 | 
        
           |  |  | 2 | // This file is part of Moodle - http://moodle.org/
 | 
        
           |  |  | 3 | //
 | 
        
           |  |  | 4 | // Moodle is free software: you can redistribute it and/or modify
 | 
        
           |  |  | 5 | // it under the terms of the GNU General Public License as published by
 | 
        
           |  |  | 6 | // the Free Software Foundation, either version 3 of the License, or
 | 
        
           |  |  | 7 | // (at your option) any later version.
 | 
        
           |  |  | 8 | //
 | 
        
           |  |  | 9 | // Moodle is distributed in the hope that it will be useful,
 | 
        
           |  |  | 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
        
           |  |  | 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
        
           |  |  | 12 | // GNU General Public License for more details.
 | 
        
           |  |  | 13 | //
 | 
        
           |  |  | 14 | // You should have received a copy of the GNU General Public License
 | 
        
           |  |  | 15 | // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 | 
        
           |  |  | 16 |   | 
        
           |  |  | 17 | /**
 | 
        
           |  |  | 18 |  * Defines the renderer base classes for question types.
 | 
        
           |  |  | 19 |  *
 | 
        
           |  |  | 20 |  * @package    moodlecore
 | 
        
           |  |  | 21 |  * @subpackage questiontypes
 | 
        
           |  |  | 22 |  * @copyright  2009 The Open University
 | 
        
           |  |  | 23 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 24 |  */
 | 
        
           |  |  | 25 |   | 
        
           |  |  | 26 |   | 
        
           |  |  | 27 | defined('MOODLE_INTERNAL') || die();
 | 
        
           |  |  | 28 |   | 
        
           |  |  | 29 |   | 
        
           |  |  | 30 | /**
 | 
        
           |  |  | 31 |  * Renderer base classes for question types.
 | 
        
           |  |  | 32 |  *
 | 
        
           |  |  | 33 |  * @copyright  2009 The Open University
 | 
        
           |  |  | 34 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 35 |  */
 | 
        
           |  |  | 36 | abstract class qtype_renderer extends plugin_renderer_base {
 | 
        
           |  |  | 37 |     /**
 | 
        
           |  |  | 38 |      * Generate the display of the formulation part of the question. This is the
 | 
        
           |  |  | 39 |      * area that contains the quetsion text, and the controls for students to
 | 
        
           |  |  | 40 |      * input their answers. Some question types also embed bits of feedback, for
 | 
        
           |  |  | 41 |      * example ticks and crosses, in this area.
 | 
        
           |  |  | 42 |      *
 | 
        
           |  |  | 43 |      * @param question_attempt $qa the question attempt to display.
 | 
        
           |  |  | 44 |      * @param question_display_options $options controls what should and should not be displayed.
 | 
        
           |  |  | 45 |      * @return string HTML fragment.
 | 
        
           |  |  | 46 |      */
 | 
        
           |  |  | 47 |     public function formulation_and_controls(question_attempt $qa,
 | 
        
           |  |  | 48 |             question_display_options $options) {
 | 
        
           |  |  | 49 |         return $qa->get_question()->format_questiontext($qa);
 | 
        
           |  |  | 50 |     }
 | 
        
           |  |  | 51 |   | 
        
           |  |  | 52 |     /**
 | 
        
           |  |  | 53 |      * In the question output there are some class="accesshide" headers to help
 | 
        
           |  |  | 54 |      * screen-readers. This method returns the text to use for the heading above
 | 
        
           |  |  | 55 |      * the formulation_and_controls section.
 | 
        
           |  |  | 56 |      * @return string to use as the heading.
 | 
        
           |  |  | 57 |      */
 | 
        
           |  |  | 58 |     public function formulation_heading() {
 | 
        
           |  |  | 59 |         return get_string('questiontext', 'question');
 | 
        
           |  |  | 60 |     }
 | 
        
           |  |  | 61 |   | 
        
           |  |  | 62 |     /**
 | 
        
           |  |  | 63 |      * Output hidden form fields to clear any wrong parts of the student's response.
 | 
        
           |  |  | 64 |      *
 | 
        
           |  |  | 65 |      * This method will only be called if the question is in read-only mode.
 | 
        
           |  |  | 66 |      * @param question_attempt $qa the question attempt to display.
 | 
        
           |  |  | 67 |      * @return string HTML fragment.
 | 
        
           |  |  | 68 |      */
 | 
        
           |  |  | 69 |     public function clear_wrong(question_attempt $qa) {
 | 
        
           |  |  | 70 |         $response = $qa->get_last_qt_data();
 | 
        
           |  |  | 71 |         if (!$response) {
 | 
        
           |  |  | 72 |             return '';
 | 
        
           |  |  | 73 |         }
 | 
        
           |  |  | 74 |         $cleanresponse = $qa->get_question()->clear_wrong_from_response($response);
 | 
        
           |  |  | 75 |         $output = '';
 | 
        
           |  |  | 76 |         foreach ($cleanresponse as $name => $value) {
 | 
        
           |  |  | 77 |             $attr = array(
 | 
        
           |  |  | 78 |                 'type' => 'hidden',
 | 
        
           |  |  | 79 |                 'name' => $qa->get_qt_field_name($name),
 | 
        
           |  |  | 80 |                 'value' => s($value),
 | 
        
           |  |  | 81 |             );
 | 
        
           |  |  | 82 |             $output .= html_writer::empty_tag('input', $attr);
 | 
        
           |  |  | 83 |         }
 | 
        
           |  |  | 84 |         return $output;
 | 
        
           |  |  | 85 |     }
 | 
        
           |  |  | 86 |   | 
        
           |  |  | 87 |     /**
 | 
        
           |  |  | 88 |      * Generate the display of the outcome part of the question. This is the
 | 
        
           |  |  | 89 |      * area that contains the various forms of feedback. This function generates
 | 
        
           |  |  | 90 |      * the content of this area belonging to the question type.
 | 
        
           |  |  | 91 |      *
 | 
        
           |  |  | 92 |      * Subclasses will normally want to override the more specific methods
 | 
        
           |  |  | 93 |      * {specific_feedback()}, {general_feedback()} and {correct_response()}
 | 
        
           |  |  | 94 |      * that this method calls.
 | 
        
           |  |  | 95 |      *
 | 
        
           |  |  | 96 |      * @param question_attempt $qa the question attempt to display.
 | 
        
           |  |  | 97 |      * @param question_display_options $options controls what should and should not be displayed.
 | 
        
           |  |  | 98 |      * @return string HTML fragment.
 | 
        
           |  |  | 99 |      */
 | 
        
           |  |  | 100 |     public function feedback(question_attempt $qa, question_display_options $options) {
 | 
        
           |  |  | 101 |         $output = '';
 | 
        
           |  |  | 102 |         $hint = null;
 | 
        
           |  |  | 103 |   | 
        
           |  |  | 104 |         if ($options->feedback) {
 | 
        
           |  |  | 105 |             $output .= html_writer::nonempty_tag('div', $this->specific_feedback($qa),
 | 
        
           |  |  | 106 |                     array('class' => 'specificfeedback'));
 | 
        
           |  |  | 107 |             $hint = $qa->get_applicable_hint();
 | 
        
           |  |  | 108 |         }
 | 
        
           |  |  | 109 |   | 
        
           |  |  | 110 |         if ($options->numpartscorrect) {
 | 
        
           |  |  | 111 |             $output .= html_writer::nonempty_tag('div', $this->num_parts_correct($qa),
 | 
        
           |  |  | 112 |                     array('class' => 'numpartscorrect'));
 | 
        
           |  |  | 113 |         }
 | 
        
           |  |  | 114 |   | 
        
           |  |  | 115 |         if ($hint) {
 | 
        
           |  |  | 116 |             $output .= $this->hint($qa, $hint);
 | 
        
           |  |  | 117 |         }
 | 
        
           |  |  | 118 |   | 
        
           |  |  | 119 |         if ($options->generalfeedback) {
 | 
        
           |  |  | 120 |             $output .= html_writer::nonempty_tag('div', $this->general_feedback($qa),
 | 
        
           |  |  | 121 |                     array('class' => 'generalfeedback'));
 | 
        
           |  |  | 122 |         }
 | 
        
           |  |  | 123 |   | 
        
           |  |  | 124 |         if ($options->rightanswer) {
 | 
        
           |  |  | 125 |             $output .= html_writer::nonempty_tag('div', $this->correct_response($qa),
 | 
        
           |  |  | 126 |                     array('class' => 'rightanswer'));
 | 
        
           |  |  | 127 |         }
 | 
        
           |  |  | 128 |   | 
        
           |  |  | 129 |         return $output;
 | 
        
           |  |  | 130 |     }
 | 
        
           |  |  | 131 |   | 
        
           |  |  | 132 |     /**
 | 
        
           |  |  | 133 |      * Generate the specific feedback. This is feedback that varies according to
 | 
        
           |  |  | 134 |      * the response the student gave.
 | 
        
           |  |  | 135 |      * @param question_attempt $qa the question attempt to display.
 | 
        
           |  |  | 136 |      * @return string HTML fragment.
 | 
        
           |  |  | 137 |      */
 | 
        
           |  |  | 138 |     protected function specific_feedback(question_attempt $qa) {
 | 
        
           |  |  | 139 |         return '';
 | 
        
           |  |  | 140 |     }
 | 
        
           |  |  | 141 |   | 
        
           |  |  | 142 |     /**
 | 
        
           |  |  | 143 |      * Gereate a brief statement of how many sub-parts of this question the
 | 
        
           |  |  | 144 |      * student got right.
 | 
        
           |  |  | 145 |      * @param question_attempt $qa the question attempt to display.
 | 
        
           |  |  | 146 |      * @return string HTML fragment.
 | 
        
           |  |  | 147 |      */
 | 
        
           |  |  | 148 |     protected function num_parts_correct(question_attempt $qa) {
 | 
        
           |  |  | 149 |         $a = new stdClass();
 | 
        
           |  |  | 150 |         list($a->num, $a->outof) = $qa->get_question()->get_num_parts_right(
 | 
        
           |  |  | 151 |                 $qa->get_last_qt_data());
 | 
        
           |  |  | 152 |         if (is_null($a->outof)) {
 | 
        
           |  |  | 153 |             return '';
 | 
        
           |  |  | 154 |         } else {
 | 
        
           |  |  | 155 |             return get_string('yougotnright', 'question', $a);
 | 
        
           |  |  | 156 |         }
 | 
        
           |  |  | 157 |     }
 | 
        
           |  |  | 158 |   | 
        
           |  |  | 159 |     /**
 | 
        
           |  |  | 160 |      * Gereate the specific feedback. This is feedback that varies according to
 | 
        
           |  |  | 161 |      * the response the student gave.
 | 
        
           |  |  | 162 |      * @param question_attempt $qa the question attempt to display.
 | 
        
           |  |  | 163 |      * @return string HTML fragment.
 | 
        
           |  |  | 164 |      */
 | 
        
           |  |  | 165 |     protected function hint(question_attempt $qa, question_hint $hint) {
 | 
        
           |  |  | 166 |         return html_writer::nonempty_tag('div',
 | 
        
           |  |  | 167 |                 $qa->get_question()->format_hint($hint, $qa), array('class' => 'hint'));
 | 
        
           |  |  | 168 |     }
 | 
        
           |  |  | 169 |   | 
        
           |  |  | 170 |     /**
 | 
        
           |  |  | 171 |      * Gereate the general feedback. This is feedback is shown ot all students.
 | 
        
           |  |  | 172 |      *
 | 
        
           |  |  | 173 |      * @param question_attempt $qa the question attempt to display.
 | 
        
           |  |  | 174 |      * @return string HTML fragment.
 | 
        
           |  |  | 175 |      */
 | 
        
           |  |  | 176 |     protected function general_feedback(question_attempt $qa) {
 | 
        
           |  |  | 177 |         return $qa->get_question()->format_generalfeedback($qa);
 | 
        
           |  |  | 178 |     }
 | 
        
           |  |  | 179 |   | 
        
           |  |  | 180 |     /**
 | 
        
           |  |  | 181 |      * Gereate an automatic description of the correct response to this question.
 | 
        
           |  |  | 182 |      * Not all question types can do this. If it is not possible, this method
 | 
        
           |  |  | 183 |      * should just return an empty string.
 | 
        
           |  |  | 184 |      *
 | 
        
           |  |  | 185 |      * @param question_attempt $qa the question attempt to display.
 | 
        
           |  |  | 186 |      * @return string HTML fragment.
 | 
        
           |  |  | 187 |      */
 | 
        
           |  |  | 188 |     protected function correct_response(question_attempt $qa) {
 | 
        
           |  |  | 189 |         return '';
 | 
        
           |  |  | 190 |     }
 | 
        
           |  |  | 191 |   | 
        
           |  |  | 192 |     /**
 | 
        
           |  |  | 193 |      * Display any extra question-type specific content that should be visible
 | 
        
           |  |  | 194 |      * when grading, if appropriate.
 | 
        
           |  |  | 195 |      *
 | 
        
           |  |  | 196 |      * @param question_attempt $qa a question attempt.
 | 
        
           |  |  | 197 |      * @param question_display_options $options controls what should and should not be displayed.
 | 
        
           |  |  | 198 |      * @return string HTML fragment.
 | 
        
           |  |  | 199 |      */
 | 
        
           |  |  | 200 |     public function manual_comment(question_attempt $qa, question_display_options $options) {
 | 
        
           |  |  | 201 |         return '';
 | 
        
           |  |  | 202 |     }
 | 
        
           |  |  | 203 |   | 
        
           |  |  | 204 |     /**
 | 
        
           |  |  | 205 |      * Return any HTML that needs to be included in the page's <head> when this
 | 
        
           |  |  | 206 |      * question is used.
 | 
        
           |  |  | 207 |      * @param $qa the question attempt that will be displayed on the page.
 | 
        
           |  |  | 208 |      * @return string HTML fragment.
 | 
        
           |  |  | 209 |      */
 | 
        
           |  |  | 210 |     public function head_code(question_attempt $qa) {
 | 
        
           |  |  | 211 |         // This method is used by the Opaque question type. The remote question
 | 
        
           |  |  | 212 |         // engine can send back arbitrary CSS that we have to link to in the
 | 
        
           |  |  | 213 |         // page header. If it was not for that, we might be able to eliminate
 | 
        
           |  |  | 214 |         // this method and load the required CSS and JS some other way.
 | 
        
           |  |  | 215 |         $qa->get_question()->qtype->find_standard_scripts();
 | 
        
           |  |  | 216 |     }
 | 
        
           |  |  | 217 |   | 
        
           |  |  | 218 |     protected function feedback_class($fraction) {
 | 
        
           |  |  | 219 |         return question_state::graded_state_for_fraction($fraction)->get_feedback_class();
 | 
        
           |  |  | 220 |     }
 | 
        
           |  |  | 221 |   | 
        
           |  |  | 222 |     /**
 | 
        
           |  |  | 223 |      * Return an appropriate icon (green tick, red cross, etc.) for a grade.
 | 
        
           |  |  | 224 |      * @param float $fraction grade on a scale 0..1.
 | 
        
           |  |  | 225 |      * @param bool $selected whether to show a big or small icon. (Deprecated)
 | 
        
           |  |  | 226 |      * @return string html fragment.
 | 
        
           |  |  | 227 |      */
 | 
        
           |  |  | 228 |     protected function feedback_image($fraction, $selected = true) {
 | 
        
           |  |  | 229 |         $feedbackclass = question_state::graded_state_for_fraction($fraction)->get_feedback_class();
 | 
        
           |  |  | 230 |   | 
        
           |  |  | 231 |         return $this->output->pix_icon('i/grade_' . $feedbackclass, get_string($feedbackclass, 'question'));
 | 
        
           |  |  | 232 |     }
 | 
        
           |  |  | 233 | }
 | 
        
           |  |  | 234 |   | 
        
           |  |  | 235 | /**
 | 
        
           |  |  | 236 |  * Renderer base classes for question types.
 | 
        
           |  |  | 237 |  *
 | 
        
           |  |  | 238 |  * @copyright  2010 The Open University
 | 
        
           |  |  | 239 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 240 |  */
 | 
        
           |  |  | 241 | abstract class qtype_with_combined_feedback_renderer extends qtype_renderer {
 | 
        
           |  |  | 242 |     protected function combined_feedback(question_attempt $qa) {
 | 
        
           |  |  | 243 |         $question = $qa->get_question();
 | 
        
           |  |  | 244 |   | 
        
           |  |  | 245 |         $state = $qa->get_state();
 | 
        
           |  |  | 246 |   | 
        
           |  |  | 247 |         if (!$state->is_finished()) {
 | 
        
           |  |  | 248 |             $response = $qa->get_last_qt_data();
 | 
        
           |  |  | 249 |             if (!$qa->get_question()->is_gradable_response($response)) {
 | 
        
           |  |  | 250 |                 return '';
 | 
        
           |  |  | 251 |             }
 | 
        
           |  |  | 252 |             list($notused, $state) = $qa->get_question()->grade_response($response);
 | 
        
           |  |  | 253 |         }
 | 
        
           |  |  | 254 |   | 
        
           |  |  | 255 |         $feedback = '';
 | 
        
           |  |  | 256 |         $field = $state->get_feedback_class() . 'feedback';
 | 
        
           |  |  | 257 |         $format = $state->get_feedback_class() . 'feedbackformat';
 | 
        
           |  |  | 258 |         if ($question->$field) {
 | 
        
           |  |  | 259 |             $feedback .= $question->format_text($question->$field, $question->$format,
 | 
        
           |  |  | 260 |                     $qa, 'question', $field, $question->id);
 | 
        
           |  |  | 261 |         }
 | 
        
           |  |  | 262 |   | 
        
           |  |  | 263 |         return $feedback;
 | 
        
           |  |  | 264 |     }
 | 
        
           |  |  | 265 | }
 |