diff --git a/question/type/ddmarker/edit_ddmarker_form.php b/question/type/ddmarker/edit_ddmarker_form.php index cb4fdee4d1b..dcb0bb32128 100644 --- a/question/type/ddmarker/edit_ddmarker_form.php +++ b/question/type/ddmarker/edit_ddmarker_form.php @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . +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 = '
'; - $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 { } diff --git a/question/type/ddmarker/lang/en/qtype_ddmarker.php b/question/type/ddmarker/lang/en/qtype_ddmarker.php index 6695efdaac6..666ff349590 100644 --- a/question/type/ddmarker/lang/en/qtype_ddmarker.php +++ b/question/type/ddmarker/lang/en/qtype_ddmarker.php @@ -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'; \ No newline at end of file diff --git a/question/type/ddmarker/question.php b/question/type/ddmarker/question.php index 54ca57b1af1..018815c5ece 100644 --- a/question/type/ddmarker/question.php +++ b/question/type/ddmarker/question.php @@ -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() { diff --git a/question/type/ddmarker/questiontype.php b/question/type/ddmarker/questiontype.php index 106ca0f1b27..034ee131bd8 100644 --- a/question/type/ddmarker/questiontype.php +++ b/question/type/ddmarker/questiontype.php @@ -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 .= " \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 .= " \n"; - $output .= " {$drag->no}\n"; - $output .= $format->writetext($drag->label, 3)."\n"; - $output .= " {$drag->draggroup}\n"; - if ($drag->infinite) { - $output .= " \n"; - } - $output .= $this->write_files($files, 3); - $output .= " \n"; - } - foreach ($question->options->drops as $drop) { - $output .= " \n"; - $output .= $format->writetext($drop->label, 3); - $output .= " {$drop->no}\n"; - $output .= " {$drop->choice}\n"; - $output .= " {$drop->xleft}\n"; - $output .= " {$drop->ytop}\n"; - $output .= " \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 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 .= ''; - $string .= base64_encode($file->get_content()); - $string .= "\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')); } } diff --git a/question/type/ddmarker/renderer.php b/question/type/ddmarker/renderer.php index da83b871c60..f7cf56007f2 100644 --- a/question/type/ddmarker/renderer.php +++ b/question/type/ddmarker/renderer.php @@ -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 ''; - } }