ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.assImagemapQuestionGUI.php
Go to the documentation of this file.
1 <?php
2 
19 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
20 
21 
37 {
38  private $linecolor;
39 
47  public function __construct($id = -1)
48  {
50  $this->object = new assImagemapQuestion();
51  if ($id >= 0) {
52  $this->object->loadFromDb($id);
53  }
54  $this->linecolor = '#' . (new ilSetting('assessment'))->get('imap_line_color') ?? 'FF0000';
55  }
56 
57  public function getCommand($cmd)
58  {
59  if (isset($_POST["imagemap"]) ||
60  isset($_POST["imagemap_x"]) ||
61  isset($_POST["imagemap_y"])) {
62  $this->ctrl->setCmd("getCoords");
63  $cmd = "getCoords";
64  }
65 
66  return $cmd;
67  }
68 
69  protected function deleteImage(): void
70  {
71  $this->object->deleteImage();
72  $this->object->saveToDb();
73  $this->tpl->setOnScreenMessage('success', $this->lng->txt('saved_successfully'), true);
74  $this->ctrl->redirect($this, 'editQuestion');
75  }
76 
80  protected function writePostData(bool $always = false): int
81  {
82  $form = $this->buildEditForm();
83  $form->setValuesByPost();
84 
85  if (!$always && !$form->checkInput()) {
86  $this->editQuestion($form);
87  return 1;
88  }
89 
91  $this->writeQuestionSpecificPostData($form);
92  $this->writeAnswerSpecificPostData($form);
93  $this->saveTaxonomyAssignments();
94 
95  return 0;
96  }
97 
98  public function writeAnswerSpecificPostData(ilPropertyFormGUI $form): void
99  {
100  if ($this->ctrl->getCmd() != 'deleteImage') {
101  $this->object->flushAnswers();
102  if (isset($_POST['image']) && is_array($_POST['image']) && is_array($_POST['image']['coords']['name'])) {
103  foreach ($_POST['image']['coords']['name'] as $idx => $name) {
104  if ($this->object->getIsMultipleChoice() && isset($_POST['image']['coords']['points_unchecked'])) {
105  $pointsUnchecked = $_POST['image']['coords']['points_unchecked'][$idx];
106  } else {
107  $pointsUnchecked = 0.0;
108  }
109 
110  $this->object->addAnswer(
111  $name,
112  $_POST['image']['coords']['points'][$idx],
113  $idx,
114  $_POST['image']['coords']['coords'][$idx],
115  $_POST['image']['coords']['shape'][$idx],
116  $pointsUnchecked
117  );
118  }
119  }
120 
121  if (strlen($_FILES['imagemapfile']['tmp_name'])) {
122  if ($this->object->getSelfAssessmentEditingMode() && $this->object->getId() < 1) {
123  $this->object->createNewQuestion();
124  }
125 
126  $this->object->uploadImagemap($form->getItemByPostVar('imagemapfile')->getShapes());
127  }
128  }
129  }
130 
132  {
133  if ($this->ctrl->getCmd() != 'deleteImage') {
134  if (strlen($_FILES['image']['tmp_name']) == 0) {
135  $this->object->setImageFilename($_POST["image_name"]);
136  }
137  }
138  if (strlen($_FILES['image']['tmp_name'])) {
139  if ($this->object->getSelfAssessmentEditingMode() && $this->object->getId() < 1) {
140  $this->object->createNewQuestion();
141  }
142  $this->object->setImageFilename($_FILES['image']['name'], $_FILES['image']['tmp_name']);
143  }
144 
145  $this->object->setIsMultipleChoice($_POST['is_multiple_choice'] == assImagemapQuestion::MODE_MULTIPLE_CHOICE);
146  }
147 
151  protected function buildEditForm(): ilPropertyFormGUI
152  {
153  $form = $this->buildBasicEditFormObject();
154 
155  $this->addBasicQuestionFormProperties($form);
156  $this->populateQuestionSpecificFormPart($form);
157  $this->populateTaxonomyFormSection($form);
158  $this->addQuestionFormCommandButtons($form);
159 
160  return $form;
161  }
162 
166  public function editQuestion(ilPropertyFormGUI $form = null): void
167  {
168  if (null === $form) {
169  $form = $this->buildEditForm();
170  }
171 
172  $this->getQuestionTemplate();
173 
174  $this->tpl->setVariable('QUESTION_DATA', $this->ctrl->getHTML($form));
175  }
176 
178  {
179  return $form; // Nothing to do here since selectable areas are handled in question-specific-form part
180  // due to their immediate dependency to the image. I decide to not break up the interfaces
181  // more just to support this very rare case. tl;dr: See the issue, ignore it.
182  }
183 
185  {
186  $radioGroup = new ilRadioGroupInputGUI($this->lng->txt('tst_imap_qst_mode'), 'is_multiple_choice');
187  $radioGroup->setValue((string) ((int) ($this->object->getIsMultipleChoice())));
188  $modeSingleChoice = new ilRadioOption(
189  $this->lng->txt('tst_imap_qst_mode_sc'),
191  );
192  $modeMultipleChoice = new ilRadioOption(
193  $this->lng->txt('tst_imap_qst_mode_mc'),
195  );
196  $radioGroup->addOption($modeSingleChoice);
197  $radioGroup->addOption($modeMultipleChoice);
198  $form->addItem($radioGroup);
199 
200  $image = new ilImagemapFileInputGUI($this->lng->txt('image'), 'image');
201  $image->setPointsUncheckedFieldEnabled($this->object->getIsMultipleChoice());
202  $image->setRequired(true);
203 
204  if (strlen($this->object->getImageFilename())) {
205  $image->setImage($this->object->getImagePathWeb() . $this->object->getImageFilename());
206  $image->setValue($this->object->getImageFilename());
207  $image->setAreas($this->object->getAnswers());
208  $assessmentSetting = new ilSetting("assessment");
209  $linecolor = (strlen(
210  $assessmentSetting->get("imap_line_color")
211  )) ? "\"#" . $assessmentSetting->get("imap_line_color") . "\"" : "\"#FF0000\"";
212  $image->setLineColor($linecolor);
213  $image->setImagePath($this->object->getImagePath());
214  $image->setImagePathWeb($this->object->getImagePathWeb());
215  }
216  $form->addItem($image);
217 
218  $imagemapfile = new ilHtmlImageMapFileInputGUI($this->lng->txt('add_imagemap'), 'imagemapfile');
219  $imagemapfile->setRequired(false);
220  $form->addItem($imagemapfile);
221  return $form;
222  }
223 
224  public function addRect(): void
225  {
226  $this->areaEditor('rect');
227  }
228 
229  public function addCircle(): void
230  {
231  $this->areaEditor('circle');
232  }
233 
234  public function addPoly(): void
235  {
236  $this->areaEditor('poly');
237  }
238 
242  public function saveShape(): void
243  {
244  $coords = "";
245  switch ($_POST["shape"]) {
247  $coords = join(",", $_POST['image']['mapcoords']);
248  $this->tpl->setOnScreenMessage('success', $this->lng->txt('msg_rect_added'), true);
249  break;
251  if (preg_match("/(\d+)\s*,\s*(\d+)\s+(\d+)\s*,\s*(\d+)/", $_POST['image']['mapcoords'][0] . " " . $_POST['image']['mapcoords'][1], $matches)) {
252  $coords = "$matches[1],$matches[2]," . (int) sqrt((($matches[3] - $matches[1]) * ($matches[3] - $matches[1])) + (($matches[4] - $matches[2]) * ($matches[4] - $matches[2])));
253  }
254  $this->tpl->setOnScreenMessage('success', $this->lng->txt('msg_circle_added'), true);
255  break;
257  $coords = join(",", $_POST['image']['mapcoords']);
258  $this->tpl->setOnScreenMessage('success', $this->lng->txt('msg_poly_added'), true);
259  break;
260  }
261  $this->object->addAnswer($_POST["shapetitle"], 0, count($this->object->getAnswers()), $coords, $_POST["shape"]);
262  $this->object->saveToDb();
263  $this->ctrl->redirect($this, 'editQuestion');
264  }
265 
266  public function areaEditor($shape = ''): void
267  {
268  $shape = (strlen($shape)) ? $shape : $_POST['shape'];
269 
270  $this->getQuestionTemplate();
271 
272  $editorTpl = new ilTemplate('tpl.il_as_qpl_imagemap_question.html', true, true, 'Modules/TestQuestionPool');
273 
274  $coords = array();
275  $mapcoords = $this->request->raw('image');
276  if ($mapcoords != null && isset($mapcoords['mapcoords']) && is_array($mapcoords['mapcoords'])) {
277  foreach ($mapcoords['mapcoords'] as $value) {
278  array_push($coords, $value);
279  }
280  }
281  $cmd = $this->request->raw('cmd');
282  if ($cmd != null && array_key_exists('areaEditor', $cmd) && is_array($cmd['areaEditor']['image'])) {
283  array_push($coords, $cmd['areaEditor']['image'][0] . "," . $cmd['areaEditor']['image'][1]);
284  }
285  foreach ($coords as $value) {
286  $editorTpl->setCurrentBlock("hidden");
287  $editorTpl->setVariable("HIDDEN_NAME", 'image[mapcoords][]');
288  $editorTpl->setVariable("HIDDEN_VALUE", $value);
289  $editorTpl->parseCurrentBlock();
290  }
291 
292  $editorTpl->setCurrentBlock("hidden");
293  $editorTpl->setVariable("HIDDEN_NAME", 'shape');
294  $editorTpl->setVariable("HIDDEN_VALUE", $shape);
295  $editorTpl->parseCurrentBlock();
296 
297  $preview = new ilImagemapPreview($this->object->getImagePath() . $this->object->getImageFilename());
298  foreach ($this->object->answers as $index => $answer) {
299  $preview->addArea($index, $answer->getArea(), $answer->getCoords(), $answer->getAnswertext(), "", "", true, $this->linecolor);
300  }
301  $hidearea = false;
302  $disabled_save = " disabled=\"disabled\"";
303  $c = "";
304  switch ($shape) {
305  case "rect":
306  if (count($coords) == 0) {
307  $this->tpl->setOnScreenMessage('info', $this->lng->txt("rectangle_click_tl_corner"));
308  } elseif (count($coords) == 1) {
309  $this->tpl->setOnScreenMessage('info', $this->lng->txt("rectangle_click_br_corner"));
310  $preview->addPoint($preview->getAreaCount(), join(",", $coords), true, "blue");
311  } elseif (count($coords) == 2) {
312  $c = join(",", $coords);
313  $hidearea = true;
314  $disabled_save = "";
315  }
316  break;
317  case "circle":
318  if (count($coords) == 0) {
319  $this->tpl->setOnScreenMessage('info', $this->lng->txt("circle_click_center"));
320  } elseif (count($coords) == 1) {
321  $this->tpl->setOnScreenMessage('info', $this->lng->txt("circle_click_circle"));
322  $preview->addPoint($preview->getAreaCount(), join(",", $coords), true, "blue");
323  } elseif (count($coords) == 2) {
324  if (preg_match("/(\d+)\s*,\s*(\d+)\s+(\d+)\s*,\s*(\d+)/", $coords[0] . " " . $coords[1], $matches)) {
325  $c = "$matches[1],$matches[2]," . (int) sqrt((($matches[3] - $matches[1]) * ($matches[3] - $matches[1])) + (($matches[4] - $matches[2]) * ($matches[4] - $matches[2])));
326  }
327  $hidearea = true;
328  $disabled_save = "";
329  }
330  break;
331  case "poly":
332  if (count($coords) == 0) {
333  $this->tpl->setOnScreenMessage('info', $this->lng->txt("polygon_click_starting_point"));
334  } elseif (count($coords) == 1) {
335  $this->tpl->setOnScreenMessage('info', $this->lng->txt("polygon_click_next_point"));
336  $preview->addPoint($preview->getAreaCount(), implode(",", $coords), true, "blue");
337  } elseif (count($coords) > 1) {
338  $this->tpl->setOnScreenMessage('info', $this->lng->txt("polygon_click_next_or_save"));
339  $disabled_save = "";
340  $c = implode(",", $coords);
341  }
342  break;
343  }
344  if (strlen($c)) {
345  $preview->addArea($preview->getAreaCount(), $shape, $c, $_POST["shapetitle"] ?? '', "", "", true, "blue");
346  }
347  $preview->createPreview();
348  $imagepath = $this->object->getImagePathWeb() . $preview->getPreviewFilename($this->object->getImagePath(), $this->object->getImageFilename()) . "?img=" . time();
349  if (!$hidearea) {
350  $editorTpl->setCurrentBlock("maparea");
351  $editorTpl->setVariable("IMAGE_SOURCE", "$imagepath");
352  $editorTpl->setVariable("IMAGEMAP_NAME", "image");
353  $editorTpl->parseCurrentBlock();
354  } else {
355  $editorTpl->setCurrentBlock("imagearea");
356  $editorTpl->setVariable("IMAGE_SOURCE", "$imagepath");
357  $editorTpl->setVariable("ALT_IMAGE", $this->lng->txt("imagemap"));
358  $editorTpl->parseCurrentBlock();
359  }
360 
361  if (isset($_POST['shapetitle']) && $_POST['shapetitle'] != '') {
362  $editorTpl->setCurrentBlock("shapetitle");
363  $editorTpl->setVariable("VALUE_SHAPETITLE", $_POST["shapetitle"]);
364  $editorTpl->parseCurrentBlock();
365  }
366 
367  $editorTpl->setVariable("TEXT_IMAGEMAP", $this->lng->txt("imagemap"));
368  $editorTpl->setVariable("TEXT_SHAPETITLE", $this->lng->txt("ass_imap_hint"));
369  $editorTpl->setVariable("CANCEL", $this->lng->txt("cancel"));
370  $editorTpl->setVariable("SAVE", $this->lng->txt("save"));
371  $editorTpl->setVariable("DISABLED_SAVE", $disabled_save);
372  switch ($shape) {
373  case "rect":
374  $editorTpl->setVariable("FORMACTION", $this->ctrl->getFormaction($this, 'addRect'));
375  break;
376  case 'circle':
377  $editorTpl->setVariable("FORMACTION", $this->ctrl->getFormaction($this, 'addCircle'));
378  break;
379  case 'poly':
380  $editorTpl->setVariable("FORMACTION", $this->ctrl->getFormaction($this, 'addPoly'));
381  break;
382  }
383 
384  $this->tpl->setVariable('QUESTION_DATA', $editorTpl->get());
385  }
386 
387  public function back(): void
388  {
389  $this->tpl->setOnScreenMessage('info', $this->lng->txt('msg_cancel'), true);
390  $this->ctrl->redirect($this, 'editQuestion');
391  }
392 
393  // hey: prevPassSolutions - max solution pass determinations allready done, pass passed for sure
394  // hey: fixedIdentifier - changed access to passed param (lower-/uppercase issues)
395  protected function completeTestOutputFormAction($formAction, $active_id, $pass)
396  {
397  $info = $this->object->getTestOutputSolutions($active_id, $pass);
398 
399  if (count($info)) {
400  if ($info[0]['value1'] !== "") {
401  $formAction .= "&selImage=" . $info[0]['value1'];
402  }
403  }
404 
405  return $formAction;
406  }
407  // hey.
408  // hey.
409 
422  public function getSolutionOutput(
423  $active_id,
424  $pass = null,
425  $graphicalOutput = false,
426  $result_output = false,
427  $show_question_only = true,
428  $show_feedback = false,
429  $show_correct_solution = false,
430  $show_manual_scoring = false,
431  $show_question_text = true
432  ): string {
433  $user_solutions = array();
434 
435 
436  if (($active_id > 0) && (!$show_correct_solution)) {
437  $user_solutions = $this->object->getSolutionValues($active_id, $pass);
438  } else {
439  if (!$this->object->getIsMultipleChoice()) {
440  $found_index = -1;
441  $max_points = 0;
442  foreach ($this->object->answers as $index => $answer) {
443  if ($answer->getPoints() > $max_points) {
444  $max_points = $answer->getPoints();
445  $found_index = $index;
446  }
447  }
448  array_push($user_solutions, array("value1" => $found_index));
449  } else {
450  // take the correct solution instead of the user solution
451  foreach ($this->object->answers as $index => $answer) {
452  $points_checked = $answer->getPoints();
453  $points_unchecked = $answer->getPointsUnchecked();
454  if ($points_checked > $points_unchecked) {
455  if ($points_checked > 0) {
456  array_push($user_solutions, array("value1" => $index));
457  }
458  }
459  }
460  }
461  }
462 
463  $show_inline_feedback = false;
464  return $this->renderSolutionOutput(
465  $user_solutions,
466  $active_id,
467  $pass,
468  $graphicalOutput,
469  $result_output,
470  $show_question_only,
471  $show_feedback,
472  $show_correct_solution,
473  $show_manual_scoring,
474  $show_question_text,
475  false,
476  $show_inline_feedback,
477  );
478  }
479 
480  public function renderSolutionOutput(
481  mixed $user_solutions,
482  int $active_id,
483  ?int $pass,
484  bool $graphical_output = false,
485  bool $result_output = false,
486  bool $show_question_only = true,
487  bool $show_feedback = false,
488  bool $show_correct_solution = false,
489  bool $show_manual_scoring = false,
490  bool $show_question_text = true,
491  bool $show_autosave_title = false,
492  bool $show_inline_feedback = false,
493  ): ?string {
494  $imagepath = $this->object->getImagePathWeb() . $this->object->getImageFilename();
495  $solution_id = -1;
496  if (is_array($user_solutions)) {
497  $preview = new ilImagemapPreview($this->object->getImagePath() . $this->object->getImageFilename());
498  foreach ($user_solutions as $idx => $solution_value) {
499  $value1 = $solution_value['value1'];
500  if (
501  $value1 === '' ||
502  !isset($this->object->answers[$value1])
503  ) {
504  continue;
505  }
506 
508  $shape = $this->object->answers[$value1];
509  $preview->addArea(
510  $value1,
511  $shape->getArea(),
512  $shape->getCoords(),
513  $shape->getAnswertext(),
514  '',
515  '',
516  true,
518  );
519 
520  $solution_id = $value1;
521  }
522  $preview->createPreview();
523  $imagepath = implode('', [
524  $this->object->getImagePathWeb(),
525  $preview->getPreviewFilename(
526  $this->object->getImagePath(),
527  $this->object->getImageFilename()
528  ),
529  ]);
530  }
531 
532  // generate the question output
533  $template = new ilTemplate("tpl.il_as_qpl_imagemap_question_output_solution.html", true, true, "Modules/TestQuestionPool");
534  $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "Modules/TestQuestionPool");
535  if ($show_question_text == true) {
536  $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
537  }
538 
539  $template->setVariable("IMG_SRC", ilWACSignedPath::signFile($imagepath));
540  $template->setVariable("IMG_ALT", $this->lng->txt("imagemap"));
541  $template->setVariable("IMG_TITLE", $this->lng->txt("imagemap"));
542  if (($active_id > 0) && (!$show_correct_solution)) {
543  if ($graphical_output) {
544  $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_NOT_OK);
545  $reached_points = $this->object->getReachedPoints($active_id, $pass);
546  if ($reached_points == $this->object->getMaximumPoints()) {
547  $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_OK);
548  }
549 
550  if ($reached_points > 0) {
551  $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_MOSTLY_OK);
552  }
553  $template->setCurrentBlock("icon_ok");
554  $template->setVariable("ICON_OK", $correctness_icon);
555  $template->parseCurrentBlock();
556  }
557  }
558 
559  if ($show_feedback) {
560  $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation(
561  $this->object->getId(),
562  0,
563  $solution_id
564  );
565 
566  if (strlen($fb)) {
567  $template->setCurrentBlock("feedback");
568  $template->setVariable("FEEDBACK", $fb);
569  $template->parseCurrentBlock();
570  }
571  }
572 
573  $questionoutput = $template->get();
574  $feedback = ($show_feedback && !$this->isTestPresentationContext()) ? $this->getGenericFeedbackOutput((int) $active_id, $pass) : "";
575  if (strlen($feedback)) {
576  $cssClass = (
577  $this->hasCorrectSolution($active_id, $pass) ?
579  );
580 
581  $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
582  $solutiontemplate->setVariable("FEEDBACK", ilLegacyFormElementsUtil::prepareTextareaOutput($feedback, true));
583  }
584  $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
585 
586  $solutionoutput = $solutiontemplate->get();
587  if (!$show_question_only) {
588  // get page object output
589  $solutionoutput = $this->getILIASPage($solutionoutput);
590  }
591  return $solutionoutput;
592  }
593 
594  public function getPreview($show_question_only = false, $showInlineFeedback = false): string
595  {
596  if (is_object($this->getPreviewSession())) {
597  $user_solution = array();
598 
599  if (is_array($this->getPreviewSession()->getParticipantsSolution())) {
600  $user_solution = array_values($this->getPreviewSession()->getParticipantsSolution());
601  }
602 
603  $preview = new ilImagemapPreview($this->object->getImagePath() . $this->object->getImageFilename());
604  foreach ($user_solution as $idx => $solution_value) {
605  if ($solution_value !== '') {
606  $preview->addArea($solution_value, $this->object->answers[$solution_value]->getArea(), $this->object->answers[$solution_value]->getCoords(), $this->object->answers[$solution_value]->getAnswertext(), "", "", true, $this->linecolor);
607  }
608  }
609  $preview->createPreview();
610  $imagepath = $this->object->getImagePathWeb() . $preview->getPreviewFilename($this->object->getImagePath(), $this->object->getImageFilename());
611  } else {
612  $user_solution = array();
613  $imagepath = $this->object->getImagePathWeb() . $this->object->getImageFilename();
614  }
615 
616  // generate the question output
617  $template = new ilTemplate("tpl.il_as_qpl_imagemap_question_output.html", true, true, "Modules/TestQuestionPool");
618 
619  if ($this->getQuestionActionCmd() && !is_null($this->getTargetGuiClass())) {
620  $hrefArea = $this->ctrl->getLinkTargetByClass($this->getTargetGuiClass(), $this->getQuestionActionCmd());
621  } else {
622  $hrefArea = null;
623  }
624 
625  foreach ($this->object->answers as $answer_id => $answer) {
626  $parameter = "&amp;selImage=$answer_id";
627  if (is_array($user_solution) && in_array($answer_id, $user_solution)) {
628  $parameter = "&amp;remImage=$answer_id";
629  }
630 
631  if ($hrefArea) {
632  $template->setCurrentBlock("imagemap_area_href");
633  $template->setVariable("HREF_AREA", $hrefArea . $parameter);
634  $template->parseCurrentBlock();
635  }
636 
637  $template->setCurrentBlock("imagemap_area");
638  $template->setVariable("SHAPE", $answer->getArea());
639  $template->setVariable("COORDS", $answer->getCoords());
640  $template->setVariable("ALT", ilLegacyFormElementsUtil::prepareFormOutput($answer->getAnswertext()));
641  $template->setVariable("TITLE", ilLegacyFormElementsUtil::prepareFormOutput($answer->getAnswertext()));
642  $template->parseCurrentBlock();
643  }
644  $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
645  $template->setVariable("IMG_SRC", ilWACSignedPath::signFile($imagepath));
646  $template->setVariable("IMG_ALT", $this->lng->txt("imagemap"));
647  $template->setVariable("IMG_TITLE", $this->lng->txt("imagemap"));
648  $questionoutput = $template->get();
649  if (!$show_question_only) {
650  // get page object output
651  $questionoutput = $this->getILIASPage($questionoutput);
652  }
653  return $questionoutput;
654  }
655 
656  // hey: prevPassSolutions - pass will be always available from now on
657  public function getTestOutput($active_id, $pass, $is_postponed = false, $use_post_solutions = false, $show_feedback = false): string
658  // hey.
659  {
660  if ($active_id) {
661  $solutions = $this->object->getTestOutputSolutions($active_id, $pass);
662  // hey.
663 
664  $userSelection = array();
665  $selectionIndex = 0;
666 
667  $preview = new ilImagemapPreview($this->object->getImagePath() . $this->object->getImageFilename());
668 
669  foreach ($solutions as $idx => $solution_value) {
670  if ($solution_value['value1'] !== null) {
671  $preview->addArea($solution_value['value1'], $this->object->answers[$solution_value['value1']]->getArea(), $this->object->answers[$solution_value['value1']]->getCoords(), $this->object->answers[$solution_value['value1']]->getAnswertext(), "", "", true, $this->linecolor);
672  $userSelection[$selectionIndex] = $solution_value['value1'];
673 
674  $selectionIndex = $this->object->getIsMultipleChoice() ? ++$selectionIndex : $selectionIndex;
675  }
676  }
677 
678  $preview->createPreview();
679 
680  $imagepath = $this->object->getImagePathWeb() . $preview->getPreviewFilename($this->object->getImagePath(), $this->object->getImageFilename());
681  } else {
682  $imagepath = $this->object->getImagePathWeb() . $this->object->getImageFilename();
683  }
684 
685  // generate the question output
686  $template = new ilTemplate("tpl.il_as_qpl_imagemap_question_output.html", true, true, "Modules/TestQuestionPool");
687  $this->ctrl->setParameterByClass($this->getTargetGuiClass(), "formtimestamp", time());
688  foreach ($this->object->answers as $answer_id => $answer) {
689  $template->setCurrentBlock("imagemap_area");
690  $template->setVariable("HREF_AREA", $this->buildAreaLinkTarget($userSelection, $answer_id));
691  $template->setVariable("SHAPE", $answer->getArea());
692  $template->setVariable("COORDS", $answer->getCoords());
693  $template->setVariable("ALT", ilLegacyFormElementsUtil::prepareFormOutput($answer->getAnswertext()));
694  $template->setVariable("TITLE", ilLegacyFormElementsUtil::prepareFormOutput($answer->getAnswertext()));
695  $template->parseCurrentBlock();
696  if ($show_feedback) {
697  if (!$this->object->getIsMultipleChoice() && count($userSelection) && current($userSelection) == $answer_id) {
698  $feedback = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation(
699  $this->object->getId(),
700  0,
701  $answer_id
702  );
703  if ($feedback !== '') {
704  $template->setCurrentBlock("feedback");
705  $template->setVariable("FEEDBACK", $feedback);
706  $template->parseCurrentBlock();
707  }
708  }
709  }
710  }
711  $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
712  $template->setVariable("IMG_SRC", ilWACSignedPath::signFile($imagepath));
713  $template->setVariable("IMG_ALT", $this->lng->txt("imagemap"));
714  $template->setVariable("IMG_TITLE", $this->lng->txt("imagemap"));
715  $questionoutput = $template->get();
716  $pageoutput = $this->outQuestionPage("", $is_postponed, $active_id, $questionoutput);
717  return $pageoutput;
718  }
719 
720  // hey: prevPassSolutions - fixed confusing handling of not reusing, but modifying the previous solution
721  protected function buildAreaLinkTarget($currentSelection, $areaIndex): string
722  {
723  $href = $this->ctrl->getLinkTargetByClass(
724  $this->getTargetGuiClass(),
725  $this->getQuestionActionCmd()
726  );
727 
729  $href,
730  $this->buildSelectionParameter($currentSelection, $areaIndex)
731  );
732 
733  return $href;
734  }
735 
736  protected function buildSelectionParameter($currentSelection, $areaIndex = null): string
737  {
738  if ($this->object->getTestPresentationConfig()->isSolutionInitiallyPrefilled()) {
739  $reuseSelection = array();
740 
741  if ($areaIndex === null) {
742  $reuseSelection = $currentSelection;
743  } elseif ($this->object->getIsMultipleChoice()) {
744  if (!in_array($areaIndex, $currentSelection)) {
745  $reuseSelection[] = $areaIndex;
746  }
747 
748  foreach (array_diff($currentSelection, array($areaIndex)) as $otherSelectedArea) {
749  $reuseSelection[] = $otherSelectedArea;
750  }
751  } else {
752  $reuseSelection[] = $areaIndex;
753  }
754 
755  $selection = assQuestion::implodeKeyValues($reuseSelection);
756  $action = 'reuseSelection';
757  } elseif ($areaIndex !== null) {
758  if (!$this->object->getIsMultipleChoice() || !in_array($areaIndex, $currentSelection)) {
759  $areaAction = 'selImage';
760  } else {
761  $areaAction = 'remImage';
762  }
763 
764  $selection = $areaIndex;
765  $action = $areaAction;
766  } else {
767  return '';
768  }
769 
770  return "{$action}={$selection}";
771  }
772 
773  public function getSpecificFeedbackOutput(array $userSolution): string
774  {
775  if (!$this->object->feedbackOBJ->specificAnswerFeedbackExists()) {
776  return '';
777  }
778 
779  $output = '<table class="test_specific_feedback"><tbody>';
780 
781  foreach ($this->object->getAnswers() as $idx => $answer) {
782  $feedback = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation(
783  $this->object->getId(),
784  0,
785  $idx
786  );
787 
788  $output .= "<tr><td>{$answer->getAnswerText()}</td><td>{$feedback}</td></tr>";
789  }
790 
791  $output .= '</tbody></table>';
792 
794  }
795 
806  {
807  return array();
808  }
809 
820  {
821  return array();
822  }
823 
824  protected function renderAggregateView($answeringFequencies): string
825  {
826  $tpl = new ilTemplate('tpl.il_as_aggregated_answers_table.html', true, true, "Modules/TestQuestionPool");
827 
828  $tpl->setCurrentBlock('headercell');
829  $tpl->setVariable('HEADER', $this->lng->txt('tst_answer_aggr_answer_header'));
831 
832  $tpl->setCurrentBlock('headercell');
833  $tpl->setVariable('HEADER', $this->lng->txt('tst_answer_aggr_frequency_header'));
835 
836  foreach ($answeringFequencies as $answerIndex => $answeringFrequency) {
837  $tpl->setCurrentBlock('aggregaterow');
838  $tpl->setVariable('OPTION', $this->object->getAnswer($answerIndex)->getAnswerText());
839  $tpl->setVariable('COUNT', $answeringFrequency);
841  }
842 
843  return $tpl->get();
844  }
845 
846  protected function aggregateAnswers($givenSolutionRows, $existingAnswerOptions): array
847  {
848  $answeringFequencies = array();
849 
850  foreach ($existingAnswerOptions as $answerIndex => $answerOption) {
851  $answeringFequencies[$answerIndex] = 0;
852  }
853 
854  foreach ($givenSolutionRows as $solutionRow) {
855  $answeringFequencies[$solutionRow['value1']]++;
856  }
857 
858  return $answeringFequencies;
859  }
860 
867  public function getAggregatedAnswersView(array $relevant_answers): string
868  {
869  return $this->renderAggregateView(
870  $this->aggregateAnswers($relevant_answers, $this->object->getAnswers())
871  );
872  }
873 
874  protected function getPreviousSolutionConfirmationCheckboxHtml(): string
875  {
876  if (!count($this->object->currentSolution)) {
877  return '';
878  }
879 
880  global $DIC;
881  $button = $DIC->ui()->factory()->link()->standard(
882  $this->lng->txt('use_previous_solution'),
884  $this->ctrl->getLinkTargetByClass($this->getTargetGuiClass(), $this->getQuestionActionCmd()),
885  $this->buildSelectionParameter($this->object->currentSolution, null)
886  )
887  );
888 
889  $tpl = new ilTemplate('tpl.tst_question_additional_behaviour_checkbox.html', true, true, 'Modules/TestQuestionPool');
890  $tpl->setVariable('BUTTON', $DIC->ui()->renderer()->render($button));
891 
892  return $tpl->get();
893  }
894 
895  public function getAnswersFrequency($relevantAnswers, $questionIndex): array
896  {
897  $agg = $this->aggregateAnswers($relevantAnswers, $this->object->getAnswers());
898 
899  $answers = array();
900 
901  foreach ($this->object->getAnswers() as $answerIndex => $ans) {
902  $answers[] = array(
903  'answer' => $ans->getAnswerText(),
904  'frequency' => $agg[$answerIndex]
905  );
906  }
907 
908  return $answers;
909  }
910 
912  {
913  $image = new ilImagemapCorrectionsInputGUI($this->lng->txt('image'), 'image');
914  $image->setPointsUncheckedFieldEnabled($this->object->getIsMultipleChoice());
915  $image->setRequired(true);
916 
917  if (strlen($this->object->getImageFilename())) {
918  $image->setImage($this->object->getImagePathWeb() . $this->object->getImageFilename());
919  $image->setValue($this->object->getImageFilename());
920  $image->setAreas($this->object->getAnswers());
921  $assessmentSetting = new ilSetting("assessment");
922  $linecolor = (strlen(
923  $assessmentSetting->get("imap_line_color")
924  )) ? "\"#" . $assessmentSetting->get("imap_line_color") . "\"" : "\"#FF0000\"";
925  $image->setLineColor($linecolor);
926  $image->setImagePath($this->object->getImagePath());
927  $image->setImagePathWeb($this->object->getImagePathWeb());
928  }
929  $form->addItem($image);
930  }
931 
936  {
937  $areas = $form->getItemByPostVar('image')->getAreas();
938 
939  foreach ($this->object->getAnswers() as $index => $answer) {
940  if ($this->object->getIsMultipleChoice()) {
941  $answer->setPointsUnchecked((float) $areas[$index]->getPointsUnchecked());
942  }
943 
944  $answer->setPoints((float) $areas[$index]->getPoints());
945  }
946  }
947 }
getTestOutput($active_id, $pass, $is_postponed=false, $use_post_solutions=false, $show_feedback=false)
hasCorrectSolution($activeId, $passIndex)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
renderAggregateView($answeringFequencies)
completeTestOutputFormAction($formAction, $active_id, $pass)
populateQuestionSpecificFormPart(\ilPropertyFormGUI $form)
static appendUrlParameterString(string $a_url, string $a_par, bool $xml_style=false)
generateCorrectnessIconsForCorrectness(int $correctness)
setCurrentBlock(string $blockname=self::DEFAULT_BLOCK)
Sets the template to the given block.
saveShape()
Saves a shape of the area editor.
getAnswersFrequency($relevantAnswers, $questionIndex)
getItemByPostVar(string $a_post_var)
addBasicQuestionFormProperties(ilPropertyFormGUI $form)
getAggregatedAnswersView(array $relevant_answers)
Returns an html string containing a question specific representation of the answers so far given in t...
parseCurrentBlock(string $blockname=self::DEFAULT_BLOCK)
Parses the given block.
renderSolutionOutput(mixed $user_solutions, int $active_id, int $pass, bool $graphical_output=false, bool $result_output=false, bool $show_question_only=true, bool $show_feedback=false, bool $show_correct_solution=false, bool $show_manual_scoring=false, bool $show_question_text=true, bool $show_autosave_title=false, bool $show_inline_feedback=false,)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
populateAnswerSpecificFormPart(\ilPropertyFormGUI $form)
writePostData(bool $always=false)
{}
ilGlobalPageTemplate $tpl
static prepareFormOutput($a_str, bool $a_strip=false)
getPreview($show_question_only=false, $showInlineFeedback=false)
buildAreaLinkTarget($currentSelection, $areaIndex)
populateTaxonomyFormSection(ilPropertyFormGUI $form)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static implodeKeyValues(array $keyValues)
addQuestionFormCommandButtons(ilPropertyFormGUI $form)
global $DIC
Definition: feed.php:28
buildSelectionParameter($currentSelection, $areaIndex=null)
This class represents an image map file property in a property form.
This class represents a property in a property form.
__construct(VocabulariesInterface $vocabularies)
aggregateAnswers($givenSolutionRows, $existingAnswerOptions)
get(string $part=self::DEFAULT_BLOCK)
Renders the given block and returns the html string.
getSolutionOutput( $active_id, $pass=null, $graphicalOutput=false, $result_output=false, $show_question_only=true, $show_feedback=false, $show_correct_solution=false, $show_manual_scoring=false, $show_question_text=true)
Get the question solution output.
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from $_POST and applies them to the data object.
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
Extracts the question specific values from $_POST and applies them to the data object.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Basic GUI class for assessment questions.
setRequired(bool $a_required)
getSpecificFeedbackOutput(array $userSolution)
getILIASPage(string $html="")
Returns the ILIAS Page around a question.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
static signFile(string $path_to_file)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
__construct($id=-1)
assImagemapQuestionGUI constructor
addArea( $index, $shape, $coords, $title="", $href="", $target="", $visible=true, $linecolor="red", $bordercolor="white", $fillcolor="#FFFFFFA0")
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
static prepareTextareaOutput(string $txt_output, bool $prepare_for_latex_output=false, bool $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output where latex code may be in it If the text is HTML-free...
setPointsUncheckedFieldEnabled($pointsUncheckedFieldEnabled)
setVariable(string $variable, $value='')
Sets the given variable to the given value.
editQuestion(ilPropertyFormGUI $form=null)
getGenericFeedbackOutput(int $active_id, ?int $pass)