ILIAS  trunk Revision v12.0_alpha-377-g3641b37b9db
class.assKprimChoiceGUI.php
Go to the documentation of this file.
1<?php
2
28{
29 private bool $rebuild_thumbnails = false;
31
35 public function __construct($qId = -1)
36 {
38
39 $this->object = new assKprimChoice();
40
41 if ($qId > 0) {
42 $this->object->loadFromDb($qId);
43 }
44 }
45
49 public function hasInlineFeedback(): bool
50 {
51 return $this->object->feedbackOBJ->isSpecificAnswerFeedbackAvailable($this->object->getId());
52 }
53
54 protected function getAdditionalEditQuestionCommands(): array
55 {
56 return ['uploadImage', 'removeImage'];
57 }
58
59 public function editQuestion(
60 bool $checkonly = false,
61 ?bool $is_save_cmd = null
62 ): bool {
63 $form = $this->edit_form;
64 if ($form === null) {
65 $form = $this->buildEditForm();
66 }
67
68 $this->renderEditForm($form);
69 return false;
70 }
71
72 public function uploadImage(): void
73 {
74 $this->setAdditionalContentEditingModeFromPost();
75 if ($this->writePostData(true) === 0) {
76 $this->object->saveToDb();
77 $this->editQuestion();
78 }
79 }
80
81 public function removeImage(): void
82 {
83 $this->object->removeAnswerImage($this->request_data_collector->getCmdIndex('removeImage'));
84 $this->object->saveToDb();
85 $this->editQuestion();
86 }
87
88 public function downkprimanswers(): void
89 {
90 $index = $this->request_data_collector->getCmdIndex(__FUNCTION__);
91 if (!empty($index)) {
92 $this->object->moveAnswerDown($index);
93 $this->object->saveToDb();
94 }
95
96 $this->editQuestion();
97 }
98
99 public function upkprimanswers(): void
100 {
101 $index = $this->request_data_collector->getCmdIndex(__FUNCTION__);
102 if (!empty($index)) {
103 $this->object->moveAnswerUp($index);
104 $this->object->saveToDb();
105 }
106
107 $this->editQuestion();
108 }
109
113 protected function writePostData(bool $always = false): int
114 {
115 $form = $this->buildEditForm();
116 $form->setValuesByPost();
117 $answers_input = $form->getItemByPostVar('kprimanswers');
118
119 if ($always && $answers_input instanceof ilFormPropertyGUI) {
120 $answers_input->setIgnoreMissingUploadsEnabled(true);
121 $answer_input_postvar = $this->request_data_collector->strArray($answers_input->getPostVar(), 2);
122
123 if (!$answers_input->checkUploads($answer_input_postvar)) {
124 $this->tpl->setOnScreenMessage('failure', $this->lng->txt('form_input_not_valid'));
125 $this->edit_form = $form;
126 $this->editQuestion();
127 return 1;
128 }
129
130 $answers_input->collectValidFiles();
131 } elseif (!$form->checkInput()) {
132 $this->edit_form = $form;
133 $this->editQuestion();
134 return 1;
135 }
136
137 $this->writeQuestionGenericPostData();
138
139 $this->writeQuestionSpecificPostData($form);
140 $this->writeAnswerSpecificPostData($form);
141
142 $this->saveTaxonomyAssignments();
143
144 return 0;
145 }
146
150 protected function buildEditForm(): ilPropertyFormGUI
151 {
152 $form = $this->buildBasicEditFormObject();
153
154 $this->addQuestionFormCommandButtons($form);
155
156 $this->addBasicQuestionFormProperties($form);
157
158 $answer_type = $this->request_data_collector->string('answer_type') ?: null;
159 $this->populateQuestionSpecificFormPart($form, $answer_type);
160 $this->populateAnswerSpecificFormPart($form, $answer_type);
161
162 $this->populateTaxonomyFormSection($form);
163
164 return $form;
165 }
166
167 public function populateQuestionSpecificFormPart(ilPropertyFormGUI $form, ?string $answer_type = null): ilPropertyFormGUI
168 {
169 // shuffle answers
170 $shuffleAnswers = new ilCheckboxInputGUI($this->lng->txt("shuffle_answers"), "shuffle_answers_enabled");
171 $shuffleAnswers->setChecked($this->object->isShuffleAnswersEnabled());
172 $form->addItem($shuffleAnswers);
173
174 $answer_type ??= $this->object->getAnswerType();
175 if (!$this->object->getSelfAssessmentEditingMode()) {
176 // answer mode (single-/multi-line)
177 $answerType = new ilSelectInputGUI($this->lng->txt('answer_types'), 'answer_type');
178 $answerType->setOptions($this->object->getAnswerTypeSelectOptions($this->lng));
179 $answerType->setValue($answer_type);
180 $form->addItem($answerType);
181 }
182
183 if (!$this->object->getSelfAssessmentEditingMode() && $this->object->isSingleLineAnswerType($answer_type)) {
184 // thumb size
185 $thumb_size = new ilNumberInputGUI($this->lng->txt('thumb_size'), 'thumb_size');
186 $thumb_size->setSuffix($this->lng->txt('thumb_size_unit_pixel'));
187 $thumb_size->setInfo($this->lng->txt('thumb_size_info'));
188 $thumb_size->setDecimals(false);
189 $thumb_size->setMinValue($this->object->getMinimumThumbSize());
190 $thumb_size->setMaxValue($this->object->getMaximumThumbSize());
191 $thumb_size->setSize(6);
192 $thumb_size->setValue($this->object->getThumbSize());
193 } else {
194 $thumb_size = new ilHiddenInputGUI('thumb_size');
195 $thumb_size->setValue($this->object->getThumbSize());
196 }
197 $form->addItem($thumb_size);
198
199 // option label
200 $optionLabel = new ilRadioGroupInputGUI($this->lng->txt('option_label'), 'option_label');
201 $optionLabel->setInfo($this->lng->txt('option_label_info'));
202 $optionLabel->setRequired(true);
203 $optionLabel->setValue($this->object->getOptionLabel());
204 foreach ($this->object->getValidOptionLabelsTranslated($this->lng) as $labelValue => $labelText) {
205 $option = new ilRadioOption($labelText, $labelValue);
206 $optionLabel->addOption($option);
207
208 if ($this->object->isCustomOptionLabel($labelValue)) {
209 $customLabelTrue = new ilTextInputGUI(
210 $this->lng->txt('option_label_custom_true'),
211 'option_label_custom_true'
212 );
213 $customLabelTrue->setValue($this->object->getCustomTrueOptionLabel());
214 $option->addSubItem($customLabelTrue);
215
216 $customLabelFalse = new ilTextInputGUI(
217 $this->lng->txt('option_label_custom_false'),
218 'option_label_custom_false'
219 );
220 $customLabelFalse->setValue($this->object->getCustomFalseOptionLabel());
221 $option->addSubItem($customLabelFalse);
222 }
223 }
224 $form->addItem($optionLabel);
225
226 // points
227 $points = new ilNumberInputGUI($this->lng->txt('points'), 'points');
228 $points->setRequired(true);
229 $points->setSize(3);
230 $points->allowDecimals(true);
231 $points->setMinValue(0);
232 $points->setMinvalueShouldBeGreater(true);
233 $points->setValue($this->object->getPoints());
234 $form->addItem($points);
235
236 // score partial solution
237 $scorePartialSolution = new ilCheckboxInputGUI($this->lng->txt('score_partsol_enabled'), 'score_partsol_enabled');
238 $scorePartialSolution->setInfo($this->lng->txt('score_partsol_enabled_info'));
239 $scorePartialSolution->setChecked($this->object->isScorePartialSolutionEnabled());
240 $form->addItem($scorePartialSolution);
241
242 return $form;
243 }
244
249 {
250 $old_answer_type = $this->object->getAnswerType();
251
252 $this->object->setShuffleAnswersEnabled($form->getItemByPostVar('shuffle_answers_enabled')->getChecked());
253
254 if (!$this->object->getSelfAssessmentEditingMode()) {
255 $this->object->setAnswerType($form->getItemByPostVar('answer_type')->getValue());
256 }
257
258 if (!$this->object->getSelfAssessmentEditingMode() && $this->object->isSingleLineAnswerType($old_answer_type)) {
259 $thumbsize = (int) ($form->getItemByPostVar('thumb_size')->getValue() ?? $this->object->getThumbSize());
260 if ($thumbsize !== $this->object->getThumbSize()) {
261 $this->object->setThumbSize($thumbsize);
262 $this->rebuild_thumbnails = true;
263 }
264 }
265
266 $this->object->setOptionLabel($form->getItemByPostVar('option_label')->getValue());
267
268 if ($this->object->isCustomOptionLabel($this->object->getOptionLabel())) {
269 $this->object->setCustomTrueOptionLabel(strip_tags(
270 $form->getItemByPostVar('option_label_custom_true')->getValue()
271 ));
272 $this->object->setCustomFalseOptionLabel(strip_tags(
273 $form->getItemByPostVar('option_label_custom_false')->getValue()
274 ));
275 }
276
277 $this->object->setPoints($form->getItemByPostVar('points')->getValue());
278
279 $this->object->setScorePartialSolutionEnabled($form->getItemByPostVar('score_partsol_enabled')->getChecked());
280 }
281
282 public function populateAnswerSpecificFormPart(ilPropertyFormGUI $form, ?string $answer_type = null): ilPropertyFormGUI
283 {
284 $answer_type ??= $this->object->getAnswerType();
285
286 $answers = new ilKprimChoiceWizardInputGUI($this->lng->txt('answers'), 'kprimanswers');
287 $answers->setInfo($this->lng->txt('kprim_answers_info') . ' ' . $this->lng->txt('latex_edit_info'));
288 $answers->setSize(64);
289 $answers->setRequired(true);
290 $answers->setAllowMove(true);
291 $answers->setQuestionObject($this->object);
292 $answers->setSingleline($this->object->isSingleLineAnswerType($answer_type));
293 $answers->setValues($this->object->getAnswers());
294 $form->addItem($answers);
295
296 return $form;
297 }
298
303 {
304 $answers = $this->handleAnswerTextsSubmit(
305 $form->getItemByPostVar('kprimanswers')->getValues()
306 );
307 $files = $form->getItemByPostVar('kprimanswers')->getFiles();
308
309 $this->object->handleFileUploads($answers, $files);
310
311 if ($this->rebuild_thumbnails) {
312 $answers = $this->object->rebuildThumbnails(
313 $this->object->getAnswerType(),
314 $this->object->getThumbSize(),
315 $this->object->getImagePath(),
316 $answers
317 );
318 }
319
320 $this->object->setAnswers($answers);
321 }
322
323 private function handleAnswerTextsSubmit($answers)
324 {
325 if ($this->object->getAnswerType() == assKprimChoice::ANSWER_TYPE_MULTI_LINE) {
326 return $answers;
327 }
328
329 foreach ($answers as $key => $answer) {
330 $answer->setAnswerText(ilUtil::secureString(htmlspecialchars($answer->getAnswerText())));
331 }
332
333 return $answers;
334 }
335
341 public function getSpecificFeedbackOutput(array $userSolution): string
342 {
343 return ''; // question type supports inline answer specific feedback
344 }
345
355 public function getTestOutput(
356 int $active_id,
357 int $pass,
358 bool $is_question_postponed = false,
359 array|bool $user_post_solutions = false,
360 bool $show_specific_inline_feedback = false
361 ): string {
362 // shuffle output
363 $keys = $this->getParticipantsAnswerKeySequence();
364
365 // get the solution of the user for the active pass or from the last pass if allowed
366 $user_solution = [];
367 if ($active_id) {
368 $solutions = $this->object->getTestOutputSolutions($active_id, $pass);
369 // hey.
370 foreach ($solutions as $idx => $solution_value) {
371 $user_solution[$solution_value["value1"]] = $solution_value["value2"];
372 }
373 }
374
375 $template = new ilTemplate("tpl.il_as_qpl_mc_kprim_output.html", true, true, "components/ILIAS/TestQuestionPool");
376
377 foreach ($keys as $answer_id) {
378 $answer = $this->object->getAnswer($answer_id);
379 if ($answer->getImageFile() !== null
380 && $answer->getImageFile() !== '') {
381 if ($this->object->getThumbSize()) {
382 $template->setCurrentBlock("preview");
383 $template->setVariable("URL_PREVIEW", $answer->getImageWebPath());
384 $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
385 $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('media/enlarge.svg'));
386 $template->setVariable("ANSWER_IMAGE_URL", $answer->getThumbWebPath());
387 [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
388 $alt = $answer->getImageFile();
389 if (strlen($answer->getAnswertext())) {
390 $alt = $answer->getAnswertext();
391 }
392 $alt = preg_replace("/<[^>]*?>/", "", $alt);
393 $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
394 $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
395 $template->parseCurrentBlock();
396 } else {
397 $template->setCurrentBlock("answer_image");
398 $template->setVariable("ANSWER_IMAGE_URL", $answer->getImageWebPath());
399 [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
400 $alt = $answer->getImageFile();
401 if (strlen($answer->getAnswertext())) {
402 $alt = $answer->getAnswertext();
403 }
404 $alt = preg_replace("/<[^>]*?>/", "", $alt);
405 $template->setVariable("ATTR", $attr);
406 $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
407 $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
408 $template->parseCurrentBlock();
409 }
410 }
411
412 if ($show_specific_inline_feedback) {
413 $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
414 }
415
416 $template->setCurrentBlock("answer_row");
417 $template->setVariable("ANSWER_ID", $answer_id);
418 $template->setVariable("ANSWER_TEXT", $this->renderLatex(
419 ilLegacyFormElementsUtil::prepareTextareaOutput($answer->getAnswertext(), true)
420 ));
421 $template->setVariable('VALUE_TRUE', 1);
422 $template->setVariable('VALUE_FALSE', 0);
423
424 if (isset($user_solution[$answer->getPosition()])) {
425 $tplVar = $user_solution[$answer->getPosition()] ? 'CHECKED_ANSWER_TRUE' : 'CHECKED_ANSWER_FALSE';
426 $template->setVariable($tplVar, " checked=\"checked\"");
427 }
428
429 $template->parseCurrentBlock();
430 }
431
432 $template->setVariable("QUESTIONTEXT", $this->renderLatex($this->object->getQuestionForHTMLOutput()));
433 $template->setVariable("INSTRUCTIONTEXT", $this->object->getInstructionTextTranslation(
434 $this->lng,
435 $this->object->getOptionLabel()
436 ));
437
438 $template->setVariable("OPTION_LABEL_TRUE", $this->object->getTrueOptionLabelTranslation(
439 $this->lng,
440 $this->object->getOptionLabel()
441 ));
442
443 $template->setVariable("OPTION_LABEL_FALSE", $this->object->getFalseOptionLabelTranslation(
444 $this->lng,
445 $this->object->getOptionLabel()
446 ));
447
448 $questionoutput = $template->get();
449 $pageoutput = $this->outQuestionPage("", $is_question_postponed, $active_id, $questionoutput, $show_specific_inline_feedback);
450 return $pageoutput;
451 }
452
453 public function getPreview(
454 bool $show_question_only = false,
455 bool $show_inline_feedback = false
456 ): string {
457 $user_solution = is_object($this->getPreviewSession()) ? (array) $this->getPreviewSession()->getParticipantsSolution() : [];
458 // shuffle output
459 $keys = $this->getParticipantsAnswerKeySequence();
460
461 $template = new ilTemplate("tpl.il_as_qpl_mc_kprim_output.html", true, true, "components/ILIAS/TestQuestionPool");
462
463 foreach ($keys as $answer_id) {
464 $answer = $this->object->getAnswer($answer_id);
465 if ($answer->getImageFile() !== null
466 && $answer->getImageFile() !== '') {
467 if ($this->object->getThumbSize()) {
468 $template->setCurrentBlock("preview");
469 $template->setVariable("URL_PREVIEW", $answer->getImageWebPath());
470 $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
471 $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('media/enlarge.svg'));
472 $template->setVariable("ANSWER_IMAGE_URL", $answer->getThumbWebPath());
473 [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
474 $alt = $answer->getImageFile();
475 if (strlen($answer->getAnswertext())) {
476 $alt = $answer->getAnswertext();
477 }
478 $alt = preg_replace("/<[^>]*?>/", "", $alt);
479 $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
480 $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
481 $template->parseCurrentBlock();
482 } else {
483 $template->setCurrentBlock("answer_image");
484 $template->setVariable("ANSWER_IMAGE_URL", $answer->getImageWebPath());
485 [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
486 $alt = $answer->getImageFile();
487 if (strlen($answer->getAnswertext())) {
488 $alt = $answer->getAnswertext();
489 }
490 $alt = preg_replace("/<[^>]*?>/", "", $alt);
491 $template->setVariable("ATTR", $attr);
492 $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
493 $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
494 $template->parseCurrentBlock();
495 }
496 }
497
498 if ($show_inline_feedback) {
499 $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
500 }
501
502 $template->setCurrentBlock("answer_row");
503 $template->setVariable("ANSWER_ID", $answer_id);
504 $template->setVariable("ANSWER_TEXT", $this->renderLatex(
505 ilLegacyFormElementsUtil::prepareTextareaOutput((string) $answer->getAnswertext(), true)
506 ));
507 $template->setVariable('VALUE_TRUE', 1);
508 $template->setVariable('VALUE_FALSE', 0);
509
510 if (isset($user_solution[$answer->getPosition()])) {
511 $tplVar = $user_solution[$answer->getPosition()] ? 'CHECKED_ANSWER_TRUE' : 'CHECKED_ANSWER_FALSE';
512 $template->setVariable($tplVar, " checked=\"checked\"");
513 }
514
515 $template->parseCurrentBlock();
516 }
517 $questiontext = $this->object->getQuestionForHTMLOutput();
518 if ($show_inline_feedback && $this->hasInlineFeedback()) {
519 $questiontext .= $this->buildFocusAnchorHtml();
520 }
521 $template->setVariable("QUESTIONTEXT", $this->renderLatex(
523 ));
524
525 $template->setVariable("INSTRUCTIONTEXT", $this->object->getInstructionTextTranslation(
526 $this->lng,
527 $this->object->getOptionLabel()
528 ));
529
530 $template->setVariable("OPTION_LABEL_TRUE", $this->object->getTrueOptionLabelTranslation(
531 $this->lng,
532 $this->object->getOptionLabel()
533 ));
534
535 $template->setVariable("OPTION_LABEL_FALSE", $this->object->getFalseOptionLabelTranslation(
536 $this->lng,
537 $this->object->getOptionLabel()
538 ));
539
540 $questionoutput = $template->get();
541 if (!$show_question_only) {
542 // get page object output
543 $questionoutput = $this->getILIASPage($questionoutput);
544 }
545 return $questionoutput;
546 }
547
548 public function getSolutionOutput(
549 int $active_id,
550 ?int $pass = null,
551 bool $graphical_output = false,
552 bool $result_output = false,
553 bool $show_question_only = true,
554 bool $show_feedback = false,
555 bool $show_correct_solution = false,
556 bool $show_manual_scoring = false,
557 bool $show_question_text = true,
558 bool $show_inline_feedback = true
559 ): string {
560 $user_solution = [];
561
562 if (($active_id > 0) && (!$show_correct_solution)) {
563 $solutions = $this->object->getSolutionValues($active_id, $pass);
564 foreach ($solutions as $idx => $solution_value) {
565 //$user_solution[$solution_value['value1']] = $solution_value['value2'];
566 $user_solution[] = [
567 'value1' => $solution_value['value1'],
568 'value2' => $solution_value['value2']
569 ];
570 }
571 } else {
572 // take the correct solution instead of the user solution
573 foreach ($this->object->getAnswers() as $answer) {
574 //$user_solution[$answer->getPosition()] = $answer->getCorrectness();
575 $user_solution[] = [
576 'value1' => $answer->getPosition(),
577 'value2' => $answer->getCorrectness()
578 ];
579 }
580 }
581
582 return $this->renderSolutionOutput(
583 $user_solution,
584 $active_id,
585 $pass,
586 $graphical_output,
587 $result_output,
588 $show_question_only,
589 $show_feedback,
590 $show_correct_solution,
591 $show_manual_scoring,
592 $show_question_text,
593 false,
594 $show_inline_feedback
595 );
596 }
597
598 public function renderSolutionOutput(
599 mixed $user_solutions,
600 int $active_id,
601 ?int $pass,
602 bool $graphical_output = false,
603 bool $result_output = false,
604 bool $show_question_only = true,
605 bool $show_feedback = false,
606 bool $show_correct_solution = false,
607 bool $show_manual_scoring = false,
608 bool $show_question_text = true,
609 bool $show_autosave_title = false,
610 bool $show_inline_feedback = false,
611 ): ?string {
612
613 $user_solution = [];
614 foreach ($user_solutions as $idx => $solution_value) {
615 $user_solution[$solution_value['value1']] = $solution_value['value2'];
616 }
617 $template = new ilTemplate("tpl.il_as_qpl_mc_kprim_output_solution.html", true, true, "components/ILIAS/TestQuestionPool");
618 $keys = $this->getParticipantsAnswerKeySequence();
619 foreach ($keys as $answer_id) {
620 $answer = $this->object->getAnswer($answer_id);
621
622 if (($active_id > 0) &&
623 !$show_correct_solution &&
624 $graphical_output) {
625 $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_NOT_OK);
626 if (isset($user_solution[$answer->getPosition()]) && $user_solution[$answer->getPosition()] == $answer->getCorrectness()) {
627 $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_OK);
628 }
629 $template->setCurrentBlock("icon_ok");
630 $template->setVariable("ICON_OK", $correctness_icon);
631 $template->parseCurrentBlock();
632 }
633 if ($answer->getImageFile() !== null
634 && $answer->getImageFile() !== '') {
635 $template->setCurrentBlock("answer_image");
636 if ($this->object->getThumbSize()) {
637 $template->setVariable("ANSWER_IMAGE_URL", $answer->getThumbWebPath());
638 } else {
639 $template->setVariable("ANSWER_IMAGE_URL", $answer->getImageWebPath());
640 }
641
642 $template->setVariable(
643 "ANSWER_IMAGE_ALT",
645 $answer->getImageFile()
646 )
647 );
648 $template->setVariable(
649 "ANSWER_IMAGE_TITLE",
651 $answer->getImageFile()
652 )
653 );
654 $template->parseCurrentBlock();
655 }
656
657 if ($show_feedback) {
658 $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
659 }
660
661 $template->setCurrentBlock("answer_row");
662 $template->setVariable("ANSWER_TEXT", $this->renderLatex(
663 ilLegacyFormElementsUtil::prepareTextareaOutput($answer->getAnswertext(), true)
664 ));
665
666 if ($this->renderPurposeSupportsFormHtml() || $this->isRenderPurposePrintPdf()) {
667 if (isset($user_solution[$answer->getPosition()])) {
668 if ($user_solution[$answer->getPosition()]) {
669 $template->setVariable("SOLUTION_IMAGE_TRUE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_checked.png")));
670 $template->setVariable("SOLUTION_ALT_TRUE", $this->lng->txt("checked"));
671 $template->setVariable("SOLUTION_IMAGE_FALSE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
672 $template->setVariable("SOLUTION_ALT_FALSE", $this->lng->txt("unchecked"));
673 } else {
674 $template->setVariable("SOLUTION_IMAGE_TRUE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
675 $template->setVariable("SOLUTION_ALT_TRUE", $this->lng->txt("unchecked"));
676 $template->setVariable("SOLUTION_IMAGE_FALSE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_checked.png")));
677 $template->setVariable("SOLUTION_ALT_FALSE", $this->lng->txt("checked"));
678 }
679 } else {
680 $template->setVariable("SOLUTION_IMAGE_TRUE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
681 $template->setVariable("SOLUTION_ALT_TRUE", $this->lng->txt("unchecked"));
682 $template->setVariable("SOLUTION_IMAGE_FALSE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
683 $template->setVariable("SOLUTION_ALT_FALSE", $this->lng->txt("unchecked"));
684 }
685 } else {
686 $template->setVariable('SOL_QID', $this->object->getId());
687 $template->setVariable('SOL_SUFFIX', $show_correct_solution ? 'bestsolution' : 'usersolution');
688 $template->setVariable('SOL_POSITION', $answer->getPosition());
689
690 $template->setVariable('SOL_TRUE_VALUE', 1);
691 $template->setVariable('SOL_FALSE_VALUE', 0);
692
693 if (isset($user_solution[$answer->getPosition()])) {
694 if ($user_solution[$answer->getPosition()]) {
695 $template->setVariable('SOL_TRUE_CHECKED', 'checked');
696 } else {
697 $template->setVariable('SOL_FALSE_CHECKED', 'checked');
698 }
699 }
700 }
701
702 $template->parseCurrentBlock();
703 }
704
705 if ($show_question_text == true) {
706 $questiontext = $this->object->getQuestionForHTMLOutput();
707 if ($show_feedback && $this->hasInlineFeedback()) {
708 $questiontext .= $this->buildFocusAnchorHtml();
709 }
710 $template->setVariable("QUESTIONTEXT", ilLegacyFormElementsUtil::prepareTextareaOutput($questiontext, true));
711
712 $template->setVariable("INSTRUCTIONTEXT", $this->object->getInstructionTextTranslation(
713 $this->lng,
714 $this->object->getOptionLabel()
715 ));
716 }
717
718 $template->setVariable("OPTION_LABEL_TRUE", $this->object->getTrueOptionLabelTranslation(
719 $this->lng,
720 $this->object->getOptionLabel()
721 ));
722
723 $template->setVariable("OPTION_LABEL_FALSE", $this->object->getFalseOptionLabelTranslation(
724 $this->lng,
725 $this->object->getOptionLabel()
726 ));
727
728
729 $questionoutput = $template->get();
730 $feedback = ($show_feedback && !$this->isTestPresentationContext()) ? $this->getGenericFeedbackOutput((int) $active_id, $pass) : "";
731
732 $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "components/ILIAS/TestQuestionPool");
733
734 if (strlen($feedback)) {
735 $cssClass = (
736 $this->hasCorrectSolution($active_id, $pass) ?
738 );
739
740 $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
741 $solutiontemplate->setVariable("FEEDBACK", ilLegacyFormElementsUtil::prepareTextareaOutput($feedback, true));
742 }
743
744 $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
745
746 $solutionoutput = $solutiontemplate->get();
747
748 if (!$show_question_only) {
749 // get page object output
750 $solutionoutput = $this->getILIASPage($solutionoutput);
751 }
752 return $solutionoutput;
753 }
754
756 {
757 $choice_keys = array_keys($this->object->getAnswers());
758
759 if ($this->object->isShuffleAnswersEnabled()) {
760 $choice_keys = $this->object->getShuffler()->transform($choice_keys);
761 }
762
763 return $choice_keys;
764 }
765
766 private function populateSpecificFeedbackInline($user_solution, $answer_id, $template): void
767 {
768 if ($this->object->getSpecificFeedbackSetting() == ilAssConfigurableMultiOptionQuestionFeedback::FEEDBACK_SETTING_CHECKED) {
769 if (isset($user_solution[$answer_id])) {
770 $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
771 if (strlen($fb)) {
772 $template->setCurrentBlock("feedback");
773 $template->setVariable("FEEDBACK", $this->renderLatex(
775 ));
776 $template->parseCurrentBlock();
777 }
778 }
779 }
780
781 if ($this->object->getSpecificFeedbackSetting() == ilAssConfigurableMultiOptionQuestionFeedback::FEEDBACK_SETTING_ALL) {
782 $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
783 if (strlen($fb)) {
784 $template->setCurrentBlock("feedback");
785 $template->setVariable("FEEDBACK", $this->renderLatex(
787 ));
788 $template->parseCurrentBlock();
789 }
790 }
791
792 if ($this->object->getSpecificFeedbackSetting() == ilAssConfigurableMultiOptionQuestionFeedback::FEEDBACK_SETTING_CORRECT) {
793 $answer = $this->object->getAnswer($answer_id);
794
795 if ($answer->getCorrectness()) {
796 $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
797 if (strlen($fb)) {
798 $template->setCurrentBlock("feedback");
799 $template->setVariable("FEEDBACK", $this->renderLatex(
801 ));
802 $template->parseCurrentBlock();
803 }
804 }
805 }
806 }
807
818 {
819 return [];
820 }
821
832 {
833 return [];
834 }
835
836 private function aggregateAnswers($rawSolutionData, $answers): array
837 {
838 $aggregate = [];
839
840 foreach ($answers as $answer) {
841 $answerAgg = [
842 'answertext' => $answer->getAnswerText(), 'count_true' => 0, 'count_false' => 0
843 ];
844
845 foreach ($rawSolutionData as $solutionRecord) {
846 if ($solutionRecord['value1'] == $answer->getPosition()) {
847 if ($solutionRecord['value2']) {
848 $answerAgg['count_true']++;
849 } else {
850 $answerAgg['count_false']++;
851 }
852 }
853 }
854
855 $aggregate[] = $answerAgg;
856 }
857
858 return $aggregate;
859 }
860
861 public function getAnswersFrequency($relevantAnswers, $questionIndex): array
862 {
863 $agg = $this->aggregateAnswers($relevantAnswers, $this->object->getAnswers());
864
865 $answers = [];
866
867 foreach ($agg as $ans) {
868 $answers[] = [
869 'answer' => $ans['answertext'],
870 'frequency_true' => $ans['count_true'],
871 'frequency_false' => $ans['count_false']
872 ];
873 }
874
875 return $answers;
876 }
877
885 public function getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex): ilAnswerFrequencyStatisticTableGUI
886 {
887 $table = new ilKprimChoiceAnswerFreqStatTableGUI($parentGui, $parentCmd, $this->object);
888 $table->setQuestionIndex($questionIndex);
889 $table->setData($this->getAnswersFrequency($relevantAnswers, $questionIndex));
890 $table->initColumns();
891
892 return $table;
893 }
894
896 {
897 // points
898 $points = new ilNumberInputGUI($this->lng->txt('points'), 'points');
899 $points->setRequired(true);
900 $points->setSize(3);
901 $points->allowDecimals(true);
902 $points->setMinValue(0);
903 $points->setMinvalueShouldBeGreater(true);
904 $points->setValue($this->object->getPoints());
905 $form->addItem($points);
906
907 // score partial solution
908 $scorePartialSolution = new ilCheckboxInputGUI($this->lng->txt('score_partsol_enabled'), 'score_partsol_enabled');
909 $scorePartialSolution->setInfo($this->lng->txt('score_partsol_enabled_info'));
910 $scorePartialSolution->setChecked($this->object->isScorePartialSolutionEnabled());
911 $form->addItem($scorePartialSolution);
912
913 // answers
914 $kprimAnswers = new ilKprimChoiceCorrectionsInputGUI($this->lng->txt('answers'), 'kprimanswers');
915 $kprimAnswers->setInfo($this->lng->txt('kprim_answers_info'));
916 $kprimAnswers->setSize(64);
917 $kprimAnswers->setMaxLength(1000);
918 $kprimAnswers->setRequired(true);
919 $kprimAnswers->setQuestionObject($this->object);
920 $kprimAnswers->setValues($this->object->getAnswers());
921 $form->addItem($kprimAnswers);
922 }
923
928 {
929 $this->object->setPoints(
930 (float) str_replace(',', '.', $form->getInput('points'))
931 );
932
933 $this->object->setScorePartialSolutionEnabled(
934 (bool) $form->getInput('score_partsol_enabled')
935 );
936
937 $this->object->setAnswers(
938 $form->getItemByPostVar('kprimanswers')->getValues()
939 );
940 }
941}
populateSpecificFeedbackInline($user_solution, $answer_id, $template)
getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex)
populateAnswerSpecificFormPart(ilPropertyFormGUI $form, ?string $answer_type=null)
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
writePostData(bool $always=false)
{Evaluates a posted edit form and writes the form data in the question object.integer A positive valu...
ilPropertyFormGUI $edit_form
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
getAnswersFrequency($relevantAnswers, $questionIndex)
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
getTestOutput(int $active_id, int $pass, bool $is_question_postponed=false, array|bool $user_post_solutions=false, bool $show_specific_inline_feedback=false)
getSpecificFeedbackOutput(array $userSolution)
aggregateAnswers($rawSolutionData, $answers)
editQuestion(bool $checkonly=false, ?bool $is_save_cmd=null)
getPreview(bool $show_question_only=false, bool $show_inline_feedback=false)
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,)
populateQuestionSpecificFormPart(ilPropertyFormGUI $form, ?string $answer_type=null)
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)
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
renderEditForm(ilPropertyFormGUI $form)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This class represents a checkbox property in a property form.
This class represents a property in a property form.
This class represents a hidden form property in a property 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,...
static prepareFormOutput($a_str, bool $a_strip=false)
This class represents a number property in a property form.
This class represents a property form user interface.
getInput(string $a_post_var, bool $ensureValidation=true)
Returns the input of an item, if item provides getInput method and as fallback the value of the HTTP-...
getItemByPostVar(string $a_post_var)
This class represents a property in a property form.
This class represents an option in a radio group.
This class represents a selection list property in a property form.
special template class to simplify handling of ITX/PEAR
This class represents a text property in a property form.
static getHtmlPath(string $relative_path)
get url of path
static getImagePath(string $image_name, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
static secureString(string $a_str, bool $a_strip_html=true, string $a_allow="")
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...
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc