Merge branch 'MDL-70148-310' of git://github.com/andrewnicols/moodle into MOODLE_310_...
[moodle.git] / question / type / gapselect / rendererbase.php
CommitLineData
0d24b17a 1<?php
f7dd2d44
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
17/**
18 * Base class for rendering question types like this one.
19 *
458700d8 20 * @package qtype_gapselect
9df0480d
TH
21 * @copyright 2011 The Open University
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
f7dd2d44
TH
23 */
24
25
b28ad86a
TH
26defined('MOODLE_INTERNAL') || die();
27
28
0d24b17a 29/**
647d9373 30 * Renders question types where the question includes embedded interactive elements.
0d24b17a 31 *
9df0480d
TH
32 * @copyright 2011 The Open University
33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
0d24b17a 34 */
060e0294
TH
35abstract class qtype_elements_embedded_in_question_text_renderer
36 extends qtype_with_combined_feedback_renderer {
0d24b17a
TH
37 public function formulation_and_controls(question_attempt $qa,
38 question_display_options $options) {
39
40 $question = $qa->get_question();
41
42 $questiontext = '';
b197da87
MG
43 // Glue question fragments together using unique placeholders, apply format_text to the result
44 // and then substitute each placeholder with the embedded element.
45 // This will ensure that format_text() is applied to the whole question but not to the embedded elements.
46 $placeholders = $this->get_fragments_glue_placeholders($question->textfragments);
0d24b17a
TH
47 foreach ($question->textfragments as $i => $fragment) {
48 if ($i > 0) {
b197da87 49 $questiontext .= $placeholders[$i];
410a088a
JB
50 // There is a preg_replace 11 lines ahead where the $embeddedelements is used as the replace.
51 // If there are currency like options ($4) in the select then the preg_replace treats them as backreferences.
52 // So we need to escape the backreferences here.
53 $embeddedelements[$placeholders[$i]] =
54 preg_replace('/\$(\d)/', '\\\$$1', $this->embedded_element($qa, $i, $options));
0d24b17a
TH
55 }
56 $questiontext .= $fragment;
57 }
b197da87
MG
58 $questiontext = $question->format_text($questiontext,
59 $question->questiontextformat, $qa, 'question', 'questiontext', $question->id);
60 foreach ($placeholders as $i => $placeholder) {
61 $questiontext = preg_replace('/'. preg_quote($placeholder, '/') . '/',
62 $embeddedelements[$placeholder], $questiontext);
63 }
0d24b17a 64
0d24b17a 65 $result = '';
b51f4f2e 66 $result .= html_writer::tag('div', $questiontext, array('class' => 'qtext'));
0d24b17a
TH
67
68 $result .= $this->post_qtext_elements($qa, $options);
69
70 if ($qa->get_state() == question_state::$invalid) {
71 $result .= html_writer::nonempty_tag('div',
72 $question->get_validation_error($qa->get_last_qt_data()),
73 array('class' => 'validationerror'));
74 }
75
76 return $result;
77 }
78
b197da87
MG
79 /**
80 * Find strings that we can use to glue the fragments with
81 *
82 * These strings have to be all different and neither of them can be present in the text
83 *
84 * @param array $fragments
85 * @return array array with indexes from 1 to count($fragments)-1
86 */
87 protected function get_fragments_glue_placeholders($fragments) {
88 $fragmentscount = count($fragments);
89 if ($fragmentscount <= 1) {
90 return [];
91 }
92 $prefix = '[[$';
93 $postfix = ']]';
94 $text = join('', $fragments);
95 while (preg_match('/' . preg_quote($prefix, '/') . '\\d+' . preg_quote($postfix, '/') . '/', $text)) {
96 $prefix .= '$';
97 }
98 $glues = [];
99 for ($i = 1; $i < $fragmentscount; $i++) {
100 $glues[$i] = $prefix . $i . $postfix;
101 }
102 return $glues;
103 }
104
0f5bb175
JP
105 protected function qtext_id($qa) {
106 return str_replace(':', '_', $qa->get_qt_field_name(''));
107 }
108
060e0294
TH
109 protected abstract function embedded_element(question_attempt $qa, $place,
110 question_display_options $options);
0d24b17a 111
060e0294
TH
112 protected function post_qtext_elements(question_attempt $qa,
113 question_display_options $options) {
0d24b17a
TH
114 return '';
115 }
116
33be3558
JP
117 protected function box_id(question_attempt $qa, $place) {
118 return str_replace(':', '_', $qa->get_qt_field_name($place));
0d24b17a
TH
119 }
120
121 public function specific_feedback(question_attempt $qa) {
122 return $this->combined_feedback($qa);
123 }
124
125 public function correct_response(question_attempt $qa) {
126 $question = $qa->get_question();
127
128 $correctanswer = '';
129 foreach ($question->textfragments as $i => $fragment) {
130 if ($i > 0) {
131 $group = $question->places[$i];
132 $choice = $question->choices[$group][$question->rightchoices[$i]];
133 $correctanswer .= '[' . str_replace('-', '&#x2011;',
134 $choice->text) . ']';
135 }
136 $correctanswer .= $fragment;
137 }
138
139 if (!empty($correctanswer)) {
a719f4d2
TH
140 return get_string('correctansweris', 'qtype_gapselect',
141 $question->format_text($correctanswer, $question->questiontextformat,
142 $qa, 'question', 'questiontext', $question->id));
0d24b17a
TH
143 }
144 }
145}