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 |
* Question type class for the drag-and-drop onto image question type.
|
|
|
19 |
*
|
|
|
20 |
* @package qtype_ddimageortext
|
|
|
21 |
* @copyright 2009 The Open University
|
|
|
22 |
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
|
23 |
*/
|
|
|
24 |
|
|
|
25 |
|
|
|
26 |
defined('MOODLE_INTERNAL') || die();
|
|
|
27 |
|
|
|
28 |
require_once($CFG->dirroot . '/question/type/ddimageortext/questiontypebase.php');
|
|
|
29 |
|
|
|
30 |
/**
|
|
|
31 |
* The drag-and-drop onto image question type class.
|
|
|
32 |
*
|
|
|
33 |
* @copyright 2009 The Open University
|
|
|
34 |
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
|
35 |
*/
|
|
|
36 |
class qtype_ddimageortext extends qtype_ddtoimage_base {
|
|
|
37 |
|
|
|
38 |
protected function make_choice($dragdata) {
|
|
|
39 |
return new qtype_ddimageortext_drag_item($dragdata->label, $dragdata->no,
|
|
|
40 |
$dragdata->draggroup, $dragdata->infinite, $dragdata->id);
|
|
|
41 |
}
|
|
|
42 |
|
|
|
43 |
protected function make_place($dropzonedata) {
|
|
|
44 |
return new qtype_ddimageortext_drop_zone($dropzonedata->label, $dropzonedata->no,
|
|
|
45 |
$dropzonedata->group,
|
|
|
46 |
$dropzonedata->xleft, $dropzonedata->ytop);
|
|
|
47 |
}
|
|
|
48 |
|
|
|
49 |
protected function make_hint($hint) {
|
|
|
50 |
return question_hint_with_parts::load_from_record($hint);
|
|
|
51 |
}
|
|
|
52 |
|
|
|
53 |
public function save_defaults_for_new_questions(stdClass $fromform): void {
|
|
|
54 |
parent::save_defaults_for_new_questions($fromform);
|
|
|
55 |
$this->set_default_value('shuffleanswers', $fromform->shuffleanswers);
|
|
|
56 |
}
|
|
|
57 |
|
|
|
58 |
public function save_question_options($formdata) {
|
|
|
59 |
global $DB, $USER;
|
|
|
60 |
$context = $formdata->context;
|
|
|
61 |
|
|
|
62 |
$options = $DB->get_record('qtype_ddimageortext', array('questionid' => $formdata->id));
|
|
|
63 |
if (!$options) {
|
|
|
64 |
$options = new stdClass();
|
|
|
65 |
$options->questionid = $formdata->id;
|
|
|
66 |
$options->correctfeedback = '';
|
|
|
67 |
$options->partiallycorrectfeedback = '';
|
|
|
68 |
$options->incorrectfeedback = '';
|
|
|
69 |
$options->id = $DB->insert_record('qtype_ddimageortext', $options);
|
|
|
70 |
}
|
|
|
71 |
|
|
|
72 |
$options->shuffleanswers = !empty($formdata->shuffleanswers);
|
|
|
73 |
$options = $this->save_combined_feedback_helper($options, $formdata, $context, true);
|
|
|
74 |
$this->save_hints($formdata, true);
|
|
|
75 |
$DB->update_record('qtype_ddimageortext', $options);
|
|
|
76 |
$DB->delete_records('qtype_ddimageortext_drops', array('questionid' => $formdata->id));
|
|
|
77 |
foreach (array_keys($formdata->drops) as $dropno) {
|
|
|
78 |
if ($formdata->drops[$dropno]['choice'] == 0) {
|
|
|
79 |
continue;
|
|
|
80 |
}
|
|
|
81 |
$drop = new stdClass();
|
|
|
82 |
$drop->questionid = $formdata->id;
|
|
|
83 |
$drop->no = $dropno + 1;
|
|
|
84 |
$drop->xleft = $formdata->drops[$dropno]['xleft'];
|
|
|
85 |
$drop->ytop = $formdata->drops[$dropno]['ytop'];
|
|
|
86 |
$drop->choice = $formdata->drops[$dropno]['choice'];
|
|
|
87 |
$drop->label = $formdata->drops[$dropno]['droplabel'];
|
|
|
88 |
|
|
|
89 |
$DB->insert_record('qtype_ddimageortext_drops', $drop);
|
|
|
90 |
}
|
|
|
91 |
|
|
|
92 |
// An array of drag no -> drag id.
|
|
|
93 |
$olddragids = $DB->get_records_menu('qtype_ddimageortext_drags',
|
|
|
94 |
array('questionid' => $formdata->id),
|
|
|
95 |
'', 'no, id');
|
|
|
96 |
foreach (array_keys($formdata->drags) as $dragno) {
|
|
|
97 |
$info = file_get_draft_area_info($formdata->dragitem[$dragno]);
|
|
|
98 |
if ($info['filecount'] > 0 || (trim($formdata->draglabel[$dragno]) != '')) {
|
|
|
99 |
$draftitemid = $formdata->dragitem[$dragno];
|
|
|
100 |
|
|
|
101 |
$drag = new stdClass();
|
|
|
102 |
$drag->questionid = $formdata->id;
|
|
|
103 |
$drag->no = $dragno + 1;
|
|
|
104 |
$drag->draggroup = $formdata->drags[$dragno]['draggroup'];
|
|
|
105 |
$drag->infinite = empty($formdata->drags[$dragno]['infinite']) ? 0 : 1;
|
|
|
106 |
$drag->label = $formdata->draglabel[$dragno];
|
|
|
107 |
|
|
|
108 |
if (isset($olddragids[$dragno + 1])) {
|
|
|
109 |
$drag->id = $olddragids[$dragno + 1];
|
|
|
110 |
unset($olddragids[$dragno + 1]);
|
|
|
111 |
$DB->update_record('qtype_ddimageortext_drags', $drag);
|
|
|
112 |
} else {
|
|
|
113 |
$drag->id = $DB->insert_record('qtype_ddimageortext_drags', $drag);
|
|
|
114 |
}
|
|
|
115 |
|
|
|
116 |
if ($formdata->drags[$dragno]['dragitemtype'] == 'image') {
|
|
|
117 |
file_save_draft_area_files($draftitemid, $formdata->context->id,
|
|
|
118 |
'qtype_ddimageortext', 'dragimage', $drag->id,
|
|
|
119 |
array('subdirs' => 0, 'maxbytes' => 0, 'maxfiles' => 1));
|
|
|
120 |
} else {
|
|
|
121 |
// Delete any existing files for draggable text item type.
|
|
|
122 |
$fs = get_file_storage();
|
|
|
123 |
$fs->delete_area_files($formdata->context->id, 'qtype_ddimageortext',
|
|
|
124 |
'dragimage', $drag->id);
|
|
|
125 |
}
|
|
|
126 |
|
|
|
127 |
}
|
|
|
128 |
|
|
|
129 |
}
|
|
|
130 |
|
|
|
131 |
if (!empty($olddragids)) {
|
|
|
132 |
list($sql, $params) = $DB->get_in_or_equal(array_values($olddragids));
|
|
|
133 |
$DB->delete_records_select('qtype_ddimageortext_drags', "id $sql", $params);
|
|
|
134 |
}
|
|
|
135 |
file_save_draft_area_files($formdata->bgimage, $formdata->context->id,
|
|
|
136 |
'qtype_ddimageortext', 'bgimage', $formdata->id,
|
|
|
137 |
array('subdirs' => 0, 'maxbytes' => 0, 'maxfiles' => 1));
|
|
|
138 |
}
|
|
|
139 |
public function move_files($questionid, $oldcontextid, $newcontextid) {
|
|
|
140 |
global $DB;
|
|
|
141 |
$fs = get_file_storage();
|
|
|
142 |
|
|
|
143 |
parent::move_files($questionid, $oldcontextid, $newcontextid);
|
|
|
144 |
$fs->move_area_files_to_new_context($oldcontextid,
|
|
|
145 |
$newcontextid, 'qtype_ddimageortext', 'bgimage', $questionid);
|
|
|
146 |
$dragids = $DB->get_records_menu('qtype_ddimageortext_drags',
|
|
|
147 |
array('questionid' => $questionid), 'id', 'id,1');
|
|
|
148 |
foreach ($dragids as $dragid => $notused) {
|
|
|
149 |
$fs->move_area_files_to_new_context($oldcontextid,
|
|
|
150 |
$newcontextid, 'qtype_ddimageortext', 'dragimage', $dragid);
|
|
|
151 |
}
|
|
|
152 |
|
|
|
153 |
$this->move_files_in_combined_feedback($questionid, $oldcontextid, $newcontextid);
|
|
|
154 |
$this->move_files_in_hints($questionid, $oldcontextid, $newcontextid);
|
|
|
155 |
}
|
|
|
156 |
|
|
|
157 |
/**
|
|
|
158 |
* Delete all the files belonging to this question.
|
|
|
159 |
* @param int $questionid the question being deleted.
|
|
|
160 |
* @param int $contextid the context the question is in.
|
|
|
161 |
*/
|
|
|
162 |
|
|
|
163 |
protected function delete_files($questionid, $contextid) {
|
|
|
164 |
global $DB;
|
|
|
165 |
$fs = get_file_storage();
|
|
|
166 |
|
|
|
167 |
parent::delete_files($questionid, $contextid);
|
|
|
168 |
|
|
|
169 |
$dragids = $DB->get_records_menu('qtype_ddimageortext_drags',
|
|
|
170 |
array('questionid' => $questionid), 'id', 'id,1');
|
|
|
171 |
foreach ($dragids as $dragid => $notused) {
|
|
|
172 |
$fs->delete_area_files($contextid, 'qtype_ddimageortext', 'dragimage', $dragid);
|
|
|
173 |
}
|
|
|
174 |
|
|
|
175 |
$this->delete_files_in_combined_feedback($questionid, $contextid);
|
|
|
176 |
$this->delete_files_in_hints($questionid, $contextid);
|
|
|
177 |
}
|
|
|
178 |
|
|
|
179 |
|
|
|
180 |
public function export_to_xml($question, qformat_xml $format, $extra = null) {
|
|
|
181 |
$fs = get_file_storage();
|
|
|
182 |
$contextid = $question->contextid;
|
|
|
183 |
$output = '';
|
|
|
184 |
|
|
|
185 |
if ($question->options->shuffleanswers) {
|
|
|
186 |
$output .= " <shuffleanswers/>\n";
|
|
|
187 |
}
|
|
|
188 |
$output .= $format->write_combined_feedback($question->options,
|
|
|
189 |
$question->id,
|
|
|
190 |
$question->contextid);
|
|
|
191 |
$files = $fs->get_area_files($contextid, 'qtype_ddimageortext', 'bgimage', $question->id);
|
|
|
192 |
$output .= " ".$this->write_files($files, 2)."\n";;
|
|
|
193 |
|
|
|
194 |
foreach ($question->options->drags as $drag) {
|
|
|
195 |
$files =
|
|
|
196 |
$fs->get_area_files($contextid, 'qtype_ddimageortext', 'dragimage', $drag->id);
|
|
|
197 |
$output .= " <drag>\n";
|
|
|
198 |
$output .= " <no>{$drag->no}</no>\n";
|
|
|
199 |
$output .= $format->writetext($drag->label, 3)."\n";
|
|
|
200 |
$output .= " <draggroup>{$drag->draggroup}</draggroup>\n";
|
|
|
201 |
if ($drag->infinite) {
|
|
|
202 |
$output .= " <infinite/>\n";
|
|
|
203 |
}
|
|
|
204 |
$output .= $this->write_files($files, 3);
|
|
|
205 |
$output .= " </drag>\n";
|
|
|
206 |
}
|
|
|
207 |
foreach ($question->options->drops as $drop) {
|
|
|
208 |
$output .= " <drop>\n";
|
|
|
209 |
$output .= $format->writetext($drop->label, 3);
|
|
|
210 |
$output .= " <no>{$drop->no}</no>\n";
|
|
|
211 |
$output .= " <choice>{$drop->choice}</choice>\n";
|
|
|
212 |
$output .= " <xleft>{$drop->xleft}</xleft>\n";
|
|
|
213 |
$output .= " <ytop>{$drop->ytop}</ytop>\n";
|
|
|
214 |
$output .= " </drop>\n";
|
|
|
215 |
}
|
|
|
216 |
|
|
|
217 |
return $output;
|
|
|
218 |
}
|
|
|
219 |
|
|
|
220 |
public function import_from_xml($data, $question, qformat_xml $format, $extra=null) {
|
|
|
221 |
if (!isset($data['@']['type']) || $data['@']['type'] != 'ddimageortext') {
|
|
|
222 |
return false;
|
|
|
223 |
}
|
|
|
224 |
|
|
|
225 |
$question = $format->import_headers($data);
|
|
|
226 |
$question->qtype = 'ddimageortext';
|
|
|
227 |
|
|
|
228 |
$question->shuffleanswers = array_key_exists('shuffleanswers',
|
|
|
229 |
$format->getpath($data, array('#'), array()));
|
|
|
230 |
|
|
|
231 |
$filexml = $format->getpath($data, array('#', 'file'), array());
|
|
|
232 |
$question->bgimage = $format->import_files_as_draft($filexml);
|
|
|
233 |
$drags = $data['#']['drag'];
|
|
|
234 |
$question->drags = array();
|
|
|
235 |
|
|
|
236 |
foreach ($drags as $dragxml) {
|
|
|
237 |
$dragno = $format->getpath($dragxml, array('#', 'no', 0, '#'), 0);
|
|
|
238 |
$dragindex = $dragno - 1;
|
|
|
239 |
$question->drags[$dragindex] = array();
|
|
|
240 |
$question->draglabel[$dragindex] =
|
|
|
241 |
$format->getpath($dragxml, array('#', 'text', 0, '#'), '', true);
|
|
|
242 |
$question->drags[$dragindex]['infinite'] = array_key_exists('infinite', $dragxml['#']);
|
|
|
243 |
$question->drags[$dragindex]['draggroup'] =
|
|
|
244 |
$format->getpath($dragxml, array('#', 'draggroup', 0, '#'), 1);
|
|
|
245 |
$filexml = $format->getpath($dragxml, array('#', 'file'), array());
|
|
|
246 |
$question->dragitem[$dragindex] = $format->import_files_as_draft($filexml);
|
|
|
247 |
if (count($filexml)) {
|
|
|
248 |
$question->drags[$dragindex]['dragitemtype'] = 'image';
|
|
|
249 |
} else {
|
|
|
250 |
$question->drags[$dragindex]['dragitemtype'] = 'word';
|
|
|
251 |
}
|
|
|
252 |
}
|
|
|
253 |
|
|
|
254 |
$drops = $data['#']['drop'];
|
|
|
255 |
$question->drops = array();
|
|
|
256 |
foreach ($drops as $dropxml) {
|
|
|
257 |
$dropno = $format->getpath($dropxml, array('#', 'no', 0, '#'), 0);
|
|
|
258 |
$dropindex = $dropno - 1;
|
|
|
259 |
$question->drops[$dropindex] = array();
|
|
|
260 |
$question->drops[$dropindex]['choice'] =
|
|
|
261 |
$format->getpath($dropxml, array('#', 'choice', 0, '#'), 0);
|
|
|
262 |
$question->drops[$dropindex]['droplabel'] =
|
|
|
263 |
$format->getpath($dropxml, array('#', 'text', 0, '#'), '', true);
|
|
|
264 |
$question->drops[$dropindex]['xleft'] =
|
|
|
265 |
$format->getpath($dropxml, array('#', 'xleft', 0, '#'), '');
|
|
|
266 |
$question->drops[$dropindex]['ytop'] =
|
|
|
267 |
$format->getpath($dropxml, array('#', 'ytop', 0, '#'), '');
|
|
|
268 |
}
|
|
|
269 |
|
|
|
270 |
$format->import_combined_feedback($question, $data, true);
|
|
|
271 |
$format->import_hints($question, $data, true, false,
|
|
|
272 |
$format->get_format($question->questiontextformat));
|
|
|
273 |
|
|
|
274 |
return $question;
|
|
|
275 |
}
|
|
|
276 |
|
|
|
277 |
}
|