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