MDL-47494 ddmarker: NOBUG extending functionality from ddimageortext question type.
This commit is contained in:
@@ -14,6 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
require_once($CFG->dirroot.'/question/type/ddimageortext/edit_ddtoimage_form_base.php');
|
||||
|
||||
/**
|
||||
* Defines the editing form for the drag-and-drop images onto images question type.
|
||||
*
|
||||
@@ -31,351 +33,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @copyright 2009 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class qtype_ddmarker_edit_form extends question_edit_form {
|
||||
const MAX_GROUPS = 8;
|
||||
const START_NUM_ITEMS = 6;
|
||||
const ADD_NUM_ITEMS = 3;
|
||||
|
||||
public function qtype() {
|
||||
return 'ddmarker';
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Options shared by all file pickers in the form.
|
||||
*/
|
||||
public static function file_picker_options() {
|
||||
$filepickeroptions = array();
|
||||
$filepickeroptions['accepted_types'] = array('web_image');
|
||||
$filepickeroptions['maxbytes'] = 0;
|
||||
$filepickeroptions['maxfiles'] = 1;
|
||||
$filepickeroptions['subdirs'] = 0;
|
||||
return $filepickeroptions;
|
||||
}
|
||||
|
||||
protected function get_drag_image_repeats() {
|
||||
$countimages = 0;
|
||||
if (isset($this->question->id)) {
|
||||
foreach ($this->question->options->drags as $drag) {
|
||||
$countimages = max($countimages, $drag->no);
|
||||
}
|
||||
}
|
||||
if ($this->question->formoptions->repeatelements) {
|
||||
$imagerepeatsatstart = max(self::START_NUM_ITEMS, $countimages + self::ADD_NUM_ITEMS);
|
||||
} else {
|
||||
$imagerepeatsatstart = $countimages;
|
||||
}
|
||||
$imagerepeats = optional_param('noitems', $imagerepeatsatstart, PARAM_INT);
|
||||
$addfields = optional_param('additems', '', PARAM_TEXT);
|
||||
if (!empty($addfields)) {
|
||||
$imagerepeats += self::ADD_NUM_ITEMS;
|
||||
}
|
||||
return array($imagerepeatsatstart, $imagerepeats);
|
||||
}
|
||||
|
||||
/**
|
||||
* definition_inner adds all specific fields to the form.
|
||||
* @param object $mform (the form being built).
|
||||
*/
|
||||
protected function definition_inner($mform) {
|
||||
|
||||
$mform->addElement('header', 'previewareaheader',
|
||||
get_string('previewareaheader', 'qtype_ddmarker'));
|
||||
$mform->addElement('static', 'previewarea',
|
||||
get_string('previewarea', 'qtype_ddmarker'),
|
||||
get_string('previewareamessage', 'qtype_ddmarker'));
|
||||
|
||||
$mform->registerNoSubmitButton('refresh');
|
||||
$mform->addElement('submit', 'refresh', get_string('refresh', 'qtype_ddmarker'));
|
||||
$mform->closeHeaderBefore('refresh');
|
||||
|
||||
list($imagerepeatsatstart, $imagerepeats) = $this->get_drag_image_repeats();
|
||||
$this->definition_drop_zones($mform, $imagerepeats);
|
||||
$mform->addElement('advcheckbox', 'shuffleanswers', ' ',
|
||||
get_string('shuffleimages', 'qtype_ddmarker'));
|
||||
$mform->setDefault('shuffleanswers', 0);
|
||||
$mform->closeHeaderBefore('shuffleanswers');
|
||||
//add the draggable image fields to the form
|
||||
$this->definition_draggable_images($mform, $imagerepeatsatstart);
|
||||
|
||||
$this->add_combined_feedback_fields(true);
|
||||
$this->add_interactive_settings(true, true);
|
||||
}
|
||||
|
||||
protected function definition_drop_zones($mform, $imagerepeats) {
|
||||
$mform->addElement('header', 'dropzoneheader',
|
||||
get_string('dropzoneheader', 'qtype_ddmarker'));
|
||||
|
||||
$mform->addElement('filepicker', 'bgimage', get_string('bgimage', 'qtype_ddmarker'),
|
||||
null, self::file_picker_options());
|
||||
|
||||
$countdropzones = 0;
|
||||
if (isset($this->question->id)) {
|
||||
foreach ($this->question->options->drops as $drop) {
|
||||
$countdropzones = max($countdropzones, $drop->no);
|
||||
}
|
||||
}
|
||||
if ($this->question->formoptions->repeatelements) {
|
||||
$dropzonerepeatsatstart = max(self::START_NUM_ITEMS,
|
||||
$countdropzones + self::ADD_NUM_ITEMS);
|
||||
} else {
|
||||
$dropzonerepeatsatstart = $countdropzones;
|
||||
}
|
||||
|
||||
$this->repeat_elements($this->drop_zone($mform, $imagerepeats), $dropzonerepeatsatstart,
|
||||
$this->drop_zones_repeated_options(),
|
||||
'nodropzone', 'adddropzone', self::ADD_NUM_ITEMS,
|
||||
get_string('addmoredropzones', 'qtype_ddmarker'));
|
||||
}
|
||||
|
||||
protected function drop_zone($mform, $imagerepeats) {
|
||||
$dropzoneitem = array();
|
||||
|
||||
$grouparray = array();
|
||||
$grouparray[] = $mform->createElement('static', 'xleftlabel', '',
|
||||
' '.get_string('xleft', 'qtype_ddmarker').' ');
|
||||
$grouparray[] = $mform->createElement('text', 'xleft',
|
||||
get_string('xleft', 'qtype_ddmarker'),
|
||||
array('size'=>5, 'class'=>'tweakcss'));
|
||||
$mform->setType('xleft', PARAM_NOTAGS);
|
||||
$grouparray[] = $mform->createElement('static', 'ytoplabel', '',
|
||||
' '.get_string('ytop', 'qtype_ddmarker').' ');
|
||||
$grouparray[] = $mform->createElement('text', 'ytop',
|
||||
get_string('ytop', 'qtype_ddmarker'),
|
||||
array('size'=>5, 'class'=>'tweakcss'));
|
||||
$mform->setType('ytop', PARAM_NOTAGS);
|
||||
$options = array();
|
||||
|
||||
$options[0] = '';
|
||||
for ($i = 1; $i <= $imagerepeats; $i += 1) {
|
||||
$options[$i] = $i;
|
||||
}
|
||||
$grouparray[] = $mform->createElement('static', '', '', ' ' .
|
||||
get_string('draggableitem', 'qtype_ddmarker').' ');
|
||||
$grouparray[] = $mform->createElement('select', 'choice',
|
||||
get_string('draggableitem', 'qtype_ddmarker'), $options);
|
||||
$grouparray[] = $mform->createElement('static', '', '', ' ' .
|
||||
get_string('label', 'qtype_ddmarker').' ');
|
||||
$grouparray[] = $mform->createElement('text', 'droplabel',
|
||||
get_string('label', 'qtype_ddmarker'),
|
||||
array('size'=>10, 'class'=>'tweakcss'));
|
||||
$mform->setType('droplabel', PARAM_NOTAGS);
|
||||
$dropzone = $mform->createElement('group', 'drops',
|
||||
get_string('dropzone', 'qtype_ddmarker', '{no}'), $grouparray);
|
||||
return array($dropzone);
|
||||
}
|
||||
|
||||
protected function drop_zones_repeated_options() {
|
||||
$repeatedoptions = array();
|
||||
$repeatedoptions['choice']['default'] = '0';
|
||||
return $repeatedoptions;
|
||||
}
|
||||
|
||||
protected function definition_draggable_images($mform, $imagerepeatsatstart) {
|
||||
|
||||
$this->repeat_elements($this->draggable_image($mform), $imagerepeatsatstart,
|
||||
$this->draggable_images_repeated_options(),
|
||||
'noitems', 'additems', self::ADD_NUM_ITEMS,
|
||||
get_string('addmoreimages', 'qtype_ddmarker'));
|
||||
}
|
||||
|
||||
protected function draggable_image($mform) {
|
||||
$draggableimageitem = array();
|
||||
|
||||
$draggableimageitem[] = $mform->createElement('header', 'draggableitemheader',
|
||||
get_string('draggableitemheader', 'qtype_ddmarker', '{no}'));
|
||||
$dragitemtypes = array('image' => get_string('draggableimage', 'qtype_ddmarker'),
|
||||
'word' => get_string('draggableword', 'qtype_ddmarker'));
|
||||
$draggableimageitem[] = $mform->createElement('select', 'dragitemtype',
|
||||
get_string('draggableitemtype', 'qtype_ddmarker'),
|
||||
$dragitemtypes,
|
||||
array('class' => 'dragitemtype'));
|
||||
$draggableimageitem[] = $mform->createElement('filepicker', 'dragitem', '', null,
|
||||
self::file_picker_options());
|
||||
|
||||
$grouparray = array();
|
||||
$grouparray[] = $mform->createElement('text', 'draglabel',
|
||||
get_string('label', 'qtype_ddmarker'),
|
||||
array('size'=>30, 'class'=>'tweakcss'));
|
||||
$mform->setType('draglabel', PARAM_NOTAGS);
|
||||
$options = array();
|
||||
for ($i = 1; $i <= self::MAX_GROUPS; $i += 1) {
|
||||
$options[$i] = $i;
|
||||
}
|
||||
$grouparray[] = $mform->createElement('static', '', '', ' ' .
|
||||
get_string('group', 'qtype_gapselect').' ');
|
||||
$grouparray[] = $mform->createElement('select', 'draggroup',
|
||||
get_string('group', 'qtype_gapselect'),
|
||||
$options,
|
||||
array('class' => 'draggroup'));
|
||||
$grouparray[] = $mform->createElement('advcheckbox', 'infinite', ' ',
|
||||
get_string('infinite', 'qtype_ddmarker'));
|
||||
$draggableimageitem[] = $mform->createElement('group', 'drags',
|
||||
get_string('label', 'qtype_ddmarker'), $grouparray);
|
||||
return $draggableimageitem;
|
||||
}
|
||||
|
||||
protected function draggable_images_repeated_options() {
|
||||
$repeatedoptions = array();
|
||||
$repeatedoptions['draggroup']['default'] = '1';
|
||||
return $repeatedoptions;
|
||||
}
|
||||
|
||||
public function data_preprocessing($question) {
|
||||
global $PAGE;
|
||||
|
||||
$question = parent::data_preprocessing($question);
|
||||
$question = $this->data_preprocessing_combined_feedback($question, true);
|
||||
$question = $this->data_preprocessing_hints($question, true, true);
|
||||
|
||||
$dragids = array(); // drag no -> dragid
|
||||
if (!empty($question->options)) {
|
||||
$question->shuffleanswers = $question->options->shuffleanswers;
|
||||
$question->drags = array();
|
||||
foreach ($question->options->drags as $drag) {
|
||||
$dragindex = $drag->no -1;
|
||||
$question->drags[$dragindex] = array();
|
||||
$question->drags[$dragindex]['draglabel'] = $drag->label;
|
||||
$question->drags[$dragindex]['infinite'] = $drag->infinite;
|
||||
$question->drags[$dragindex]['draggroup'] = $drag->draggroup;
|
||||
$dragids[$dragindex] = $drag->id;
|
||||
}
|
||||
$question->drops = array();
|
||||
foreach ($question->options->drops as $drop) {
|
||||
$question->drops[$drop->no -1] = array();
|
||||
$question->drops[$drop->no -1]['choice'] = $drop->choice;
|
||||
$question->drops[$drop->no -1]['droplabel'] = $drop->label;
|
||||
$question->drops[$drop->no -1]['xleft'] = $drop->xleft;
|
||||
$question->drops[$drop->no -1]['ytop'] = $drop->ytop;
|
||||
}
|
||||
}
|
||||
//initialise file picker for bgimage
|
||||
$draftitemid = file_get_submitted_draft_itemid('bgimage');
|
||||
|
||||
file_prepare_draft_area($draftitemid, $this->context->id, 'qtype_ddmarker',
|
||||
'bgimage', !empty($question->id) ? (int) $question->id : null,
|
||||
self::file_picker_options());
|
||||
$question->bgimage = $draftitemid;
|
||||
|
||||
//initialise file picker for dragimages
|
||||
list(, $imagerepeats) = $this->get_drag_image_repeats();
|
||||
$draftitemids = optional_param_array('dragitem', array(), PARAM_INT);
|
||||
for ($imageindex = 0; $imageindex < $imagerepeats; $imageindex++) {
|
||||
$draftitemid = isset($draftitemids[$imageindex]) ? $draftitemids[$imageindex] :0;
|
||||
//numbers not allowed in filearea name
|
||||
$itemid = isset($dragids[$imageindex]) ? $dragids[$imageindex] : null;
|
||||
file_prepare_draft_area($draftitemid, $this->context->id, 'qtype_ddmarker',
|
||||
'dragimage', $itemid, self::file_picker_options());
|
||||
$question->dragitem[$imageindex] = $draftitemid;
|
||||
}
|
||||
if (!empty($question->options)) {
|
||||
foreach ($question->options->drags as $drag) {
|
||||
$dragindex = $drag->no -1;
|
||||
if (!isset($question->dragitem[$dragindex])) {
|
||||
$fileexists = false;
|
||||
} else {
|
||||
$fileexists = self::file_uploaded($question->dragitem[$dragindex]);
|
||||
}
|
||||
$labelexists = $question->drags[$dragindex]['draglabel'];
|
||||
if ($labelexists && !$fileexists) {
|
||||
$question->dragitemtype[$dragindex] = 'word';
|
||||
} else {
|
||||
$question->dragitemtype[$dragindex] = 'image';
|
||||
}
|
||||
}
|
||||
}
|
||||
$maxsizes =new stdClass();
|
||||
$maxsizes->bgimage = new stdClass();
|
||||
$maxsizes->bgimage->width = QTYPE_ddmarker_BGIMAGE_MAXWIDTH;
|
||||
$maxsizes->bgimage->height = QTYPE_ddmarker_BGIMAGE_MAXHEIGHT;
|
||||
$maxsizes->dragimage = new stdClass();
|
||||
$maxsizes->dragimage->width = QTYPE_ddmarker_DRAGIMAGE_MAXWIDTH;
|
||||
$maxsizes->dragimage->height = QTYPE_ddmarker_DRAGIMAGE_MAXHEIGHT;
|
||||
|
||||
$params = array('maxsizes' => $maxsizes,
|
||||
'topnode' => 'fieldset#previewareaheader');
|
||||
|
||||
$PAGE->requires->yui_module('moodle-qtype_ddmarker-form',
|
||||
'M.qtype_ddmarker.init_form',
|
||||
array($params));
|
||||
return $question;
|
||||
}
|
||||
|
||||
|
||||
public static function file_uploaded($draftitemid) {
|
||||
$draftareafiles = file_get_drafarea_files($draftitemid);
|
||||
do {
|
||||
$draftareafile = array_shift($draftareafiles->list);
|
||||
} while ($draftareafile !== null && $draftareafile->filename == '.');
|
||||
if ($draftareafile === null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function validation($data, $files) {
|
||||
$errors = parent::validation($data, $files);
|
||||
if (!self::file_uploaded($data['bgimage'])) {
|
||||
$errors["bgimage"] = get_string('formerror_nobgimage', 'qtype_ddmarker');
|
||||
}
|
||||
|
||||
$allchoices = array();
|
||||
for ($i=0; $i < $data['nodropzone']; $i++) {
|
||||
$ytoppresent = (trim($data['drops'][$i]['ytop']) !== '');
|
||||
$xleftpresent = (trim($data['drops'][$i]['ytop']) !== '');
|
||||
$labelpresent = (trim($data['drops'][$i]['droplabel']) !== '');
|
||||
$choice = $data['drops'][$i]['choice'];
|
||||
$imagechoicepresent = ($choice !== '0');
|
||||
|
||||
if ($imagechoicepresent) {
|
||||
if (!$ytoppresent) {
|
||||
$errors["drops[$i]"] =
|
||||
get_string('formerror_noytop', 'qtype_ddmarker');
|
||||
}
|
||||
if (!$xleftpresent) {
|
||||
$errors["drops[$i]"] =
|
||||
get_string('formerror_noxleft', 'qtype_ddmarker');
|
||||
}
|
||||
|
||||
if ($data['dragitemtype'][$choice - 1] != 'word' &&
|
||||
!self::file_uploaded($data['dragitem'][$choice - 1])) {
|
||||
$errors['dragitem['.($choice - 1).']'] =
|
||||
get_string('formerror_nofile', 'qtype_ddmarker', $i);
|
||||
}
|
||||
|
||||
if (isset($allchoices[$choice]) && !$data['drags'][$choice-1]['infinite']) {
|
||||
$errors["drops[$i]"] =
|
||||
get_string('formerror_multipledraginstance', 'qtype_ddmarker', $choice);
|
||||
$errors['drops['.($allchoices[$choice]).']'] =
|
||||
get_string('formerror_multipledraginstance', 'qtype_ddmarker', $choice);
|
||||
$errors['drags['.($choice-1).']'] =
|
||||
get_string('formerror_multipledraginstance2', 'qtype_ddmarker', $choice);
|
||||
}
|
||||
$allchoices[$choice] = $i;
|
||||
} else {
|
||||
if ($ytoppresent || $xleftpresent || $labelpresent) {
|
||||
$errors["drops[$i]"] =
|
||||
get_string('formerror_noimageselected', 'qtype_ddmarker');
|
||||
}
|
||||
}
|
||||
}
|
||||
for ($dragindex=0; $dragindex < $data['noitems']; $dragindex++) {
|
||||
$label = $data['drags'][$dragindex]['draglabel'];
|
||||
if ($data['dragitemtype'][$dragindex] == 'word') {
|
||||
$allowedtags = '<br><sub><sup><b><i><strong><em>';
|
||||
$errormessage = get_string('formerror_disallowedtags', 'qtype_ddmarker');
|
||||
} else {
|
||||
$allowedtags = '';
|
||||
$errormessage = get_string('formerror_noallowedtags', 'qtype_ddmarker');
|
||||
}
|
||||
if ($label != strip_tags($label, $allowedtags)) {
|
||||
$errors["drags[{$dragindex}]"] = $errormessage;
|
||||
}
|
||||
|
||||
}
|
||||
return $errors;
|
||||
}
|
||||
|
||||
class qtype_ddmarker_edit_form extends qtype_ddtoimage_edit_form_base {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ $string['addmoreimages'] = 'Blanks for {no} More Draggable Items';
|
||||
$string['answer'] = 'Answer';
|
||||
$string['bgimage'] = 'Background Image';
|
||||
$string['correctansweris'] = 'The correct answer is: {$a}';
|
||||
$string['ddmarker'] = 'Drag and drop: images or text onto image';
|
||||
$string['ddmarker'] = 'Drag and drop: markers onto image';
|
||||
$string['ddmarker_help'] = 'Select a background image file, select draggable images or enter text and define the drop zones on the background image to which they must be dragged.';
|
||||
$string['ddmarkersummary'] = 'Images or text labels are dragged and dropped into drop zones on a background image.';
|
||||
$string['draggableimage'] = 'Draggable image';
|
||||
@@ -58,9 +58,7 @@ $string['previewareaheader'] = 'Preview';
|
||||
$string['previewareamessage'] = 'Select a background image file and select draggable images or just enter text that will be made draggable. Then choose a drag item for each \'drop zone\', and drag the drag item to where the student should drag it to.';
|
||||
$string['refresh'] = 'Refresh Preview';
|
||||
$string['shuffleimages'] = 'Shuffle Drag Items Each Time Question Is Attempted';
|
||||
$string['summarisechoice'] = '{$a->no}. {$a->text}';
|
||||
$string['summariseplace'] = '{$a->no}. {$a->text}';
|
||||
$string['summarisechoiceno'] = 'Item {$a}';
|
||||
$string['summariseplaceno'] = 'Drop zone {$a}';
|
||||
$string['xleft'] = 'Left';
|
||||
$string['ytop'] = 'Top';
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/question/type/gapselect/questionbase.php');
|
||||
require_once($CFG->dirroot . '/question/type/ddimageortext/questionbase.php');
|
||||
|
||||
|
||||
/**
|
||||
@@ -35,133 +35,13 @@ require_once($CFG->dirroot . '/question/type/gapselect/questionbase.php');
|
||||
* @copyright 2009 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class qtype_ddmarker_question extends qtype_gapselect_question_base {
|
||||
public function clear_wrong_from_response(array $response) {
|
||||
foreach ($this->places as $place => $notused) {
|
||||
if (array_key_exists($this->field($place), $response) &&
|
||||
$response[$this->field($place)] != $this->get_right_choice_for($place)) {
|
||||
$response[$this->field($place)] = '';
|
||||
}
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
class qtype_ddmarker_question extends qtype_ddtoimage_question_base {
|
||||
|
||||
public function get_right_choice_for($placeno) {
|
||||
$place = $this->places[$placeno];
|
||||
foreach ($this->choiceorder[$place->group] as $choicekey => $choiceid) {
|
||||
if ($this->rightchoices[$placeno] == $choiceid) {
|
||||
return $choicekey;
|
||||
}
|
||||
}
|
||||
}
|
||||
public function summarise_response(array $response) {
|
||||
$allblank = true;
|
||||
foreach ($this->places as $placeno => $place) {
|
||||
$summariseplace = $place->summarise();
|
||||
if (array_key_exists($this->field($placeno), $response) &&
|
||||
$response[$this->field($placeno)]) {
|
||||
$selected = $this->get_selected_choice($place->group,
|
||||
$response[$this->field($placeno)]);
|
||||
$summarisechoice = $selected->summarise();
|
||||
$allblank = false;
|
||||
} else {
|
||||
$summarisechoice = '';
|
||||
}
|
||||
$choices[] = "$summariseplace -> {{$summarisechoice}}";
|
||||
}
|
||||
if ($allblank) {
|
||||
return null;
|
||||
}
|
||||
return implode(' ', $choices);
|
||||
}
|
||||
|
||||
public function check_file_access($qa, $options, $component, $filearea, $args, $forcedownload) {
|
||||
if ($filearea == 'bgimage' || $filearea == 'dragimage') {
|
||||
$validfilearea = true;
|
||||
} else {
|
||||
$validfilearea = false;
|
||||
}
|
||||
if ($component == 'qtype_ddmarker' && $validfilearea) {
|
||||
$question = $qa->get_question();
|
||||
$itemid = reset($args);
|
||||
if ($filearea == 'bgimage') {
|
||||
return $itemid == $question->id;
|
||||
} else if ($filearea == 'dragimage') {
|
||||
foreach ($question->choices as $group) {
|
||||
foreach ($group as $drag) {
|
||||
if ($drag->id == $itemid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return parent::check_file_access($qa, $options, $component,
|
||||
$filearea, $args, $forcedownload);
|
||||
}
|
||||
}
|
||||
public function get_validation_error(array $response) {
|
||||
if ($this->is_complete_response($response)) {
|
||||
return '';
|
||||
}
|
||||
return get_string('pleasedraganimagetoeachdropregion', 'qtype_ddmarker');
|
||||
}
|
||||
|
||||
public function classify_response(array $response) {
|
||||
$parts = array();
|
||||
foreach ($this->places as $placeno => $place) {
|
||||
$group = $place->group;
|
||||
if (!array_key_exists($this->field($placeno), $response) ||
|
||||
!$response[$this->field($placeno)]) {
|
||||
$parts[$placeno] = question_classified_response::no_response();
|
||||
continue;
|
||||
}
|
||||
|
||||
$fieldname = $this->field($placeno);
|
||||
$choiceno = $this->choiceorder[$group][$response[$fieldname]];
|
||||
$choice = $this->choices[$group][$choiceno];
|
||||
|
||||
$correct = $this->get_right_choice_for($placeno) == $response[$fieldname];
|
||||
$parts[$placeno] = new question_classified_response(
|
||||
$choiceno, $choice->summarise(), $correct?1:0);
|
||||
}
|
||||
return $parts;
|
||||
}
|
||||
|
||||
public function get_random_guess_score() {
|
||||
$accum = 0;
|
||||
|
||||
foreach ($this->places as $place) {
|
||||
$accum += 1 / count($this->choices[$place->group]);
|
||||
}
|
||||
|
||||
return $accum / count($this->places);
|
||||
}
|
||||
|
||||
|
||||
public function get_question_summary() {
|
||||
$summary = '';
|
||||
if (!html_is_blank($this->questiontext)) {
|
||||
$question = $this->html_to_text($this->questiontext, $this->questiontextformat);
|
||||
$summary .= $question . '; ';
|
||||
}
|
||||
$places = array();
|
||||
foreach ($this->places as $place) {
|
||||
$cs = array();
|
||||
foreach ($this->choices[$place->group] as $choice) {
|
||||
$cs[] = $choice->summarise();
|
||||
}
|
||||
$places[] = '[[' . $place->summarise() . ']] -> {' . implode(' / ', $cs) . '}';
|
||||
}
|
||||
$summary .= implode('; ', $places);
|
||||
return $summary;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents one of the choices (draggable images).
|
||||
* Represents one of the choices (draggable markers).
|
||||
*
|
||||
* @copyright 2009 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
@@ -170,26 +50,18 @@ class qtype_ddmarker_drag_item {
|
||||
public $id;
|
||||
public $text;
|
||||
public $no;
|
||||
public $group;
|
||||
public $isinfinite;
|
||||
|
||||
public function __construct($alttextlabel, $no, $group = 1, $isinfinite = false, $id = 0) {
|
||||
public function __construct($label, $no, $id = 0) {
|
||||
$this->id = $id;
|
||||
$this->text = $alttextlabel;
|
||||
$this->text = $label;
|
||||
$this->no = $no;
|
||||
$this->group = $group;
|
||||
$this->isinfinite = $isinfinite;
|
||||
}
|
||||
public function choice_group() {
|
||||
return $this->group;
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function summarise() {
|
||||
if (trim($this->text) != '') {
|
||||
return get_string('summarisechoice', 'qtype_ddmarker', $this);
|
||||
} else {
|
||||
return get_string('summarisechoiceno', 'qtype_ddmarker', $this->no);
|
||||
}
|
||||
return $this->text;
|
||||
}
|
||||
}
|
||||
/**
|
||||
@@ -201,14 +73,14 @@ class qtype_ddmarker_drag_item {
|
||||
class qtype_ddmarker_drop_zone {
|
||||
public $no;
|
||||
public $text;
|
||||
public $group;
|
||||
public $xy;
|
||||
public $shape;
|
||||
public $coords;
|
||||
|
||||
public function __construct($alttextlabel, $no, $group = 1, $x = '', $y = '') {
|
||||
public function __construct($label, $no, $shape, $coords) {
|
||||
$this->no = $no;
|
||||
$this->text = $alttextlabel;
|
||||
$this->group = $group;
|
||||
$this->xy = array($x, $y);
|
||||
$this->text = $label;
|
||||
$this->shape = $shape;
|
||||
$this->coords = $coords;
|
||||
}
|
||||
|
||||
public function summarise() {
|
||||
|
||||
@@ -26,15 +26,10 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
require_once($CFG->dirroot . '/question/engine/lib.php');
|
||||
require_once($CFG->dirroot . '/question/format/xml/format.php');
|
||||
require_once($CFG->dirroot . '/question/type/gapselect/questiontypebase.php');
|
||||
require_once($CFG->dirroot . '/question/type/ddimageortext/questiontypebase.php');
|
||||
|
||||
define('QTYPE_ddmarker_BGIMAGE_MAXWIDTH', 600);
|
||||
define('QTYPE_ddmarker_BGIMAGE_MAXHEIGHT', 400);
|
||||
define('QTYPE_ddmarker_DRAGIMAGE_MAXWIDTH', 150);
|
||||
define('QTYPE_ddmarker_DRAGIMAGE_MAXHEIGHT', 100);
|
||||
|
||||
/**
|
||||
* The drag-and-drop words into sentences question type class.
|
||||
@@ -42,423 +37,10 @@ define('QTYPE_ddmarker_DRAGIMAGE_MAXHEIGHT', 100);
|
||||
* @copyright 2009 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class qtype_ddmarker extends question_type {
|
||||
protected function choice_group_key() {
|
||||
return 'draggroup';
|
||||
}
|
||||
class qtype_ddmarker extends qtype_ddtoimage_base {
|
||||
|
||||
public function requires_qtypes() {
|
||||
return array('gapselect');
|
||||
}
|
||||
|
||||
public function get_question_options($question) {
|
||||
global $DB;
|
||||
$question->options = $DB->get_record('qtype_ddmarker',
|
||||
array('questionid' => $question->id), '*', MUST_EXIST);
|
||||
$question->options->drags = $DB->get_records('qtype_ddmarker_drags',
|
||||
array('questionid' => $question->id), 'no ASC', '*');
|
||||
$question->options->drops = $DB->get_records('qtype_ddmarker_drops',
|
||||
array('questionid' => $question->id), 'no ASC', '*');
|
||||
parent::get_question_options($question);
|
||||
}
|
||||
|
||||
protected function make_choice($dragdata) {
|
||||
return new qtype_ddmarker_drag_item($dragdata->label, $dragdata->no,
|
||||
$dragdata->draggroup, $dragdata->infinite, $dragdata->id);
|
||||
}
|
||||
|
||||
protected function make_place($dropzonedata) {
|
||||
return new qtype_ddmarker_drop_zone($dropzonedata->label, $dropzonedata->no,
|
||||
$dropzonedata->group,
|
||||
$dropzonedata->xleft, $dropzonedata->ytop);
|
||||
}
|
||||
|
||||
protected function make_hint($hint) {
|
||||
return question_hint_with_parts::load_from_record($hint);
|
||||
}
|
||||
|
||||
protected function initialise_question_instance(question_definition $question, $questiondata) {
|
||||
parent::initialise_question_instance($question, $questiondata);
|
||||
$question->shufflechoices = $questiondata->options->shuffleanswers;
|
||||
|
||||
$this->initialise_combined_feedback($question, $questiondata, true);
|
||||
|
||||
$question->choices = array();
|
||||
$choiceindexmap= array();
|
||||
|
||||
// Store the choices in arrays by group.
|
||||
foreach ($questiondata->options->drags as $dragdata) {
|
||||
|
||||
$choice = $this->make_choice($dragdata);
|
||||
|
||||
if (array_key_exists($choice->choice_group(), $question->choices)) {
|
||||
$question->choices[$choice->choice_group()][$dragdata->no] = $choice;
|
||||
} else {
|
||||
$question->choices[$choice->choice_group()][1] = $choice;
|
||||
}
|
||||
|
||||
end($question->choices[$choice->choice_group()]);
|
||||
$choiceindexmap[$dragdata->no] = array($choice->choice_group(),
|
||||
key($question->choices[$choice->choice_group()]));
|
||||
}
|
||||
|
||||
$question->places = array();
|
||||
$question->rightchoices = array();
|
||||
|
||||
$i = 1;
|
||||
|
||||
foreach ($questiondata->options->drops as $dropdata) {
|
||||
list($group, $choiceindex) = $choiceindexmap[$dropdata->choice];
|
||||
$dropdata->group = $group;
|
||||
$question->places[$dropdata->no] = $this->make_place($dropdata);
|
||||
$question->rightchoices[$dropdata->no] = $choiceindex;
|
||||
}
|
||||
}
|
||||
|
||||
public function save_question_options($formdata) {
|
||||
global $DB, $USER;
|
||||
$context = $formdata->context;
|
||||
|
||||
$options = $DB->get_record('qtype_ddmarker', array('questionid' => $formdata->id));
|
||||
if (!$options) {
|
||||
$options = new stdClass();
|
||||
$options->questionid = $formdata->id;
|
||||
$options->correctfeedback = '';
|
||||
$options->partiallycorrectfeedback = '';
|
||||
$options->incorrectfeedback = '';
|
||||
$options->id = $DB->insert_record('qtype_ddmarker', $options);
|
||||
}
|
||||
|
||||
$options->shuffleanswers = !empty($formdata->shuffleanswers);
|
||||
$options = $this->save_combined_feedback_helper($options, $formdata, $context, true);
|
||||
$this->save_hints($formdata, true);
|
||||
$DB->update_record('qtype_ddmarker', $options);
|
||||
$DB->delete_records('qtype_ddmarker_drops', array('questionid' => $formdata->id));
|
||||
foreach (array_keys($formdata->drops) as $dropno) {
|
||||
if ($formdata->drops[$dropno]['choice'] == 0) {
|
||||
continue;
|
||||
}
|
||||
$drop = new stdClass();
|
||||
$drop->questionid = $formdata->id;
|
||||
$drop->no = $dropno + 1;
|
||||
$drop->xleft = $formdata->drops[$dropno]['xleft'];
|
||||
$drop->ytop = $formdata->drops[$dropno]['ytop'];
|
||||
$drop->choice = $formdata->drops[$dropno]['choice'];
|
||||
$drop->label = $formdata->drops[$dropno]['droplabel'];
|
||||
|
||||
$DB->insert_record('qtype_ddmarker_drops', $drop);
|
||||
}
|
||||
|
||||
//an array of drag no -> drag id
|
||||
$olddragids = $DB->get_records_menu('qtype_ddmarker_drags',
|
||||
array('questionid' => $formdata->id),
|
||||
'', 'no, id');
|
||||
foreach (array_keys($formdata->drags) as $dragno) {
|
||||
$info = file_get_draft_area_info($formdata->dragitem[$dragno]);
|
||||
if ($info['filecount'] > 0 || !empty($formdata->drags[$dragno]['draglabel'])) {
|
||||
$draftitemid = $formdata->dragitem[$dragno];
|
||||
|
||||
$drag = new stdClass();
|
||||
$drag->questionid = $formdata->id;
|
||||
$drag->no = $dragno + 1;
|
||||
$drag->draggroup = $formdata->drags[$dragno]['draggroup'];
|
||||
$drag->infinite = empty($formdata->drags[$dragno]['infinite'])? 0 : 1;
|
||||
$drag->label = $formdata->drags[$dragno]['draglabel'];
|
||||
|
||||
if (isset($olddragids[$dragno +1])) {
|
||||
$drag->id = $olddragids[$dragno +1];
|
||||
unset($olddragids[$dragno +1]);
|
||||
$DB->update_record('qtype_ddmarker_drags', $drag);
|
||||
} else {
|
||||
$drag->id = $DB->insert_record('qtype_ddmarker_drags', $drag);
|
||||
}
|
||||
|
||||
if ($formdata->dragitemtype[$dragno] == 'image') {
|
||||
self::constrain_image_size_in_draft_area($draftitemid,
|
||||
QTYPE_ddmarker_DRAGIMAGE_MAXWIDTH,
|
||||
QTYPE_ddmarker_DRAGIMAGE_MAXHEIGHT);
|
||||
file_save_draft_area_files($draftitemid, $formdata->context->id,
|
||||
'qtype_ddmarker', 'dragimage', $drag->id,
|
||||
array('subdirs' => 0, 'maxbytes' => 0, 'maxfiles' => 1));
|
||||
} else {
|
||||
//delete any existing files for draggable text item type
|
||||
$fs = get_file_storage();
|
||||
$fs->delete_area_files($formdata->context->id, 'qtype_ddmarker',
|
||||
'dragimage', $drag->id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if (!empty($olddragids)) {
|
||||
list($sql, $params) = $DB->get_in_or_equal(array_values($olddragids));
|
||||
$DB->delete_records_select('qtype_ddmarker_drags', "id $sql", $params);
|
||||
}
|
||||
|
||||
self::constrain_image_size_in_draft_area($formdata->bgimage,
|
||||
QTYPE_ddmarker_BGIMAGE_MAXWIDTH,
|
||||
QTYPE_ddmarker_BGIMAGE_MAXHEIGHT);
|
||||
file_save_draft_area_files($formdata->bgimage, $formdata->context->id,
|
||||
'qtype_ddmarker', 'bgimage', $formdata->id,
|
||||
array('subdirs' => 0, 'maxbytes' => 0, 'maxfiles' => 1));
|
||||
}
|
||||
|
||||
|
||||
public static function constrain_image_size_in_draft_area($draftitemid, $maxwidth, $maxheight) {
|
||||
global $USER;
|
||||
$usercontext = get_context_instance(CONTEXT_USER, $USER->id);
|
||||
$fs = get_file_storage();
|
||||
$draftfiles = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'id');
|
||||
if ($draftfiles) {
|
||||
foreach ($draftfiles as $file) {
|
||||
if ($file->is_directory()) {
|
||||
continue;
|
||||
}
|
||||
$imageinfo = $file->get_imageinfo();
|
||||
$width = $imageinfo['width'];
|
||||
$height = $imageinfo['height'];
|
||||
$mimetype = $imageinfo['mimetype'];
|
||||
switch ($mimetype) {
|
||||
case 'image/jpeg' :
|
||||
$quality = 80;
|
||||
break;
|
||||
case 'image/png' :
|
||||
$quality = 8;
|
||||
break;
|
||||
default :
|
||||
$quality = null;
|
||||
}
|
||||
$newwidth = min($maxwidth, $width);
|
||||
$newheight = min($maxheight, $height);
|
||||
if ($newwidth != $width || $newheight != $height) {
|
||||
$newimagefilename = $file->get_filename();
|
||||
$newimagefilename =
|
||||
preg_replace('!\.!', "_{$newwidth}x{$newheight}.", $newimagefilename, 1);
|
||||
$newrecord = new stdClass();
|
||||
$newrecord->contextid = $usercontext->id;
|
||||
$newrecord->component = 'user';
|
||||
$newrecord->filearea = 'draft';
|
||||
$newrecord->itemid = $draftitemid;
|
||||
$newrecord->filepath = '/';
|
||||
$newrecord->filename = $newimagefilename;
|
||||
$fs->convert_image($newrecord, $file, $newwidth, $newheight, true, $quality);
|
||||
$file->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public function move_files($questionid, $oldcontextid, $newcontextid) {
|
||||
global $DB;
|
||||
$fs = get_file_storage();
|
||||
|
||||
parent::move_files($questionid, $oldcontextid, $newcontextid);
|
||||
$fs->move_area_files_to_new_context($oldcontextid,
|
||||
$newcontextid, 'qtype_ddmarker', 'bgimage', $questionid);
|
||||
$dragids = $DB->get_records_menu('qtype_ddmarker_drags',
|
||||
array('questionid' => $questionid), 'id', 'id,1');
|
||||
foreach ($dragids as $dragid => $notused) {
|
||||
$fs->move_area_files_to_new_context($oldcontextid,
|
||||
$newcontextid, 'qtype_ddmarker', 'dragimage', $dragid);
|
||||
}
|
||||
|
||||
$this->move_files_in_combined_feedback($questionid, $oldcontextid, $newcontextid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all the files belonging to this question.
|
||||
* @param int $questionid the question being deleted.
|
||||
* @param int $contextid the context the question is in.
|
||||
*/
|
||||
|
||||
protected function delete_files($questionid, $contextid) {
|
||||
global $DB;
|
||||
$fs = get_file_storage();
|
||||
|
||||
parent::delete_files($questionid, $contextid);
|
||||
|
||||
$dragids = $DB->get_records_menu('qtype_ddmarker_drags',
|
||||
array('questionid' => $questionid), 'id', 'id,1');
|
||||
foreach ($dragids as $dragid => $notused) {
|
||||
$fs->delete_area_files($contextid, 'qtype_ddmarker', 'dragimage', $dragid);
|
||||
}
|
||||
|
||||
$this->delete_files_in_combined_feedback($questionid, $contextid);
|
||||
}
|
||||
|
||||
public function export_to_xml($question, $format, $extra = null) {
|
||||
$fs = get_file_storage();
|
||||
$contextid = $question->contextid;
|
||||
$output = '';
|
||||
|
||||
if ($question->options->shuffleanswers) {
|
||||
$output .= " <shuffleanswers/>\n";
|
||||
}
|
||||
$output .= $format->write_combined_feedback($question->options);
|
||||
$output .= $format->write_hints($question);
|
||||
$files = $fs->get_area_files($contextid, 'qtype_ddmarker', 'bgimage', $question->id);
|
||||
$output .= " ".$this->write_files($files, 2)."\n";;
|
||||
|
||||
foreach ($question->options->drags as $drag) {
|
||||
$files =
|
||||
$fs->get_area_files($contextid, 'qtype_ddmarker', 'dragimage', $drag->id);
|
||||
$output .= " <drag>\n";
|
||||
$output .= " <no>{$drag->no}</no>\n";
|
||||
$output .= $format->writetext($drag->label, 3)."\n";
|
||||
$output .= " <draggroup>{$drag->draggroup}</draggroup>\n";
|
||||
if ($drag->infinite) {
|
||||
$output .= " <infinite/>\n";
|
||||
}
|
||||
$output .= $this->write_files($files, 3);
|
||||
$output .= " </drag>\n";
|
||||
}
|
||||
foreach ($question->options->drops as $drop) {
|
||||
$output .= " <drop>\n";
|
||||
$output .= $format->writetext($drop->label, 3);
|
||||
$output .= " <no>{$drop->no}</no>\n";
|
||||
$output .= " <choice>{$drop->choice}</choice>\n";
|
||||
$output .= " <xleft>{$drop->xleft}</xleft>\n";
|
||||
$output .= " <ytop>{$drop->ytop}</ytop>\n";
|
||||
$output .= " </drop>\n";
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function import_from_xml($data, $question, $format, $extra=null) {
|
||||
if (!isset($data['@']['type']) || $data['@']['type'] != 'ddmarker') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$question = $format->import_headers($data);
|
||||
$question->qtype = 'ddmarker';
|
||||
|
||||
$question->shuffleanswers = array_key_exists('shuffleanswers',
|
||||
$format->getpath($data, array('#'), array()));
|
||||
|
||||
$filexml = $format->getpath($data, array('#', 'file'), array());
|
||||
$question->bgimage = $this->import_files_to_draft_file_area($format, $filexml);
|
||||
$drags = $data['#']['drag'];
|
||||
$question->drags = array();
|
||||
|
||||
foreach ($drags as $dragxml) {
|
||||
$dragno = $format->getpath($dragxml, array('#', 'no', 0, '#'), 0);
|
||||
$dragindex = $dragno -1;
|
||||
$question->drags[$dragindex] = array();
|
||||
$question->drags[$dragindex]['draglabel'] =
|
||||
$format->getpath($dragxml, array('#', 'text', 0, '#'), '', true);
|
||||
$question->drags[$dragindex]['infinite'] = array_key_exists('infinite', $dragxml['#']);
|
||||
$question->drags[$dragindex]['draggroup'] =
|
||||
$format->getpath($dragxml, array('#', 'draggroup', 0, '#'), 1);
|
||||
$filexml = $format->getpath($dragxml, array('#', 'file'), array());
|
||||
$question->dragitem[$dragindex] =
|
||||
$this->import_files_to_draft_file_area($format, $filexml);
|
||||
if (count($filexml)) {
|
||||
$question->dragitemtype[$dragindex] = 'image';
|
||||
} else {
|
||||
$question->dragitemtype[$dragindex] = 'word';
|
||||
}
|
||||
}
|
||||
|
||||
$drops = $data['#']['drop'];
|
||||
$question->drops = array();
|
||||
foreach ($drops as $dropxml) {
|
||||
$dropno = $format->getpath($dropxml, array('#', 'no', 0, '#'), 0);
|
||||
$dropindex = $dropno -1;
|
||||
$question->drops[$dropindex] = array();
|
||||
$question->drops[$dropindex]['choice'] =
|
||||
$format->getpath($dropxml, array('#', 'choice', 0, '#'), 0);
|
||||
$question->drops[$dropindex]['droplabel'] =
|
||||
$format->getpath($dropxml, array('#', 'text', 0, '#'), '', true);
|
||||
$question->drops[$dropindex]['xleft'] =
|
||||
$format->getpath($dropxml, array('#', 'xleft', 0, '#'), '');
|
||||
$question->drops[$dropindex]['ytop'] =
|
||||
$format->getpath($dropxml, array('#', 'ytop', 0, '#'), '');
|
||||
}
|
||||
|
||||
$format->import_combined_feedback($question, $data, true);
|
||||
$format->import_hints($question, $data, true);
|
||||
|
||||
return $question;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a draft files area, import files into it and return the draft item id.
|
||||
* @param qformat_xml $format
|
||||
* @param array $xml an array of <file> nodes from the the parsed XML.
|
||||
* @return integer draftitemid
|
||||
*/
|
||||
public function import_files_to_draft_file_area($format, $xml) {
|
||||
global $USER;
|
||||
$fs = get_file_storage();
|
||||
$files = $format->import_files($xml);
|
||||
$usercontext = get_context_instance(CONTEXT_USER, $USER->id);
|
||||
$draftitemid = file_get_unused_draft_itemid();
|
||||
foreach ($files as $file) {
|
||||
$record = new stdClass();
|
||||
$record->contextid = $usercontext->id;
|
||||
$record->component = 'user';
|
||||
$record->filearea = 'draft';
|
||||
$record->itemid = $draftitemid;
|
||||
$record->filename = $file->name;
|
||||
$record->filepath = '/';
|
||||
$fs->create_file_from_string($record, $this->decode_file($file));
|
||||
}
|
||||
return $draftitemid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert files into text output in the given format.
|
||||
* This method is copied from qformat_default as a quick fix, as the method there is
|
||||
* protected.
|
||||
* @param array
|
||||
* @param string encoding method
|
||||
* @return string $string
|
||||
*/
|
||||
public function write_files($files, $indent) {
|
||||
if (empty($files)) {
|
||||
return '';
|
||||
}
|
||||
$string = '';
|
||||
foreach ($files as $file) {
|
||||
if ($file->is_directory()) {
|
||||
continue;
|
||||
}
|
||||
$string .= str_repeat(' ', $indent);
|
||||
$string .= '<file name="' . $file->get_filename() . '" encoding="base64">';
|
||||
$string .= base64_encode($file->get_content());
|
||||
$string .= "</file>\n";
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
public function get_possible_responses($questiondata) {
|
||||
$question = $this->make_question($questiondata);
|
||||
|
||||
$parts = array();
|
||||
foreach ($question->places as $placeno => $place) {
|
||||
$group = $place->group;
|
||||
$choices = array();
|
||||
|
||||
foreach ($question->choices[$group] as $i => $choice) {
|
||||
$summarisechoice = $choice->summarise();
|
||||
|
||||
$correct = $question->rightchoices[$placeno] == $i;
|
||||
$choices[$choice->no] = new question_possible_response(
|
||||
$summarisechoice,
|
||||
$correct?1:0);
|
||||
}
|
||||
$choices[null] = question_possible_response::no_response();
|
||||
|
||||
$parts[$placeno] = $choices;
|
||||
}
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
public function get_random_guess_score($questiondata) {
|
||||
$question = $this->make_question($questiondata);
|
||||
return $question->get_random_guess_score();
|
||||
return array_merge(parent::requires_qtypes(), array('ddimageortext'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/question/type/gapselect/rendererbase.php');
|
||||
require_once($CFG->dirroot . '/question/type/ddimageortext/rendererbase.php');
|
||||
|
||||
|
||||
/**
|
||||
@@ -35,146 +35,6 @@ require_once($CFG->dirroot . '/question/type/gapselect/rendererbase.php');
|
||||
* @copyright 2010 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class qtype_ddmarker_renderer extends qtype_with_combined_feedback_renderer {
|
||||
class qtype_ddmarker_renderer extends qtype_ddtoimage_renderer_base {
|
||||
|
||||
public function head_code(question_attempt $qa) {
|
||||
return parent::head_code($qa);
|
||||
}
|
||||
public function clear_wrong(question_attempt $qa) {
|
||||
$question = $qa->get_question();
|
||||
$response = $qa->get_last_qt_data();
|
||||
|
||||
if (!empty($response)) {
|
||||
$cleanresponse = $question->clear_wrong_from_response($response);
|
||||
} else {
|
||||
$cleanresponse = $response;
|
||||
}
|
||||
$cleanresponsehtml = '';
|
||||
foreach ($cleanresponse as $fieldname => $value) {
|
||||
list (, $html) = $this->hidden_field_for_qt_var($qa, $fieldname, $value);
|
||||
$cleanresponsehtml .= $html;
|
||||
}
|
||||
return $cleanresponsehtml;
|
||||
}
|
||||
|
||||
public function formulation_and_controls(question_attempt $qa,
|
||||
question_display_options $options) {
|
||||
global $PAGE;
|
||||
|
||||
$question = $qa->get_question();
|
||||
$response = $qa->get_last_qt_data();
|
||||
|
||||
$questiontext = $question->format_questiontext($qa);
|
||||
|
||||
$output = html_writer::tag('div', $questiontext, array('class' => 'qtext'));
|
||||
|
||||
$bgimage = self::get_url_for_image($qa, 'bgimage');
|
||||
|
||||
$img = html_writer::empty_tag('img', array('src'=>$bgimage, 'class'=>'dropbackground'));
|
||||
$droparea = html_writer::tag('div', $img, array('class'=>'droparea'));
|
||||
|
||||
$dragimagehomes = '';
|
||||
foreach ($question->choices as $groupno => $group) {
|
||||
$dragimagehomesgroup = '';
|
||||
$orderedgroup = $question->get_ordered_choices($groupno);
|
||||
foreach ($orderedgroup as $choiceno => $dragimage) {
|
||||
$dragimageurl = self::get_url_for_image($qa, 'dragimage', $dragimage->id);
|
||||
$classes = array("group{$groupno}",
|
||||
'draghome',
|
||||
"dragitemhomes{$dragimage->no}",
|
||||
"choice{$choiceno}");
|
||||
if ($dragimage->isinfinite) {
|
||||
$classes[] = 'infinite';
|
||||
}
|
||||
if ($dragimageurl === null) {
|
||||
$classes[] = 'yui3-cssfonts';
|
||||
$dragimagehomesgroup .= html_writer::tag('div',
|
||||
$dragimage->text,
|
||||
array('src'=>$dragimageurl,
|
||||
'class'=>join(' ', $classes)));
|
||||
} else {
|
||||
$dragimagehomesgroup .= html_writer::empty_tag('img',
|
||||
array('src'=>$dragimageurl,
|
||||
'alt' => $dragimage->text,
|
||||
'class'=>join(' ', $classes)));
|
||||
}
|
||||
}
|
||||
$dragimagehomes .= html_writer::tag('div', $dragimagehomesgroup,
|
||||
array('class'=>'dragitemgroup'.$groupno));
|
||||
}
|
||||
|
||||
$dragitemsclass = 'dragitems';
|
||||
if ($options->readonly) {
|
||||
$dragitemsclass .= ' readonly';
|
||||
}
|
||||
$dragitems = html_writer::tag('div', $dragimagehomes, array('class'=> $dragitemsclass));
|
||||
$dropzones = html_writer::empty_tag('div', array('class'=>'dropzones'));
|
||||
$output .= html_writer::tag('div', $droparea.$dragitems.$dropzones,
|
||||
array('class'=>'ddarea'));
|
||||
foreach ($question->places as $placeno => $place) {
|
||||
$varname = $question->field($placeno);
|
||||
list($fieldname, $html) = $this->hidden_field_for_qt_var($qa, $varname);
|
||||
$output .= $html;
|
||||
$question->places[$placeno]->fieldname = $fieldname;
|
||||
}
|
||||
$topnode = 'div#q'.$qa->get_slot().' div.ddarea';
|
||||
$params = array('drops' => $question->places,
|
||||
'topnode' => $topnode,
|
||||
'readonly' => $options->readonly);
|
||||
|
||||
$PAGE->requires->yui_module('moodle-qtype_ddmarker-dd',
|
||||
'M.qtype_ddmarker.init_question',
|
||||
array($params));
|
||||
|
||||
if ($qa->get_state() == question_state::$invalid) {
|
||||
$output .= html_writer::nonempty_tag('div',
|
||||
$question->get_validation_error($qa->get_last_qt_data()),
|
||||
array('class' => 'validationerror'));
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
protected static function get_url_for_image(question_attempt $qa, $filearea, $itemid = 0) {
|
||||
$question = $qa->get_question();
|
||||
$qubaid = $qa->get_usage_id();
|
||||
$slot = $qa->get_slot();
|
||||
$fs = get_file_storage();
|
||||
if ($filearea == 'bgimage') {
|
||||
$itemid = $question->id;
|
||||
}
|
||||
$draftfiles = $fs->get_area_files($question->contextid, 'qtype_ddmarker',
|
||||
$filearea, $itemid, 'id');
|
||||
if ($draftfiles) {
|
||||
foreach ($draftfiles as $file) {
|
||||
if ($file->is_directory()) {
|
||||
continue;
|
||||
}
|
||||
$url = moodle_url::make_pluginfile_url($question->contextid, 'qtype_ddmarker',
|
||||
$filearea, "$qubaid/$slot/{$itemid}", '/',
|
||||
$file->get_filename());
|
||||
return $url->out();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function hidden_field_for_qt_var(question_attempt $qa, $varname, $value = null) {
|
||||
if ($value === null) {
|
||||
$value = $qa->get_last_qt_var($varname);
|
||||
}
|
||||
$fieldname = $qa->get_qt_field_name($varname);
|
||||
$attributes = array('type' => 'hidden',
|
||||
'id' => str_replace(':', '_', $fieldname),
|
||||
'name' => $fieldname,
|
||||
'value' => $value);
|
||||
return array($fieldname, html_writer::empty_tag('input', $attributes)."\n");
|
||||
}
|
||||
|
||||
public function specific_feedback(question_attempt $qa) {
|
||||
return $this->combined_feedback($qa);
|
||||
}
|
||||
|
||||
public function correct_response(question_attempt $qa) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user