diff --git a/question/type/ddmarker/edit_ddmarker_form.php b/question/type/ddmarker/edit_ddmarker_form.php index 7d9ab7963af..ebc9a2b4177 100644 --- a/question/type/ddmarker/edit_ddmarker_form.php +++ b/question/type/ddmarker/edit_ddmarker_form.php @@ -92,22 +92,13 @@ class qtype_ddmarker_edit_form extends qtype_ddtoimage_edit_form_base { return array(); } - protected function shapes() { - return preg_grep('!^qtype_ddmarker_shape_!', get_declared_classes()); - return array('qtype_ddmarker_shape_circle', - 'qtype_ddmarker_shape_rectangle', - 'qtype_ddmarker_shape_polygon'); - } protected function drop_zone($mform, $imagerepeats) { $dropzoneitem = array(); $grouparray = array(); - $shapearray = array(); - foreach ($this->shapes() as $shape) { - $shapearray[$shape::name()] = $shape::human_readable_name(); - } + $shapearray = qtype_ddmarker_shape::shape_options(); $grouparray[] = $mform->createElement('select', 'shape', get_string('marker', 'qtype_ddmarker'), $shapearray); $grouparray[] = $mform->createElement('text', 'coords', @@ -229,18 +220,25 @@ class qtype_ddmarker_edit_form extends qtype_ddtoimage_edit_form_base { if ($choicepresent) { //test coords here if ($bgimagesize !== null) { - if (in_array($data['drops'][$i]['shape'], $this->shapes())) { - + $shape = $data['drops'][$i]['shape']; + $coordsstring = $data['drops'][$i]['coords']; + $shapeobj = qtype_ddmarker_shape::create($shape, $coordsstring); + $interpretererror = $shapeobj->get_coords_interpreter_error(); + if ($interpretererror) { + $errors["drops[{$i}]"] = $interpretererror; + } else if (!$shapeobj->inside_width_height($bgimagesize)) { + $errorcode = 'shapeoutsideboundsofbgimage'; + $errors["drops[{$i}]"] = + get_string('formerror_'.$errorcode, 'qtype_ddmarker'); } } - - } else { if (trim($data['drops'][$i]['coords']) !== '') { - $errors["drops[{$i}]"] - = get_string('formerror_noitemselected', 'qtype_ddmarker'); + $errorcode = 'noitemselected'; + $errors["drops[{$i}]"] = get_string('formerror_'.$errorcode, 'qtype_ddmarker'); } } + } for ($dragindex=0; $dragindex < $data['noitems']; $dragindex++) { $label = $data['drags'][$dragindex]['label']; diff --git a/question/type/ddmarker/lang/en/qtype_ddmarker.php b/question/type/ddmarker/lang/en/qtype_ddmarker.php index 2f14a1cf0df..4e92ba4efdb 100644 --- a/question/type/ddmarker/lang/en/qtype_ddmarker.php +++ b/question/type/ddmarker/lang/en/qtype_ddmarker.php @@ -43,13 +43,20 @@ $string['dropzoneheader'] = 'Drop zones'; $string['editingddmarker'] = 'Editing drag and drop markers'; $string['formerror_nobgimage'] = 'You need to select an image to use as the background for the drag and drop area.'; $string['formerror_noitemselected'] = 'You have specified a drop zone but not chosen a marker that must be dragged to the zone'; +$string['formerror_nosemicolons'] = 'There are no semicolons in your coordinates string. Your coordinates for a {$a->shape} should be expressed as - {$a->coordsstring}.'; $string['formerror_notagsallowed'] = 'No html tags are allowed in the label for a marker'; +$string['formerror_onlyusewholepositivenumbers'] = 'Please use only whole positive numbers to specify x,y coords and/or width and height of shapes. Your coordinates for a {$a->shape} should be expressed as - {$a->coordsstring}.'; +$string['formerror_polygonmusthaveatleastthreepoints'] = 'For a polygon shape you need to specify at least 3 points. Your coordinates for a {$a->shape} should be expressed as - {$a->coordsstring}.'; +$string['formerror_shapeoutsideboundsofbgimage'] = 'The shape you have defined goes out of the bounds of the background image'; +$string['formerror_toomanysemicolons'] = 'There are too many semi colon separated parts to the coordinates you have specified. Your coordinates for a {$a->shape} should be expressed as - {$a->coordsstring}.'; +$string['formerror_unrecognisedwidthheightpart'] = 'We do not recognise the width and height you have specified. Your coordinates for a {$a->shape} should be expressed as - {$a->coordsstring}.'; +$string['formerror_unrecognisedxypart'] = 'We do not recognise the x,y coordinates you have specified. Your coordinates for a {$a->shape} should be expressed as - {$a->coordsstring}.'; $string['infinite'] = 'Infinite'; $string['marker'] = 'Marker'; $string['marker_n'] = 'Marker {no}'; $string['markers'] = 'Markers'; $string['nolabel'] = 'No label text'; -$string['pleasedraganimagetoeachdropregion'] = 'Your answer is not complete, please drag an item to each drop region.'; +$string['pleasedragatleastonemarker'] = 'Your answer is not complete, please drag at least one marker onto the image.'; $string['previewarea'] = 'Preview area -'; $string['previewareaheader'] = 'Preview'; $string['previewareamessage'] = 'Select a background image file, enter text labels for markers and define the drop zones on the background image to which they must be dragged.'; diff --git a/question/type/ddmarker/shapes.php b/question/type/ddmarker/shapes.php index 97c6faf0483..34e6ca025e0 100644 --- a/question/type/ddmarker/shapes.php +++ b/question/type/ddmarker/shapes.php @@ -23,6 +23,9 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ abstract class qtype_ddmarker_shape { + + protected $error = false; + public function __construct($coordsstring) { } @@ -59,6 +62,17 @@ abstract class qtype_ddmarker_shape { return true; } + public function get_coords_interpreter_error() { + if ($this->error) { + $a = new stdClass(); + $a->shape = self::human_readable_name(); + $a->coordsstring = self::human_readable_coords_format(); + return get_string('formerror_'.$this->error, 'qtype_ddmarker', $a); + } else { + return false; + } + } + /** * @param array $xy $xy[0] is x, $xy[1] is y * @return boolean is point inside shape @@ -66,12 +80,37 @@ abstract class qtype_ddmarker_shape { abstract public function is_point_in_shape($xy); public static function name() { - return substr(get_called_class(), 21); + return substr(get_called_class(), strlen(self::$classnameprefix)); } + protected static $classnameprefix = 'qtype_ddmarker_shape_'; + public static function human_readable_name() { return get_string('shape_'.self::name(), 'qtype_ddmarker'); } + + public static function human_readable_coords_format() { + return get_string('shape_'.self::name().'_coords', 'qtype_ddmarker'); + } + + + public static function shape_options() { + $grepexpression = '!^'.preg_quote(self::$classnameprefix, '!').'!'; + $shapes = preg_grep($grepexpression, get_declared_classes()); + $shapearray = array(); + foreach ($shapes as $shape) { + $shapearray[$shape::name()] = $shape::human_readable_name(); + } + asort($shapearray); + return $shapearray; + } + public static function exists($shape) { + return class_exists((self::$classnameprefix).$shape); + } + public static function create($shape, $coordsstring) { + $classname = (self::$classnameprefix).$shape; + return new $classname($coordsstring); + } } class qtype_ddmarker_shape_rectangle extends qtype_ddmarker_shape { protected $width; @@ -81,14 +120,14 @@ class qtype_ddmarker_shape_rectangle extends qtype_ddmarker_shape { public function __construct($coordsstring) { $coordstring = preg_replace('!^\s*!', '', $coordsstring); $coordstring = preg_replace('!\s*$!', '', $coordsstring); - $coordsstringparts = preg_split('!\s*!', $coordsstring); + $coordsstringparts = preg_split('!;!', $coordsstring); if (count($coordsstringparts) > 2) { - $this->error = 'rectangletoomanyspaces'; + $this->error = 'toomanysemicolons'; } else if (count($coordsstringparts) < 2) { - $this->error = 'rectanglenospaces'; + $this->error = 'nosemicolons'; } else { $xy = explode(',', $coordsstringparts[0]); - $widthheightparts = explode('x', $coordsstringparts[1]); + $widthheightparts = explode(',', $coordsstringparts[1]); if (count($xy) !== 2) { $this->error = 'unrecognisedxypart'; } else if (count($widthheightparts) !== 2) {