MDL-70153 qtype_essay: Add behat test for attachments max size
[moodle.git] / question / type / ddimageortext / edit_ddimageortext_form.php
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/>.
18 /**
19  * Defines the editing form for the drag-and-drop images onto images question type.
20  *
21  * @package   qtype_ddimageortext
22  * @copyright 2009 The Open University
23  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 require_once($CFG->dirroot . '/question/type/ddimageortext/edit_ddtoimage_form_base.php');
31 /**
32  * Drag-and-drop images onto images  editing form definition.
33  *
34  * @copyright 2009 The Open University
35  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36  */
37 class qtype_ddimageortext_edit_form extends qtype_ddtoimage_edit_form_base {
38     public function qtype() {
39         return 'ddimageortext';
40     }
42     public function data_preprocessing($question) {
43         $question = parent::data_preprocessing($question);
44         $question = $this->data_preprocessing_combined_feedback($question, true);
45         $question = $this->data_preprocessing_hints($question, true, true);
47         $dragids = array(); // Drag no -> dragid.
48         if (!empty($question->options)) {
49             $question->shuffleanswers = $question->options->shuffleanswers;
50             $question->drags = array();
51             foreach ($question->options->drags as $drag) {
52                 $dragindex = $drag->no - 1;
53                 $question->drags[$dragindex] = array();
54                 $question->draglabel[$dragindex] = $drag->label;
55                 $question->drags[$dragindex]['infinite'] = $drag->infinite;
56                 $question->drags[$dragindex]['draggroup'] = $drag->draggroup;
57                 $dragids[$dragindex] = $drag->id;
58             }
59             $question->drops = array();
60             foreach ($question->options->drops as $drop) {
61                 $question->drops[$drop->no - 1] = array();
62                 $question->drops[$drop->no - 1]['choice'] = $drop->choice;
63                 $question->drops[$drop->no - 1]['droplabel'] = $drop->label;
64                 $question->drops[$drop->no - 1]['xleft'] = $drop->xleft;
65                 $question->drops[$drop->no - 1]['ytop'] = $drop->ytop;
66             }
67         }
68         // Initialise file picker for bgimage.
69         $draftitemid = file_get_submitted_draft_itemid('bgimage');
71         file_prepare_draft_area($draftitemid, $this->context->id, 'qtype_ddimageortext',
72                                 'bgimage', !empty($question->id) ? (int) $question->id : null,
73                                 self::file_picker_options());
74         $question->bgimage = $draftitemid;
76         // Initialise file picker for dragimages.
77         list(, $imagerepeats) = $this->get_drag_item_repeats();
78         $draftitemids = optional_param_array('dragitem', array(), PARAM_INT);
79         for ($imageindex = 0; $imageindex < $imagerepeats; $imageindex++) {
80             $draftitemid = isset($draftitemids[$imageindex]) ? $draftitemids[$imageindex] : 0;
81             // Numbers not allowed in filearea name.
82             $itemid = isset($dragids[$imageindex]) ? $dragids[$imageindex] : null;
83             file_prepare_draft_area($draftitemid, $this->context->id, 'qtype_ddimageortext',
84                                 'dragimage', $itemid, self::file_picker_options());
85             $question->dragitem[$imageindex] = $draftitemid;
86         }
87         if (!empty($question->options)) {
88             foreach ($question->options->drags as $drag) {
89                 $dragindex = $drag->no - 1;
90                 if (!isset($question->dragitem[$dragindex])) {
91                     $fileexists = false;
92                 } else {
93                     $fileexists = self::file_uploaded($question->dragitem[$dragindex]);
94                 }
95                 $labelexists = (trim($question->draglabel[$dragindex]) != '');
96                 if ($labelexists && !$fileexists) {
97                     $question->drags[$dragindex]['dragitemtype'] = 'word';
98                 } else {
99                     $question->drags[$dragindex]['dragitemtype'] = 'image';
100                 }
101             }
102         }
103         $this->js_call();
105         return $question;
106     }
109     public function js_call() {
110         global $PAGE;
111         $PAGE->requires->js_call_amd('qtype_ddimageortext/form', 'init');
112     }
114     // Drag items.
116     protected function definition_draggable_items($mform, $itemrepeatsatstart) {
117         $mform->addElement('header', 'draggableitemheader',
118                                 get_string('draggableitems', 'qtype_ddimageortext'));
119         $mform->addElement('advcheckbox', 'shuffleanswers', ' ',
120                                 get_string('shuffleimages', 'qtype_'.$this->qtype()));
121         $mform->setDefault('shuffleanswers', 0);
122         $this->repeat_elements($this->draggable_item($mform), $itemrepeatsatstart,
123                 $this->draggable_items_repeated_options(),
124                 'noitems', 'additems', self::ADD_NUM_ITEMS,
125                 get_string('addmoreimages', 'qtype_ddimageortext'), true);
126     }
128     protected function draggable_item($mform) {
129         $draggableimageitem = array();
131         $grouparray = array();
132         $dragitemtypes = array('image' => get_string('draggableimage', 'qtype_ddimageortext'),
133                                 'word' => get_string('draggableword', 'qtype_ddimageortext'));
134         $grouparray[] = $mform->createElement('select', 'dragitemtype',
135                                             get_string('draggableitemtype', 'qtype_ddimageortext'),
136                                             $dragitemtypes,
137                                             array('class' => 'dragitemtype'));
138         $options = array();
139         for ($i = 1; $i <= self::MAX_GROUPS; $i += 1) {
140             $options[$i] = question_utils::int_to_letter($i);
141         }
142         $grouparray[] = $mform->createElement('select', 'draggroup',
143                                                 get_string('group', 'qtype_gapselect'),
144                                                 $options,
145                                                 array('class' => 'draggroup'));
146         $grouparray[] = $mform->createElement('advcheckbox', 'infinite', ' ',
147                 get_string('infinite', 'qtype_ddimageortext'));
148         $draggableimageitem[] = $mform->createElement('group', 'drags',
149                 get_string('draggableitemheader', 'qtype_ddimageortext', '{no}'), $grouparray);
151         $draggableimageitem[] = $mform->createElement('filepicker', 'dragitem', '', null,
152                                     self::file_picker_options());
154         $draggableimageitem[] = $mform->createElement('text', 'draglabel',
155                                                 get_string('label', 'qtype_ddimageortext'),
156                                                 array('size' => 30, 'class' => 'tweakcss draglabel'));
157         $mform->setType('draglabel', PARAM_RAW); // These are validated manually.
158         return $draggableimageitem;
159     }
161     protected function draggable_items_repeated_options() {
162         $repeatedoptions = array();
163         $repeatedoptions['draggroup']['default'] = '1';
164         return $repeatedoptions;
165     }
167     // Drop zones.
169     protected function drop_zone($mform, $imagerepeats) {
170         $dropzoneitem = array();
172         $grouparray = array();
173         $grouparray[] = $mform->createElement('text', 'xleft',
174                                                 get_string('xleft', 'qtype_ddimageortext'),
175                                                 array('size' => 5, 'class' => 'tweakcss'));
176         $grouparray[] = $mform->createElement('text', 'ytop',
177                                                 get_string('ytop', 'qtype_ddimageortext'),
178                                                 array('size' => 5, 'class' => 'tweakcss'));
179         $options = array();
181         $options[0] = '';
182         for ($i = 1; $i <= $imagerepeats; $i += 1) {
183             $options[$i] = $i;
184         }
185         $grouparray[] = $mform->createElement('select', 'choice',
186                                     get_string('draggableitem', 'qtype_ddimageortext'), $options);
187         $grouparray[] = $mform->createElement('text', 'droplabel',
188                                                 get_string('label', 'qtype_ddimageortext'),
189                                                 array('size' => 10, 'class' => 'tweakcss'));
190         $mform->setType('droplabel', PARAM_NOTAGS);
191         $dropzone = $mform->createElement('group', 'drops',
192                 get_string('dropzone', 'qtype_ddimageortext', '{no}'), $grouparray);
193         return array($dropzone);
194     }
196     protected function drop_zones_repeated_options() {
197         $repeatedoptions = array();
198         // The next two are PARAM_RAW becuase we need to distinguish 0 and ''.
199         // We do the necessary validation in the validation method.
200         $repeatedoptions['drops[xleft]']['type']     = PARAM_RAW;
201         $repeatedoptions['drops[ytop]']['type']      = PARAM_RAW;
202         $repeatedoptions['drops[droplabel]']['type'] = PARAM_RAW;
203         $repeatedoptions['choice']['default'] = '0';
204         return $repeatedoptions;
205     }
207     public function validation($data, $files) {
208         $errors = parent::validation($data, $files);
209         if (!self::file_uploaded($data['bgimage'])) {
210             $errors["bgimage"] = get_string('formerror_nobgimage', 'qtype_'.$this->qtype());
211         }
213         $allchoices = array();
214         for ($i = 0; $i < $data['nodropzone']; $i++) {
215             $ytoppresent = (trim($data['drops'][$i]['ytop']) !== '');
216             $xleftpresent = (trim($data['drops'][$i]['xleft']) !== '');
217             $ytopisint = (string) clean_param($data['drops'][$i]['ytop'], PARAM_INT) === trim($data['drops'][$i]['ytop']);
218             $xleftisint = (string) clean_param($data['drops'][$i]['xleft'], PARAM_INT) === trim($data['drops'][$i]['xleft']);
219             $labelpresent = (trim($data['drops'][$i]['droplabel']) !== '');
220             $choice = $data['drops'][$i]['choice'];
221             $imagechoicepresent = ($choice !== '0');
223             if ($imagechoicepresent) {
224                 if (!$ytoppresent) {
225                     $errors["drops[$i]"] = get_string('formerror_noytop', 'qtype_ddimageortext');
226                 } else if (!$ytopisint) {
227                     $errors["drops[$i]"] = get_string('formerror_notintytop', 'qtype_ddimageortext');
228                 }
229                 if (!$xleftpresent) {
230                     $errors["drops[$i]"] = get_string('formerror_noxleft', 'qtype_ddimageortext');
231                 } else if (!$xleftisint) {
232                     $errors["drops[$i]"] = get_string('formerror_notintxleft', 'qtype_ddimageortext');
233                 }
235                 if ($data['drags'][$choice - 1]['dragitemtype'] != 'word' &&
236                                         !self::file_uploaded($data['dragitem'][$choice - 1])) {
237                     $errors['dragitem['.($choice - 1).']'] =
238                                     get_string('formerror_nofile', 'qtype_ddimageortext', $i);
239                 }
241                 if (isset($allchoices[$choice]) && !$data['drags'][$choice - 1]['infinite']) {
242                     $errors["drops[$i]"] =
243                             get_string('formerror_multipledraginstance', 'qtype_ddimageortext', $choice);
244                     $errors['drops['.($allchoices[$choice]).']'] =
245                             get_string('formerror_multipledraginstance', 'qtype_ddimageortext', $choice);
246                     $errors['drags['.($choice - 1).']'] =
247                             get_string('formerror_multipledraginstance2', 'qtype_ddimageortext', $choice);
248                 }
249                 $allchoices[$choice] = $i;
250             } else {
251                 if ($ytoppresent || $xleftpresent || $labelpresent) {
252                     $errors["drops[$i]"] =
253                             get_string('formerror_noimageselected', 'qtype_ddimageortext');
254                 }
255             }
256         }
257         for ($dragindex = 0; $dragindex < $data['noitems']; $dragindex++) {
258             $label = $data['draglabel'][$dragindex];
259             if ($data['drags'][$dragindex]['dragitemtype'] == 'word') {
260                 $allowedtags = '<br><sub><sup><b><i><strong><em><span>';
261                 $errormessage = get_string('formerror_disallowedtags', 'qtype_ddimageortext', s($allowedtags));
262             } else {
263                 $allowedtags = '';
264                 $errormessage = get_string('formerror_noallowedtags', 'qtype_ddimageortext');
265             }
266             if ($label != strip_tags($label, $allowedtags)) {
267                 $errors["drags[{$dragindex}]"] = $errormessage;
268             }
270         }
271         return $errors;
272     }