ILIAS  release_8 Revision v8.24
class.assMultipleChoiceGUI.php
Go to the documentation of this file.
1<?php
2
19require_once './Modules/Test/classes/inc.AssessmentConstants.php';
20
36{
38
47 public function __construct($id = -1)
48 {
50 include_once "./Modules/TestQuestionPool/classes/class.assMultipleChoice.php";
51 $this->object = new assMultipleChoice();
52 if ($id >= 0) {
53 $this->object->loadFromDb($id);
54 }
55 }
56
60 public function hasInlineFeedback(): bool
61 {
62 return $this->object->feedbackOBJ->isSpecificAnswerFeedbackAvailable($this->object->getId());
63 }
64
68 protected function writePostData(bool $always = false): int
69 {
70 $hasErrors = (!$always) ? $this->editQuestion(true) : false;
71 if (!$hasErrors) {
72 $is_singleline = $this->getEditAnswersSingleLine();
73 $form = $this->buildEditForm($is_singleline);
74 $form->setValuesByPost();
75 require_once 'Services/Form/classes/class.ilPropertyFormGUI.php';
78 $this->writeAnswerSpecificPostData($form);
80 return 0;
81 }
82 return 1;
83 }
84
92 protected function getEditAnswersSingleLine($checkonly = false): bool
93 {
94 if ($this->object->getSelfAssessmentEditingMode()) {
95 return $this->object->isSingleline();
96 }
97
98 if ($checkonly) {
99 $types = $_POST['types'] ?? '0';
100 return $types === '0' ? true : false;
101 }
102
103 $lastChange = $this->object->getLastChange();
104 if (empty($lastChange) && !isset($_POST['types'])) {
105 // a new question is edited
106 return $this->object->getMultilineAnswerSetting() ? false : true;
107 } else {
108 // a saved question is edited
109 return $this->object->isSingleline();
110 }
111 }
112
120 public function editQuestion($checkonly = false): bool
121 {
122 $save = $this->isSaveCommand();
123 $this->getQuestionTemplate();
124
125 $is_singleline = $this->getEditAnswersSingleLine($checkonly);
126
127 $form = $this->buildEditForm($is_singleline);
128
129 if ($is_singleline) {
130 $form->setMultipart(true);
131 } else {
132 $form->setMultipart(false);
133 }
134
135 $errors = false;
136
137 if ($save) {
138 $form->getItemByPostVar('selection_limit')->setMaxValue(count((array) $_POST['choice']['answer']));
139
140 $form->setValuesByPost();
141 $errors = !$form->checkInput();
142 if ($errors) {
143 $checkonly = false;
144 }
145 }
146
147 if (!$checkonly) {
148 $this->tpl->setVariable("QUESTION_DATA", $form->getHTML());
149 }
150 return $errors;
151 }
152
154 {
155 parent::addBasicQuestionFormProperties($form);
156 $form->getItemByPostVar('question')->setInitialRteWidth('100');
157 }
158
162 public function uploadchoice(): void
163 {
164 $this->writePostData(true);
165 $this->editQuestion();
166 }
167
171 public function removeimagechoice(): void
172 {
173 $this->writePostData(true);
174 $position = key($_POST['cmd']['removeimagechoice']);
175 $this->object->removeAnswerImage($position);
176 $this->editQuestion();
177 }
178
182 public function addchoice(): void
183 {
184 $this->writePostData(true);
185 $position = key($_POST['cmd']['addchoice']);
186 $this->object->addAnswer("", 0, 0, $position + 1);
187 $this->editQuestion();
188 }
189
193 public function removechoice(): void
194 {
195 $this->writePostData(true);
196 $position = key($_POST['cmd']['removechoice']);
197 $this->object->deleteAnswer($position);
198 $this->editQuestion();
199 }
200
214 public function getSolutionOutput(
215 $active_id,
216 $pass = null,
217 $graphicalOutput = false,
218 $result_output = false,
219 $show_question_only = true,
220 $show_feedback = false,
221 $show_correct_solution = false,
222 $show_manual_scoring = false,
223 $show_question_text = true
224 ): string {
225 // shuffle output
226 $keys = $this->getChoiceKeys();
227
228 // get the solution of the user for the active pass or from the last pass if allowed
229 $user_solution = array();
230 if (($active_id > 0) && (!$show_correct_solution)) {
231 $solutions = $this->object->getSolutionValues($active_id, $pass);
232 foreach ($solutions as $idx => $solution_value) {
233 array_push($user_solution, $solution_value["value1"]);
234 }
235 } else {
236 // take the correct solution instead of the user solution
237 foreach ($this->object->answers as $index => $answer) {
238 $points_checked = $answer->getPointsChecked();
239 $points_unchecked = $answer->getPointsUnchecked();
240 if ($points_checked > $points_unchecked) {
241 if ($points_checked > 0) {
242 array_push($user_solution, $index);
243 }
244 }
245 }
246 }
247
248 // generate the question output
249 include_once "./Services/UICore/classes/class.ilTemplate.php";
250 $template = new ilTemplate("tpl.il_as_qpl_mc_mr_output_solution.html", true, true, "Modules/TestQuestionPool");
251 $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "Modules/TestQuestionPool");
252 foreach ($keys as $answer_id) {
253 $answer = $this->object->answers[$answer_id];
254 if (($active_id > 0) && (!$show_correct_solution)) {
255 if ($graphicalOutput) {
256 // output of ok/not ok icons for user entered solutions
257 $ok = false;
258 $checked = false;
259 foreach ($user_solution as $mc_solution) {
260 if (strcmp($mc_solution, $answer_id) == 0) {
261 $checked = true;
262 }
263 }
264 if ($checked) {
265 if ($answer->getPointsChecked() > $answer->getPointsUnchecked()) {
267 } else {
269 }
270 } else {
271 if ($answer->getPointsChecked() > $answer->getPointsUnchecked()) {
273 } else {
275 }
276 }
277 $icon = $this->generateCorrectnessIconsForCorrectness($ok);
278 $template->setCurrentBlock("icon_ok");
279 $template->setVariable("ICON_OK", $icon);
280 $template->parseCurrentBlock();
281 }
282 }
283 if (strlen($answer->getImage())) {
284 $template->setCurrentBlock("answer_image");
285 if ($this->object->getThumbSize()) {
286 $template->setVariable("ANSWER_IMAGE_URL", $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $answer->getImage());
287 } else {
288 $template->setVariable("ANSWER_IMAGE_URL", $this->object->getImagePathWeb() . $answer->getImage());
289 }
290 $alt = $answer->getImage();
291 if (strlen($answer->getAnswertext())) {
292 $alt = $answer->getAnswertext();
293 }
294 $alt = preg_replace("/<[^>]*?>/", "", $alt);
295 $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
296 $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
297 $template->parseCurrentBlock();
298 }
299
300 if ($show_feedback) {
301 if ($this->object->getSpecificFeedbackSetting() == 2) {
302 foreach ($user_solution as $mc_solution) {
303 if (strcmp($mc_solution, $answer_id) == 0) {
304 $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation(
305 $this->object->getId(),
306 0,
307 $answer_id
308 );
309 if (strlen($fb)) {
310 $template->setCurrentBlock("feedback");
311 $template->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($fb, true));
312 $template->parseCurrentBlock();
313 }
314 }
315 }
316 }
317
318 if ($this->object->getSpecificFeedbackSetting() == 1) {
319 $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation(
320 $this->object->getId(),
321 0,
322 $answer_id
323 );
324 if (strlen($fb)) {
325 $template->setCurrentBlock("feedback");
326 $template->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($fb, true));
327 $template->parseCurrentBlock();
328 }
329 }
330
331 if ($this->object->getSpecificFeedbackSetting() == 3) {
332 $answer = $this->object->getAnswer($answer_id);
333
334 if ($answer->getPoints() > 0) {
335 $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation(
336 $this->object->getId(),
337 0,
338 $answer_id
339 );
340 if (strlen($fb)) {
341 $template->setCurrentBlock("feedback");
342 $template->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($fb, true));
343 $template->parseCurrentBlock();
344 }
345 }
346 }
347 }
348 $template->setCurrentBlock("answer_row");
349 $template->setVariable("ANSWER_TEXT", $this->object->prepareTextareaOutput($answer->getAnswertext(), true));
350 $checked = false;
351 if ($result_output) {
352 $pointschecked = $this->object->answers[$answer_id]->getPointsChecked();
353 $pointsunchecked = $this->object->answers[$answer_id]->getPointsUnchecked();
354 $resulttextchecked = ($pointschecked == 1) || ($pointschecked == -1) ? "%s " . $this->lng->txt("point") : "%s " . $this->lng->txt("points");
355 $resulttextunchecked = ($pointsunchecked == 1) || ($pointsunchecked == -1) ? "%s " . $this->lng->txt("point") : "%s " . $this->lng->txt("points");
356 $template->setVariable("RESULT_OUTPUT", sprintf("(" . $this->lng->txt("checkbox_checked") . " = $resulttextchecked, " . $this->lng->txt("checkbox_unchecked") . " = $resulttextunchecked)", $pointschecked, $pointsunchecked));
357 }
358 foreach ($user_solution as $mc_solution) {
359 if (strcmp($mc_solution, $answer_id) == 0) {
361 $template->setVariable("SOLUTION_IMAGE", ilUtil::getHtmlPath(ilUtil::getImagePath("checkbox_checked.png")));
362 $template->setVariable("SOLUTION_ALT", $this->lng->txt("checked"));
363 } else {
364 $template->setVariable('QID', $this->object->getId());
365 $template->setVariable('SUFFIX', $show_correct_solution ? 'bestsolution' : 'usersolution');
366 $template->setVariable('SOLUTION_VALUE', $answer_id);
367 $template->setVariable('SOLUTION_CHECKED', 'checked');
368 }
369 $checked = true;
370 }
371 }
372 if (!$checked) {
374 $template->setVariable("SOLUTION_IMAGE", ilUtil::getHtmlPath(ilUtil::getImagePath("checkbox_unchecked.png")));
375 $template->setVariable("SOLUTION_ALT", $this->lng->txt("unchecked"));
376 } else {
377 $template->setVariable('QID', $this->object->getId());
378 $template->setVariable('SUFFIX', $show_correct_solution ? 'bestsolution' : 'usersolution');
379 $template->setVariable('SOLUTION_VALUE', $answer_id);
380 }
381 }
382 $template->parseCurrentBlock();
383 }
384 $questiontext = $this->object->getQuestionForHTMLOutput();
385 if ($show_feedback && $this->hasInlineFeedback()) {
386 $questiontext .= $this->buildFocusAnchorHtml();
387 }
388 if ($show_question_text == true) {
389 $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, true));
390 }
391 $questionoutput = $template->get();
392 $feedback = ($show_feedback && !$this->isTestPresentationContext()) ? $this->getGenericFeedbackOutput((int) $active_id, $pass) : "";
393
394 if (strlen($feedback)) {
395 $cssClass = (
396 $this->hasCorrectSolution($active_id, $pass) ?
398 );
399
400 $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
401 $solutiontemplate->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($feedback, true));
402 }
403 $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
404
405 $solutionoutput = $solutiontemplate->get();
406
407 if (!$show_question_only) {
408 // get page object output
409 $solutionoutput = $this->getILIASPage($solutionoutput);
410 }
411 return $solutionoutput;
412 }
413
414 public function getPreview($show_question_only = false, $showInlineFeedback = false): string
415 {
416 $user_solution = is_object($this->getPreviewSession()) ? (array) $this->getPreviewSession()->getParticipantsSolution() : array();
417 // shuffle output
418 $keys = $this->getChoiceKeys();
419
420 // generate the question output
421 include_once "./Services/UICore/classes/class.ilTemplate.php";
422 $this->tpl->addOnLoadCode('ilAssMultipleChoiceCharCounterInit();');
423 $template = new ilTemplate("tpl.il_as_qpl_mc_mr_output.html", true, true, "Modules/TestQuestionPool");
424 foreach ($keys as $answer_id) {
425 $answer = $this->object->answers[$answer_id];
426 if (strlen($answer->getImage())) {
427 if ($this->object->getThumbSize()) {
428 $template->setCurrentBlock("preview");
429 $template->setVariable("URL_PREVIEW", $this->object->getImagePathWeb() . $answer->getImage());
430 $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
431 $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
432 $template->setVariable("ANSWER_IMAGE_URL", $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $answer->getImage());
433 list($width, $height, $type, $attr) = getimagesize($this->object->getImagePath() . $answer->getImage());
434 $alt = $answer->getImage();
435 if (strlen($answer->getAnswertext())) {
436 $alt = $answer->getAnswertext();
437 }
438 $alt = preg_replace("/<[^>]*?>/", "", $alt);
439 $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
440 $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
441 $template->parseCurrentBlock();
442 } else {
443 $template->setCurrentBlock("answer_image");
444 $template->setVariable("ANSWER_IMAGE_URL", $this->object->getImagePathWeb() . $answer->getImage());
445 list($width, $height, $type, $attr) = getimagesize($this->object->getImagePath() . $answer->getImage());
446 $alt = $answer->getImage();
447 if (strlen($answer->getAnswertext())) {
448 $alt = $answer->getAnswertext();
449 }
450 $alt = preg_replace("/<[^>]*?>/", "", $alt);
451 $template->setVariable("ATTR", $attr);
452 $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
453 $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
454 $template->parseCurrentBlock();
455 }
456 }
457
458 if ($showInlineFeedback) {
459 $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
460 }
461
462 $template->setCurrentBlock("answer_row");
463 $template->setVariable("QID", $this->object->getId());
464 $template->setVariable("ANSWER_ID", $answer_id);
465 $template->setVariable("ANSWER_TEXT", $this->object->prepareTextareaOutput($answer->getAnswertext(), true));
466 foreach ($user_solution as $mc_solution) {
467 if (strcmp($mc_solution, $answer_id) == 0) {
468 $template->setVariable("CHECKED_ANSWER", " checked=\"checked\"");
469 }
470 }
471 $template->parseCurrentBlock();
472 }
473 if ($this->object->getSelectionLimit()) {
474 $template->setVariable('SELECTION_LIMIT_HINT', sprintf(
475 $this->lng->txt('ass_mc_sel_lim_hint'),
476 $this->object->getSelectionLimit(),
477 $this->object->getAnswerCount()
478 ));
479
480 $template->setVariable('SELECTION_LIMIT_VALUE', $this->object->getSelectionLimit());
481 } else {
482 $template->setVariable('SELECTION_LIMIT_VALUE', 'null');
483 }
484 $template->setVariable("QUESTION_ID", $this->object->getId());
485 $questiontext = $this->object->getQuestionForHTMLOutput();
486 if ($showInlineFeedback && $this->hasInlineFeedback()) {
487 $questiontext .= $this->buildFocusAnchorHtml();
488 }
489 $template->setVariable("QUESTIONTEXT", $this->object->prepareTextareaOutput($questiontext, true));
490 $questionoutput = $template->get();
491 if (!$show_question_only) {
492 // get page object output
493 $questionoutput = $this->getILIASPage($questionoutput);
494 }
495 return $questionoutput;
496 }
497
507 public function getTestOutput(
508 $active_id,
509 // hey: prevPassSolutions - will be always available from now on
510 $pass,
511 // hey.
512 $is_postponed = false,
513 $use_post_solutions = false,
514 $show_feedback = false
515 ): string {
516 // shuffle output
517 $keys = $this->getChoiceKeys();
518
519 // get the solution of the user for the active pass or from the last pass if allowed
520 $user_solution = array();
521 if ($active_id) {
522 $solutions = $this->object->getTestOutputSolutions($active_id, $pass);
523 // hey.
524 foreach ($solutions as $idx => $solution_value) {
525 // fau: testNav - don't add the dummy entry for 'none of the above' to the user options
526 if ($solution_value["value1"] == 'mc_none_above') {
527 $this->setUseEmptySolutionInputChecked(true);
528 continue;
529 }
530
531 $user_solution[] = $solution_value["value1"];
532 // fau.
533 }
534
535 if (empty($user_solution) && $this->object->getTestPresentationConfig()->isWorkedThrough()) {
536 $this->setUseEmptySolutionInputChecked(true);
537 }
538 }
539 // generate the question output
540 $this->tpl->addJavaScript('Modules/TestQuestionPool/js/ilAssMultipleChoice.js');
541 $this->tpl->addOnLoadCode('ilAssMultipleChoiceCharCounterInit();');
542 include_once "./Services/UICore/classes/class.ilTemplate.php";
543 $template = new ilTemplate("tpl.il_as_qpl_mc_mr_output.html", true, true, "Modules/TestQuestionPool");
544 foreach ($keys as $answer_id) {
545 $answer = $this->object->answers[$answer_id];
546 if (strlen($answer->getImage())) {
547 if ($this->object->getThumbSize()) {
548 $template->setCurrentBlock("preview");
549 $template->setVariable("URL_PREVIEW", $this->object->getImagePathWeb() . $answer->getImage());
550 $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
551 $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('enlarge.svg'));
552 $template->setVariable("ANSWER_IMAGE_URL", $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $answer->getImage());
553 list($width, $height, $type, $attr) = getimagesize($this->object->getImagePath() . $answer->getImage());
554 $alt = $answer->getImage();
555 if (strlen($answer->getAnswertext())) {
556 $alt = $answer->getAnswertext();
557 }
558 $alt = preg_replace("/<[^>]*?>/", "", $alt);
559 $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
560 $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
561 $template->parseCurrentBlock();
562 } else {
563 $template->setCurrentBlock("answer_image");
564 $template->setVariable("ANSWER_IMAGE_URL", $this->object->getImagePathWeb() . $answer->getImage());
565 list($width, $height, $type, $attr) = getimagesize($this->object->getImagePath() . $answer->getImage());
566 $alt = $answer->getImage();
567 if (strlen($answer->getAnswertext())) {
568 $alt = $answer->getAnswertext();
569 }
570 $alt = preg_replace("/<[^>]*?>/", "", $alt);
571 $template->setVariable("ATTR", $attr);
572 $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
573 $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
574 $template->parseCurrentBlock();
575 }
576 }
577
578 if ($show_feedback) {
579 $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
580 }
581
582 $template->setCurrentBlock("answer_row");
583 $template->setVariable("QID", $this->object->getId());
584 $template->setVariable("ANSWER_ID", $answer_id);
585 $template->setVariable("ANSWER_TEXT", $this->object->prepareTextareaOutput($answer->getAnswertext(), true));
586 foreach ($user_solution as $mc_solution) {
587 if (strcmp($mc_solution, $answer_id) == 0) {
588 $template->setVariable("CHECKED_ANSWER", " checked=\"checked\"");
589 }
590 }
591 $template->parseCurrentBlock();
592 }
593
594 $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
595 $template->setVariable("QUESTION_ID", $this->object->getId());
596 if ($this->object->getSelectionLimit()) {
597 $template->setVariable('SELECTION_LIMIT_HINT', sprintf(
598 $this->lng->txt('ass_mc_sel_lim_hint'),
599 $this->object->getSelectionLimit(),
600 $this->object->getAnswerCount()
601 ));
602
603 $template->setVariable('SELECTION_LIMIT_VALUE', $this->object->getSelectionLimit());
604 } else {
605 $template->setVariable('SELECTION_LIMIT_VALUE', 'null');
606 }
607 $questionoutput = $template->get();
608 $pageoutput = $this->outQuestionPage("", $is_postponed, $active_id, $questionoutput, $show_feedback);
609 return $pageoutput;
610 }
611
612 protected $useEmptySolutionInputChecked = false;
613
614 public function isUseEmptySolutionInputChecked(): bool
615 {
616 return $this->useEmptySolutionInputChecked;
617 }
618
619 public function setUseEmptySolutionInputChecked($useEmptySolutionInputChecked): void
620 {
621 $this->useEmptySolutionInputChecked = $useEmptySolutionInputChecked;
622 }
623
624 protected function getUseUnchangedAnswerCheckboxHtml(): string
625 {
626 // hey: prevPassSolutions - use abstracted template to share with other purposes of this kind
627 $this->tpl->addJavaScript('Modules/TestQuestionPool/js/ilAssMultipleChoice.js');
628
629 $tpl = new ilTemplate('tpl.tst_question_additional_behaviour_checkbox.html', true, true, 'Modules/TestQuestionPool');
630
631 // HEY: affects next if (!) /// noneAboveChecked repaired but disabled because the checked input ..
632 if (false) { // .. makes the qstEditController initialize the "edit" instead of the "answered" state
633 if ($this->isUseEmptySolutionInputChecked()) {
634 $tpl->setCurrentBlock('checked');
635 $tpl->touchBlock('checked');
636 $tpl->parseCurrentBlock();
637 }
638 }
639
640 $tpl->setCurrentBlock('checkbox');
641 $tpl->setVariable('TXT_FORCE_FORM_DIFF_LABEL', $this->object->getTestPresentationConfig()->getUseUnchangedAnswerLabel());
642 $tpl->parseCurrentBlock();
643 // hey.
644 return $tpl->get();
645 }
646
647 public function getPresentationJavascripts(): array
648 {
649 return array('Modules/TestQuestionPool/js/ilAssMultipleChoice.js');
650 }
651
657 public function getChoiceKeys(): array
658 {
659 $choiceKeys = array_keys($this->object->answers);
660
661 if ($this->object->getShuffle()) {
662 $choiceKeys = $this->object->getShuffler()->transform($choiceKeys);
663 }
664
665 return $choiceKeys;
666 }
667
668 public function getSpecificFeedbackOutput(array $userSolution): string
669 {
670 // No return value, this question type supports inline specific feedback.
671 $output = "";
672 return $this->object->prepareTextareaOutput($output, true);
673 }
674
676 {
677 $this->object->setShuffle($_POST["shuffle"] ?? '0');
678
679 $selectionLimit = (int) $form->getItemByPostVar('selection_limit')->getValue();
680 $this->object->setSelectionLimit($selectionLimit > 0 ? $selectionLimit : null);
681
682 if (isset($_POST['feedback_setting'])) {
683 $this->object->setSpecificFeedbackSetting($_POST['feedback_setting']);
684 }
685
686 $types = (int) ($_POST['types'] ?? '0');
687 $this->object->setMultilineAnswerSetting($types);
688 if (isset($_POST['choice']['imagename']) && is_array($_POST['choice']['imagename']) && $types === 1) {
689 $this->object->setIsSingleline(true);
690 $this->tpl->setOnScreenMessage('info', $this->lng->txt('info_answer_type_change'), true);
691 } else {
692 $this->object->setIsSingleline(($types === 0) ? true : false);
693 }
694 if (isset($_POST["thumb_size"])) {
695 $this->object->setThumbSize((int) $_POST["thumb_size"]);
696 }
697 }
698
700 {
701 // Delete all existing answers and create new answers from the form data
702 $this->object->flushAnswers();
703 $choice = $this->cleanupAnswerText($_POST['choice'], $this->object->isSingleline() === false);
704 if ($this->object->isSingleline()) {
705 foreach ($choice['answer'] as $index => $answertext) {
706 $answertext = htmlentities($answertext);
707 $picturefile = $choice['imagename'][$index] ?? '';
708 $file_org_name = $_FILES['choice']['name']['image'][$index] ?? '';
709 $file_temp_name = $_FILES['choice']['tmp_name']['image'][$index] ?? '';
710
711 if ($file_temp_name !== '') {
712 // check suffix
713 $parts = explode(".", $file_org_name);
714 $suffix = strtolower(array_pop($parts));
715 if (in_array($suffix, ["jpg", "jpeg", "png", "gif"])) {
716 // upload image
717 $filename = $this->object->buildHashedImageFilename($file_org_name);
718 if ($this->object->setImageFile($filename, $file_temp_name) == 0) {
719 $picturefile = $filename;
720 }
721 }
722 }
723
724 $this->object->addAnswer(
725 $answertext,
726 (float) str_replace(',', '.', $choice['points'][$index]),
727 (float) str_replace(',', '.', $choice['points_unchecked'][$index]),
728 $index,
729 $picturefile,
730 $choice['answer_id'][$index]
731 );
732 }
733 } else {
734 foreach ($choice['answer'] as $index => $answer) {
735 $answertext = $answer;
736 $this->object->addAnswer(
737 $answertext,
738 (float) str_replace(',', '.', $choice['points'][$index]),
739 (float) str_replace(',', '.', $choice['points_unchecked'][$index]),
740 $index,
741 '',
742 (int) $choice['answer_id'][$index]
743 );
744 }
745 }
746 }
747
748 public function populateQuestionSpecificFormPart(\ilPropertyFormGUI $form, bool $is_singleline = false): ilPropertyFormGUI
749 {
750 // shuffle
751 $shuffle = new ilCheckboxInputGUI($this->lng->txt("shuffle_answers"), "shuffle");
752 $shuffle->setValue(1);
753 $shuffle->setChecked($this->object->getShuffle());
754 $shuffle->setRequired(false);
755 $form->addItem($shuffle);
756
757 require_once 'Services/Form/classes/class.ilNumberInputGUI.php';
758 $selLim = new ilNumberInputGUI($this->lng->txt('ass_mc_sel_lim_setting'), 'selection_limit');
759 $selLim->setInfo($this->lng->txt('ass_mc_sel_lim_setting_desc'));
760 $selLim->setSize(2);
761 $selLim->setRequired(false);
762 $selLim->allowDecimals(false);
763 $selLim->setMinvalueShouldBeGreater(false);
764 $selLim->setMaxvalueShouldBeLess(false);
765 $selLim->setMinValue(1);
766 $selLim->setMaxValue($this->object->getAnswerCount());
767 $selLim->setValue($this->object->getSelectionLimit());
768 $form->addItem($selLim);
769
770 if ($this->object->getId()) {
771 $hidden = new ilHiddenInputGUI("ID");
772 $hidden->setValue($this->object->getId());
773 $form->addItem($hidden);
774 }
775
776 if (!$this->object->getSelfAssessmentEditingMode()) {
777 // Answer types
778 $types = new ilSelectInputGUI($this->lng->txt("answer_types"), "types");
779 $types->setRequired(false);
780 $types->setValue(($is_singleline) ? 0 : 1);
781 $types->setOptions([
782 0 => $this->lng->txt('answers_singleline'),
783 1 => $this->lng->txt('answers_multiline'),
784 ]);
785 $form->addItem($types);
786 }
787
788 if ($is_singleline) {
789 // thumb size
790 $thumb_size = new ilNumberInputGUI($this->lng->txt('thumb_size'), "thumb_size");
791 $thumb_size->setSuffix($this->lng->txt('thumb_size_unit_pixel'));
792 $thumb_size->setMinValue($this->object->getMinimumThumbSize());
793 $thumb_size->setMaxValue($this->object->getMaximumThumbSize());
794 $thumb_size->setDecimals(0);
795 $thumb_size->setSize(6);
796 $thumb_size->setInfo($this->lng->txt('thumb_size_info'));
797 $thumb_size->setValue($this->object->getThumbSize());
798 $thumb_size->setRequired(true);
799 } else {
800 $thumb_size = new ilHiddenInputGUI('thumb_size');
801 $thumb_size->setValue($this->object->getThumbSize());
802 }
803 $form->addItem($thumb_size);
804
805 return $form;
806 }
807
808 public function populateAnswerSpecificFormPart(\ilPropertyFormGUI $form, bool $is_singleline = false): ilPropertyFormGUI
809 {
810 // Choices
811 include_once "./Modules/TestQuestionPool/classes/class.ilMultipleChoiceWizardInputGUI.php";
812 $choices = new ilMultipleChoiceWizardInputGUI($this->lng->txt("answers"), "choice");
813 $choices->setRequired(true);
814 $choices->setQuestionObject($this->object);
815 $choices->setSingleline($is_singleline);
816 $choices->setAllowMove(false);
817 if ($this->object->getSelfAssessmentEditingMode()) {
818 $choices->setSize(40);
819 }
820 if ($this->object->getAnswerCount() == 0) {
821 $this->object->addAnswer("", 0, 0, 0);
822 }
823 $choices->setValues(array_map(
824 function (ASS_AnswerMultipleResponseImage $value) {
825 $value->setAnswerText(html_entity_decode($value->getAnswerText()));
826 return $value;
827 },
828 $this->object->getAnswers()
829 ));
830 $form->addItem($choices);
831 return $form;
832 }
833
844 {
845 return array();
846 }
847
858 {
859 return array();
860 }
861
868 public function getAggregatedAnswersView(array $relevant_answers): string
869 {
870 return $this->renderAggregateView(
871 $this->aggregateAnswers($relevant_answers, $this->object->getAnswers())
872 )->get();
873 }
874
875 public function aggregateAnswers($relevant_answers_chosen, $answers_defined_on_question): array
876 {
877 $aggregate = array();
878 foreach ($answers_defined_on_question as $answer) {
879 $aggregated_info_for_answer = array();
880 $aggregated_info_for_answer['answertext'] = $answer->getAnswerText();
881 $aggregated_info_for_answer['count_checked'] = 0;
882
883 foreach ($relevant_answers_chosen as $relevant_answer) {
884 if ($relevant_answer['value1'] == $answer->getOrder()) {
885 $aggregated_info_for_answer['count_checked']++;
886 }
887 }
888 $aggregated_info_for_answer['count_unchecked'] =
889 ceil(count($relevant_answers_chosen) / count($answers_defined_on_question))
890 - $aggregated_info_for_answer['count_checked'];
891
892 $aggregate[] = $aggregated_info_for_answer;
893 }
894 return $aggregate;
895 }
896
902 public function renderAggregateView($aggregate): ilTemplate
903 {
904 $tpl = new ilTemplate('tpl.il_as_aggregated_answers_table.html', true, true, "Modules/TestQuestionPool");
905
906 $tpl->setCurrentBlock('headercell');
907 $tpl->setVariable('HEADER', $this->lng->txt('tst_answer_aggr_answer_header'));
908 $tpl->parseCurrentBlock();
909
910 $tpl->setCurrentBlock('headercell');
911 $tpl->setVariable('HEADER', $this->lng->txt('tst_answer_aggr_frequency_header'));
912 $tpl->parseCurrentBlock();
913
914 foreach ($aggregate as $line_data) {
915 $tpl->setCurrentBlock('aggregaterow');
916 $tpl->setVariable('OPTION', $line_data['answertext']);
917 $tpl->setVariable('COUNT', $line_data['count_checked']);
918 $tpl->parseCurrentBlock();
919 }
920 return $tpl;
921 }
922
923 private function populateSpecificFeedbackInline($user_solution, $answer_id, $template): void
924 {
925 if ($this->object->getSpecificFeedbackSetting() == 2) {
926 foreach ($user_solution as $mc_solution) {
927 if (strcmp($mc_solution, $answer_id) == 0) {
928 $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
929 if (strlen($fb)) {
930 $template->setCurrentBlock("feedback");
931 $template->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($fb, true));
932 $template->parseCurrentBlock();
933 }
934 }
935 }
936 }
937
938 if ($this->object->getSpecificFeedbackSetting() == 1) {
939 $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
940 if (strlen($fb)) {
941 $template->setCurrentBlock("feedback");
942 $template->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($fb, true));
943 $template->parseCurrentBlock();
944 }
945 }
946
947 if ($this->object->getSpecificFeedbackSetting() == 3) {
948 $answer = $this->object->getAnswer($answer_id);
949
950 if ($answer->getPoints() > 0) {
951 $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
952 if (strlen($fb)) {
953 $template->setCurrentBlock("feedback");
954 $template->setVariable("FEEDBACK", $this->object->prepareTextareaOutput($fb, true));
955 $template->parseCurrentBlock();
956 }
957 }
958 }
959 }
960
961 // fau: testNav - new functions setWithNoneAbove() and setIsAnswered()
962 // moved functionality to ilTestQuestionPresentationConfig
963 // fau.
964
968 protected function buildEditForm(bool $is_singleline = true): ilPropertyFormGUI
969 {
970 include_once("./Services/Form/classes/class.ilPropertyFormGUI.php");
971 $form = new ilPropertyFormGUI();
972 $form->setFormAction($this->ctrl->getFormAction($this));
973 $form->setTitle($this->outQuestionType());
974 $form->setTableWidth("100%");
975 $form->setId("assmultiplechoice");
976
977 $this->addBasicQuestionFormProperties($form);
978 $this->populateQuestionSpecificFormPart($form, $is_singleline);
979 $this->populateAnswerSpecificFormPart($form, $is_singleline);
980 $this->populateTaxonomyFormSection($form);
981 $this->addQuestionFormCommandButtons($form);
982 return $form;
983 }
984
985 public function getAnswersFrequency($relevantAnswers, $questionIndex): array
986 {
987 $agg = $this->aggregateAnswers($relevantAnswers, $this->object->getAnswers());
988
989 $answers = array();
990
991 foreach ($agg as $ans) {
992 $answers[] = array(
993 'answer' => $ans['answertext'],
994 'frequency' => $ans['count_checked']
995 );
996 }
997
998 return $answers;
999 }
1000
1002 {
1003 require_once 'Modules/TestQuestionPool/classes/forms/class.ilAssMultipleChoiceCorrectionsInputGUI.php';
1004 $choices = new ilAssMultipleChoiceCorrectionsInputGUI($this->lng->txt("answers"), "choice");
1005 $choices->setRequired(true);
1006 $choices->setQuestionObject($this->object);
1007 $choices->setValues($this->object->getAnswers());
1008 $form->addItem($choices);
1009 }
1010
1015 {
1016 $input = $form->getItemByPostVar('choice');
1017 $answerElements = $input->getValues();
1018
1019 foreach ($this->object->getAnswers() as $index => $answer) {
1020 /* @var ASS_AnswerMultipleResponseImage $answer */
1021 $answer->setPointsChecked((float) str_replace(',', '.', $answerElements[$index]->getPointsChecked()));
1022 $answer->setPointsUnchecked((float) str_replace(',', '.', $answerElements[$index]->getPointsUnchecked()));
1023 }
1024 }
1025}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
$filename
Definition: buildRTE.php:78
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
return true
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getSpecificFeedbackOutput(array $userSolution)
Returns the answer specific feedback for the question.
populateQuestionSpecificFormPart(\ilPropertyFormGUI $form, bool $is_singleline=false)
writePostData(bool $always=false)
{Evaluates a posted edit form and writes the form data in the question object.integer A positive valu...
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
setUseEmptySolutionInputChecked($useEmptySolutionInputChecked)
getTestOutput( $active_id, $pass, $is_postponed=false, $use_post_solutions=false, $show_feedback=false)
getChoiceKeys()
Create the key index numbers for the array of choices.
populateAnswerSpecificFormPart(\ilPropertyFormGUI $form, bool $is_singleline=false)
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
aggregateAnswers($relevant_answers_chosen, $answers_defined_on_question)
populateSpecificFeedbackInline($user_solution, $answer_id, $template)
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
buildEditForm(bool $is_singleline=true)
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from $_POST and applies them to the data object.
getPreview($show_question_only=false, $showInlineFeedback=false)
getEditAnswersSingleLine($checkonly=false)
Get the single/multiline editing of answers.
__construct($id=-1)
assMultipleChoiceGUI constructor
getAnswersFrequency($relevantAnswers, $questionIndex)
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
addBasicQuestionFormProperties(ilPropertyFormGUI $form)
getAggregatedAnswersView(array $relevant_answers)
Returns an html string containing a question specific representation of the answers so far given in t...
editQuestion($checkonly=false)
Creates an output of the edit form for the question.
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.
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...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getILIASPage(string $html="")
Returns the ILIAS Page around a question.
getGenericFeedbackOutput(int $active_id, ?int $pass)
hasCorrectSolution($activeId, $passIndex)
generateCorrectnessIconsForCorrectness(int $correctness)
This class represents a checkbox property in a property form.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static prepareFormOutput($a_str, bool $a_strip=false)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This class represents a number property in a property form.
This class represents a property form user interface.
getItemByPostVar(string $a_post_var)
This class represents a selection list property in a property form.
special template class to simplify handling of ITX/PEAR
static getHtmlPath(string $relative_path)
get url of path
static getImagePath(string $img, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
$errors
Definition: imgupload.php:65
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
if($DIC->http() ->request() ->getMethod()=="GET" &&isset($DIC->http() ->request() ->getQueryParams()['tex'])) $tpl
Definition: latex.php:41
if($clientAssertionType !='urn:ietf:params:oauth:client-assertion-type:jwt-bearer'|| $grantType !='client_credentials') $parts
Definition: ltitoken.php:64
$index
Definition: metadata.php:145
$keys
Definition: metadata.php:204
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
$type