MDL-20636 fix styling of essay questions. #371
[moodle.git] / question / type / essay / renderer.php
CommitLineData
6d03299d 1<?php
6d03299d
TH
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
6d03299d
TH
17/**
18 * Essay question renderer class.
19 *
7764183a
TH
20 * @package qtype
21 * @subpackage essay
22 * @copyright 2009 The Open University
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6d03299d
TH
24 */
25
26
a17b297d
TH
27defined('MOODLE_INTERNAL') || die();
28
29
6d03299d
TH
30/**
31 * Generates the output for essay questions.
32 *
7764183a
TH
33 * @copyright 2009 The Open University
34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6d03299d
TH
35 */
36class qtype_essay_renderer extends qtype_renderer {
37 public function formulation_and_controls(question_attempt $qa,
38 question_display_options $options) {
39
40 $question = $qa->get_question();
b36d2d06 41 $responseoutput = $question->get_format_renderer($this->page);
6d03299d
TH
42
43 // Answer field.
48d9c17d 44 $step = $qa->get_last_step_with_qt_var('answer');
6d03299d 45 if (empty($options->readonly)) {
48d9c17d
TH
46 $answer = $responseoutput->response_area_input('answer', $qa,
47 $step, $question->responsefieldlines, $options->context);
6d03299d
TH
48
49 } else {
48d9c17d
TH
50 $answer = $responseoutput->response_area_read_only('answer', $qa,
51 $step, $question->responsefieldlines, $options->context);
b36d2d06
TH
52 }
53
54 $files = '';
d42dbe87
TH
55 if ($question->attachments) {
56 if (empty($options->readonly)) {
57 $files = $this->files_input($qa, $question->attachments, $options);
b36d2d06 58
d42dbe87
TH
59 } else {
60 $files = $this->files_read_only($qa, $options);
61 }
6d03299d
TH
62 }
63
64 $result = '';
65 $result .= html_writer::tag('div', $question->format_questiontext($qa),
66 array('class' => 'qtext'));
67
b36d2d06 68 $result .= html_writer::start_tag('div', array('class' => 'ablock'));
6d03299d 69 $result .= html_writer::tag('div', $answer, array('class' => 'answer'));
caeeff07 70 $result .= html_writer::tag('div', $files, array('class' => 'attachments'));
6d03299d
TH
71 $result .= html_writer::end_tag('div');
72
73 return $result;
74 }
b36d2d06
TH
75
76 /**
77 * Displays any attached files when the question is in read-only mode.
d42dbe87
TH
78 * @param question_attempt $qa the question attempt to display.
79 * @param question_display_options $options controls what should and should
80 * not be displayed. Used to get the context.
b36d2d06 81 */
caeeff07 82 public function files_read_only(question_attempt $qa, question_display_options $options) {
8026d4aa 83 $files = $qa->get_last_qt_files('attachments', $options->context->id);
caeeff07
TH
84 $output = array();
85
86 foreach ($files as $file) {
87 $mimetype = $file->get_mimetype();
88 $output[] = html_writer::tag('p', html_writer::link($qa->get_response_file_url($file),
89 $this->output->pix_icon(file_mimetype_icon($mimetype), $mimetype,
90 'moodle', array('class' => 'icon')) . ' ' . s($file->get_filename())));
91 }
92 return implode($output);
b36d2d06
TH
93 }
94
95 /**
96 * Displays the input control for when the student should upload a single file.
d42dbe87
TH
97 * @param question_attempt $qa the question attempt to display.
98 * @param int $numallowed the maximum number of attachments allowed. -1 = unlimited.
99 * @param question_display_options $options controls what should and should
100 * not be displayed. Used to get the context.
b36d2d06 101 */
121fd4c1
TH
102 public function files_input(question_attempt $qa, $numallowed,
103 question_display_options $options) {
8026d4aa
TH
104 global $CFG;
105 require_once($CFG->dirroot . '/lib/form/filemanager.php');
106
107 $pickeroptions = new stdClass();
108 $pickeroptions->mainfile = null;
d42dbe87 109 $pickeroptions->maxfiles = $numallowed;
8026d4aa
TH
110 $pickeroptions->itemid = $qa->prepare_response_files_draft_itemid(
111 'attachments', $options->context->id);
112 $pickeroptions->context = $options->context;
113
48d9c17d
TH
114 $pickeroptions->itemid = $qa->prepare_response_files_draft_itemid(
115 'attachments', $options->context->id);
116
217f9a61
TH
117 return form_filemanager_render($pickeroptions) . html_writer::empty_tag(
118 'input', array('type' => 'hidden', 'name' => $qa->get_qt_field_name('attachments'),
119 'value' => $pickeroptions->itemid));
b36d2d06
TH
120 }
121
783af252
TH
122 public function manual_comment(question_attempt $qa, question_display_options $options) {
123 if ($options->manualcomment != question_display_options::EDITABLE) {
124 return '';
125 }
126
127 $question = $qa->get_question();
128 return html_writer::nonempty_tag('div', $question->format_text(
129 $question->graderinfo, $question->graderinfo, $qa, 'qtype_essay',
130 'graderinfo', $question->id), array('class' => 'graderinfo'));
131 }
b36d2d06
TH
132}
133
134
135/**
136 * A base class to abstract out the differences between different type of
137 * response format.
138 *
139 * @copyright 2011 The Open University
140 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
141 */
142abstract class qtype_essay_format_renderer_base extends plugin_renderer_base {
143 /**
144 * Render the students respone when the question is in read-only mode.
48d9c17d
TH
145 * @param string $name the variable name this input edits.
146 * @param question_attempt $qa the question attempt being display.
147 * @param question_attempt_step $step the current step.
b36d2d06 148 * @param int $lines approximate size of input box to display.
48d9c17d
TH
149 * @param object $context the context teh output belongs to.
150 * @return string html to display the response.
b36d2d06 151 */
48d9c17d
TH
152 public abstract function response_area_read_only($name, question_attempt $qa,
153 question_attempt_step $step, $lines, $context);
b36d2d06
TH
154
155 /**
156 * Render the students respone when the question is in read-only mode.
48d9c17d
TH
157 * @param string $name the variable name this input edits.
158 * @param question_attempt $qa the question attempt being display.
159 * @param question_attempt_step $step the current step.
b36d2d06 160 * @param int $lines approximate size of input box to display.
48d9c17d
TH
161 * @param object $context the context teh output belongs to.
162 * @return string html to display the response for editing.
163 */
164 public abstract function response_area_input($name, question_attempt $qa,
165 question_attempt_step $step, $lines, $context);
166
167 /**
168 * @return string specific class name to add to the input element.
b36d2d06 169 */
48d9c17d 170 protected abstract function class_name();
b36d2d06
TH
171}
172
173
174/**
175 * An essay format renderer for essays where the student should use the HTML
176 * editor without the file picker.
177 *
178 * @copyright 2011 The Open University
179 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
180 */
181class qtype_essay_format_editor_renderer extends plugin_renderer_base {
48d9c17d
TH
182 protected function class_name() {
183 return 'qtype_essay_editor';
b36d2d06
TH
184 }
185
48d9c17d
TH
186 public function response_area_read_only($name, $qa, $step, $lines, $context) {
187 return html_writer::tag('div', $this->prepare_response($name, $qa, $step, $context),
9199e7a5 188 array('class' => $this->class_name() . ' qtype_essay_response readonly'));
48d9c17d
TH
189 }
190
191 public function response_area_input($name, $qa, $step, $lines, $context) {
a54ecbbb
TH
192 global $CFG, $PAGE;
193 require_once($CFG->dirroot.'/repository/lib.php');
194
48d9c17d
TH
195 $inputname = $qa->get_qt_field_name($name);
196 $responseformat = $step->get_qt_var($name . 'format');
a54ecbbb
TH
197 $id = $inputname . '_id';
198
199 $editor = editors_get_preferred_editor($responseformat);
200 $strformats = format_text_menu();
201 $formats = $editor->get_supported_formats();
202 foreach ($formats as $fid) {
203 $formats[$fid] = $strformats[$fid];
204 }
205
48d9c17d
TH
206 list($draftitemid, $reponse) = $this->prepare_response_for_editing(
207 $name, $step, $context);
208
a54ecbbb 209 $editor->use_editor($id, $this->get_editor_options($context),
48d9c17d 210 $this->get_filepicker_options($context, $draftitemid));
a54ecbbb
TH
211
212 $output = '';
48d9c17d
TH
213 $output .= html_writer::start_tag('div', array('class' =>
214 $this->class_name() . ' qtype_essay_response'));
a54ecbbb 215
48d9c17d 216 $output .= html_writer::tag('div', html_writer::tag('textarea', s($reponse),
dbf76faf 217 array('id' => $id, 'name' => $inputname, 'rows' => $lines, 'cols' => 60)));
a54ecbbb
TH
218
219 $output .= html_writer::start_tag('div');
220 if (count($formats == 1)) {
221 reset($formats);
222 $output .= html_writer::empty_tag('input', array('type' => 'hidden',
223 'name' => $inputname . 'format', 'value' => key($formats)));
224
225 } else {
226 $output .= html_writer::select($formats, $inputname . 'format', $responseformat, '');
227 }
228 $output .= html_writer::end_tag('div');
229
48d9c17d 230 $output .= $this->filepicker_html($inputname, $draftitemid);
a54ecbbb
TH
231
232 $output .= html_writer::end_tag('div');
233 return $output;
234 }
235
236 /**
48d9c17d
TH
237 * Prepare the response for read-only display.
238 * @param string $name the variable name this input edits.
239 * @param question_attempt $qa the question attempt being display.
240 * @param question_attempt_step $step the current step.
241 * @param object $context the context the attempt belongs to.
242 * @return string the response prepared for display.
a54ecbbb 243 */
48d9c17d
TH
244 protected function prepare_response($name, question_attempt $qa,
245 question_attempt_step $step, $context) {
246 if (!$step->has_qt_var($name)) {
247 return '';
248 }
249
250 $formatoptions = new stdClass();
251 $formatoptions->para = false;
252 return format_text($step->get_qt_var($name), $step->get_qt_var($name . 'format'),
253 $formatoptions);
a54ecbbb
TH
254 }
255
256 /**
48d9c17d
TH
257 * Prepare the response for editing.
258 * @param string $name the variable name this input edits.
259 * @param question_attempt_step $step the current step.
260 * @param object $context the context the attempt belongs to.
261 * @return string the response prepared for display.
a54ecbbb 262 */
48d9c17d
TH
263 protected function prepare_response_for_editing($name,
264 question_attempt_step $step, $context) {
265 return array(0, $step->get_qt_var($name));
a54ecbbb
TH
266 }
267
268 /**
48d9c17d 269 * @param object $context the context the attempt belongs to.
a54ecbbb
TH
270 * @return array options for the editor.
271 */
272 protected function get_editor_options($context) {
273 return array('context' => $context);
274 }
275
276 /**
48d9c17d
TH
277 * @param object $context the context the attempt belongs to.
278 * @param int $draftitemid draft item id.
279 * @return array filepicker options for the editor.
280 */
281 protected function get_filepicker_options($context, $draftitemid) {
282 return array();
283 }
284
285 /**
286 * @param string $inputname input field name.
287 * @param int $draftitemid draft file area itemid.
288 * @return string HTML for the filepicker, if used.
a54ecbbb 289 */
48d9c17d 290 protected function filepicker_html($inputname, $draftitemid) {
a54ecbbb 291 return '';
b36d2d06
TH
292 }
293}
294
295
296/**
297 * An essay format renderer for essays where the student should use the HTML
298 * editor with the file picker.
299 *
300 * @copyright 2011 The Open University
301 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
302 */
a54ecbbb 303class qtype_essay_format_editorfilepicker_renderer extends qtype_essay_format_editor_renderer {
48d9c17d
TH
304 protected function class_name() {
305 return 'qtype_essay_editorfilepicker';
306 }
307
308 protected function prepare_response($name, question_attempt $qa,
309 question_attempt_step $step, $context) {
310 if (!$step->has_qt_var($name)) {
311 return '';
312 }
a54ecbbb 313
48d9c17d
TH
314 $formatoptions = new stdClass();
315 $formatoptions->para = false;
316 $text = $qa->rewrite_response_pluginfile_urls($step->get_qt_var($name),
317 $context->id, 'answer', $step);
318 return format_text($text, $step->get_qt_var($name . 'format'), $formatoptions);
a54ecbbb
TH
319 }
320
48d9c17d
TH
321 protected function prepare_response_for_editing($name,
322 question_attempt_step $step, $context) {
323 return $step->prepare_response_files_draft_itemid_with_text(
324 $name, $context->id, $step->get_qt_var($name));
b36d2d06
TH
325 }
326
48d9c17d
TH
327 protected function get_editor_options($context) {
328 return array(
329 'subdirs' => 0,
330 'maxbytes' => 0,
331 'maxfiles' => -1,
332 'context' => $context,
333 'noclean' => 0,
334 'trusttext'=>0
335 );
336 }
337
338 /**
339 * Get the options required to configure the filepicker for one of the editor
340 * toolbar buttons.
341 * @param mixed $acceptedtypes array of types of '*'.
342 * @param int $draftitemid the draft area item id.
343 * @param object $context the context.
344 * @return object the required options.
345 */
346 protected function specific_filepicker_options($acceptedtypes, $draftitemid, $context) {
347 $filepickeroptions = new stdClass();
348 $filepickeroptions->accepted_types = $acceptedtypes;
349 $filepickeroptions->return_types = FILE_INTERNAL | FILE_EXTERNAL;
350 $filepickeroptions->context = $context;
351 $filepickeroptions->env = 'filepicker';
352
353 $options = initialise_filepicker($filepickeroptions);
354 $options->context = $context;
355 $options->client_id = uniqid();
356 $options->env = 'editor';
357 $options->itemid = $draftitemid;
358
359 return $options;
360 }
361
362 protected function get_filepicker_options($context, $draftitemid) {
363 global $CFG;
364
365 return array(
366 'image' => $this->specific_filepicker_options(array('image'),
367 $draftitemid, $context),
368 'media' => $this->specific_filepicker_options(array('video', 'audio'),
369 $draftitemid, $context),
370 'link' => $this->specific_filepicker_options('*',
371 $draftitemid, $context),
372 );
373 }
374
375 protected function filepicker_html($inputname, $draftitemid) {
376 $nonjspickerurl = new moodle_url('/repository/draftfiles_manager.php', array(
377 'action' => 'browse',
378 'env' => 'editor',
379 'itemid' => $draftitemid,
380 'subdirs' => false,
381 'maxfiles' => -1,
382 'sesskey' => sesskey(),
383 ));
384
385 return html_writer::empty_tag('input', array('type' => 'hidden',
386 'name' => $inputname . ':itemid', 'value' => $draftitemid)) .
387 html_writer::tag('noscript', html_writer::tag('div',
388 html_writer::tag('object', '', array('type' => 'text/html',
389 'data' => $nonjspickerurl, 'height' => 160, 'width' => 600,
390 'style' => 'border: 1px solid #000;'))));
b36d2d06
TH
391 }
392}
393
394
395/**
396 * An essay format renderer for essays where the student should use a plain
397 * input box, but with a normal, proportional font.
398 *
399 * @copyright 2011 The Open University
400 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
401 */
402class qtype_essay_format_plain_renderer extends plugin_renderer_base {
403 /**
404 * @return string the HTML for the textarea.
405 */
406 protected function textarea($response, $lines, $attributes) {
407 $attributes['class'] = $this->class_name() . ' qtype_essay_response';
408 $attributes['rows'] = $lines;
dbf76faf 409 $attributes['cols'] = 60;
b36d2d06
TH
410 return html_writer::tag('textarea', s($response), $attributes);
411 }
412
413 protected function class_name() {
414 return 'qtype_essay_plain';
415 }
416
48d9c17d
TH
417 public function response_area_read_only($name, $qa, $step, $lines, $context) {
418 return $this->textarea($step->get_qt_var($name), $lines, array('readonly' => 'readonly'));
b36d2d06
TH
419 }
420
48d9c17d
TH
421 public function response_area_input($name, $qa, $step, $lines, $context) {
422 $inputname = $qa->get_qt_field_name($name);
423 return $this->textarea($step->get_qt_var($name), $lines, array('name' => $inputname)) .
a54ecbbb
TH
424 html_writer::empty_tag('input', array('type' => 'hidden',
425 'name' => $inputname . 'format', 'value' => FORMAT_PLAIN));
b36d2d06
TH
426 }
427}
428
429
430/**
431 * An essay format renderer for essays where the student should use a plain
432 * input box with a monospaced font. You might use this, for example, for a
433 * question where the students should type computer code.
434 *
435 * @copyright 2011 The Open University
436 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
437 */
438class qtype_essay_format_monospaced_renderer extends qtype_essay_format_plain_renderer {
439 protected function class_name() {
440 return 'qtype_essay_monospaced';
441 }
6d03299d 442}