ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
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 $this->populateQuestionSpecificFormPart($form);
159 $this->populateAnswerSpecificFormPart($form);
160
161 $this->populateTaxonomyFormSection($form);
162
163 return $form;
164 }
165
171 {
172 // shuffle answers
173 $shuffleAnswers = new ilCheckboxInputGUI($this->lng->txt("shuffle_answers"), "shuffle_answers_enabled");
174 $shuffleAnswers->setChecked($this->object->isShuffleAnswersEnabled());
175 $form->addItem($shuffleAnswers);
176
177 if (!$this->object->getSelfAssessmentEditingMode()) {
178 // answer mode (single-/multi-line)
179 $answerType = new ilSelectInputGUI($this->lng->txt('answer_types'), 'answer_type');
180 $answerType->setOptions($this->object->getAnswerTypeSelectOptions($this->lng));
181 $answerType->setValue($this->object->getAnswerType());
182 $form->addItem($answerType);
183 }
184
185 if (!$this->object->getSelfAssessmentEditingMode() && $this->object->isSingleLineAnswerType($this->object->getAnswerType())) {
186 // thumb size
187 $thumb_size = new ilNumberInputGUI($this->lng->txt('thumb_size'), 'thumb_size');
188 $thumb_size->setSuffix($this->lng->txt('thumb_size_unit_pixel'));
189 $thumb_size->setInfo($this->lng->txt('thumb_size_info'));
190 $thumb_size->setDecimals(false);
191 $thumb_size->setMinValue($this->object->getMinimumThumbSize());
192 $thumb_size->setMaxValue($this->object->getMaximumThumbSize());
193 $thumb_size->setSize(6);
194 $thumb_size->setValue($this->object->getThumbSize());
195 } else {
196 $thumb_size = new ilHiddenInputGUI('thumb_size');
197 $thumb_size->setValue($this->object->getThumbSize());
198 }
199 $form->addItem($thumb_size);
200
201 // option label
202 $optionLabel = new ilRadioGroupInputGUI($this->lng->txt('option_label'), 'option_label');
203 $optionLabel->setInfo($this->lng->txt('option_label_info'));
204 $optionLabel->setRequired(true);
205 $optionLabel->setValue($this->object->getOptionLabel());
206 foreach ($this->object->getValidOptionLabelsTranslated($this->lng) as $labelValue => $labelText) {
207 $option = new ilRadioOption($labelText, $labelValue);
208 $optionLabel->addOption($option);
209
210 if ($this->object->isCustomOptionLabel($labelValue)) {
211 $customLabelTrue = new ilTextInputGUI(
212 $this->lng->txt('option_label_custom_true'),
213 'option_label_custom_true'
214 );
215 $customLabelTrue->setValue($this->object->getCustomTrueOptionLabel());
216 $option->addSubItem($customLabelTrue);
217
218 $customLabelFalse = new ilTextInputGUI(
219 $this->lng->txt('option_label_custom_false'),
220 'option_label_custom_false'
221 );
222 $customLabelFalse->setValue($this->object->getCustomFalseOptionLabel());
223 $option->addSubItem($customLabelFalse);
224 }
225 }
226 $form->addItem($optionLabel);
227
228 // points
229 $points = new ilNumberInputGUI($this->lng->txt('points'), 'points');
230 $points->setRequired(true);
231 $points->setSize(3);
232 $points->allowDecimals(true);
233 $points->setMinValue(0);
234 $points->setMinvalueShouldBeGreater(true);
235 $points->setValue($this->object->getPoints());
236 $form->addItem($points);
237
238 // score partial solution
239 $scorePartialSolution = new ilCheckboxInputGUI($this->lng->txt('score_partsol_enabled'), 'score_partsol_enabled');
240 $scorePartialSolution->setInfo($this->lng->txt('score_partsol_enabled_info'));
241 $scorePartialSolution->setChecked($this->object->isScorePartialSolutionEnabled());
242 $form->addItem($scorePartialSolution);
243
244 return $form;
245 }
246
251 {
252 $old_answer_type = $this->object->getAnswerType();
253
254 $this->object->setShuffleAnswersEnabled($form->getItemByPostVar('shuffle_answers_enabled')->getChecked());
255
256 if (!$this->object->getSelfAssessmentEditingMode()) {
257 $this->object->setAnswerType($form->getItemByPostVar('answer_type')->getValue());
258 }
259
260 if (!$this->object->getSelfAssessmentEditingMode() && $this->object->isSingleLineAnswerType($old_answer_type)) {
261 $thumbsize = (int) ($form->getItemByPostVar('thumb_size')->getValue() ?? $this->object->getThumbSize());
262 if ($thumbsize !== $this->object->getThumbSize()) {
263 $this->object->setThumbSize($thumbsize);
264 $this->rebuild_thumbnails = true;
265 }
266 }
267
268 $this->object->setOptionLabel($form->getItemByPostVar('option_label')->getValue());
269
270 if ($this->object->isCustomOptionLabel($this->object->getOptionLabel())) {
271 $this->object->setCustomTrueOptionLabel(strip_tags(
272 $form->getItemByPostVar('option_label_custom_true')->getValue()
273 ));
274 $this->object->setCustomFalseOptionLabel(strip_tags(
275 $form->getItemByPostVar('option_label_custom_false')->getValue()
276 ));
277 }
278
279 $this->object->setPoints($form->getItemByPostVar('points')->getValue());
280
281 $this->object->setScorePartialSolutionEnabled($form->getItemByPostVar('score_partsol_enabled')->getChecked());
282 }
283
289 {
290 $answers = new ilKprimChoiceWizardInputGUI($this->lng->txt('answers'), 'kprimanswers');
291 $answers->setInfo($this->lng->txt('kprim_answers_info') . ' ' . $this->lng->txt('latex_edit_info'));
292 $answers->setSize(64);
293 $answers->setRequired(true);
294 $answers->setAllowMove(true);
295 $answers->setQuestionObject($this->object);
296 $answers->setSingleline($this->object->isSingleLineAnswerType($this->object->getAnswerType()));
297 $answers->setValues($this->object->getAnswers());
298 $form->addItem($answers);
299
300 return $form;
301 }
302
307 {
308 $answers = $this->handleAnswerTextsSubmit(
309 $form->getItemByPostVar('kprimanswers')->getValues()
310 );
311 $files = $form->getItemByPostVar('kprimanswers')->getFiles();
312
313 $this->object->handleFileUploads($answers, $files);
314
315 if ($this->rebuild_thumbnails) {
316 $answers = $this->object->rebuildThumbnails(
317 $this->object->getAnswerType(),
318 $this->object->getThumbSize(),
319 $this->object->getImagePath(),
320 $answers
321 );
322 }
323
324 $this->object->setAnswers($answers);
325 }
326
327 private function handleAnswerTextsSubmit($answers)
328 {
329 if ($this->object->getAnswerType() == assKprimChoice::ANSWER_TYPE_MULTI_LINE) {
330 return $answers;
331 }
332
333 foreach ($answers as $key => $answer) {
334 $answer->setAnswerText(ilUtil::secureString(htmlspecialchars($answer->getAnswerText())));
335 }
336
337 return $answers;
338 }
339
345 public function getSpecificFeedbackOutput(array $userSolution): string
346 {
347 return ''; // question type supports inline answer specific feedback
348 }
349
359 public function getTestOutput(
360 int $active_id,
361 int $pass,
362 bool $is_question_postponed = false,
363 array|bool $user_post_solutions = false,
364 bool $show_specific_inline_feedback = false
365 ): string {
366 // shuffle output
367 $keys = $this->getParticipantsAnswerKeySequence();
368
369 // get the solution of the user for the active pass or from the last pass if allowed
370 $user_solution = [];
371 if ($active_id) {
372 $solutions = $this->object->getTestOutputSolutions($active_id, $pass);
373 // hey.
374 foreach ($solutions as $idx => $solution_value) {
375 $user_solution[$solution_value["value1"]] = $solution_value["value2"];
376 }
377 }
378
379 $template = new ilTemplate("tpl.il_as_qpl_mc_kprim_output.html", true, true, "components/ILIAS/TestQuestionPool");
380
381 foreach ($keys as $answer_id) {
382 $answer = $this->object->getAnswer($answer_id);
383 if ($answer->getImageFile() !== null
384 && $answer->getImageFile() !== '') {
385 if ($this->object->getThumbSize()) {
386 $template->setCurrentBlock("preview");
387 $template->setVariable("URL_PREVIEW", $answer->getImageWebPath());
388 $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
389 $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('media/enlarge.svg'));
390 $template->setVariable("ANSWER_IMAGE_URL", $answer->getThumbWebPath());
391 [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
392 $alt = $answer->getImageFile();
393 if (strlen($answer->getAnswertext())) {
394 $alt = $answer->getAnswertext();
395 }
396 $alt = preg_replace("/<[^>]*?>/", "", $alt);
397 $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
398 $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
399 $template->parseCurrentBlock();
400 } else {
401 $template->setCurrentBlock("answer_image");
402 $template->setVariable("ANSWER_IMAGE_URL", $answer->getImageWebPath());
403 [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
404 $alt = $answer->getImageFile();
405 if (strlen($answer->getAnswertext())) {
406 $alt = $answer->getAnswertext();
407 }
408 $alt = preg_replace("/<[^>]*?>/", "", $alt);
409 $template->setVariable("ATTR", $attr);
410 $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
411 $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
412 $template->parseCurrentBlock();
413 }
414 }
415
416 if ($show_specific_inline_feedback) {
417 $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
418 }
419
420 $template->setCurrentBlock("answer_row");
421 $template->setVariable("ANSWER_ID", $answer_id);
422 $template->setVariable("ANSWER_TEXT", $this->renderLatex(
423 ilLegacyFormElementsUtil::prepareTextareaOutput($answer->getAnswertext(), true)
424 ));
425 $template->setVariable('VALUE_TRUE', 1);
426 $template->setVariable('VALUE_FALSE', 0);
427
428 if (isset($user_solution[$answer->getPosition()])) {
429 $tplVar = $user_solution[$answer->getPosition()] ? 'CHECKED_ANSWER_TRUE' : 'CHECKED_ANSWER_FALSE';
430 $template->setVariable($tplVar, " checked=\"checked\"");
431 }
432
433 $template->parseCurrentBlock();
434 }
435
436 $template->setVariable("QUESTIONTEXT", $this->renderLatex($this->object->getQuestionForHTMLOutput()));
437 $template->setVariable("INSTRUCTIONTEXT", $this->object->getInstructionTextTranslation(
438 $this->lng,
439 $this->object->getOptionLabel()
440 ));
441
442 $template->setVariable("OPTION_LABEL_TRUE", $this->object->getTrueOptionLabelTranslation(
443 $this->lng,
444 $this->object->getOptionLabel()
445 ));
446
447 $template->setVariable("OPTION_LABEL_FALSE", $this->object->getFalseOptionLabelTranslation(
448 $this->lng,
449 $this->object->getOptionLabel()
450 ));
451
452 $questionoutput = $template->get();
453 $pageoutput = $this->outQuestionPage("", $is_question_postponed, $active_id, $questionoutput, $show_specific_inline_feedback);
454 return $pageoutput;
455 }
456
457 public function getPreview(
458 bool $show_question_only = false,
459 bool $show_inline_feedback = false
460 ): string {
461 $user_solution = is_object($this->getPreviewSession()) ? (array) $this->getPreviewSession()->getParticipantsSolution() : [];
462 // shuffle output
463 $keys = $this->getParticipantsAnswerKeySequence();
464
465 $template = new ilTemplate("tpl.il_as_qpl_mc_kprim_output.html", true, true, "components/ILIAS/TestQuestionPool");
466
467 foreach ($keys as $answer_id) {
468 $answer = $this->object->getAnswer($answer_id);
469 if ($answer->getImageFile() !== null
470 && $answer->getImageFile() !== '') {
471 if ($this->object->getThumbSize()) {
472 $template->setCurrentBlock("preview");
473 $template->setVariable("URL_PREVIEW", $answer->getImageWebPath());
474 $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
475 $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('media/enlarge.svg'));
476 $template->setVariable("ANSWER_IMAGE_URL", $answer->getThumbWebPath());
477 [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
478 $alt = $answer->getImageFile();
479 if (strlen($answer->getAnswertext())) {
480 $alt = $answer->getAnswertext();
481 }
482 $alt = preg_replace("/<[^>]*?>/", "", $alt);
483 $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
484 $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
485 $template->parseCurrentBlock();
486 } else {
487 $template->setCurrentBlock("answer_image");
488 $template->setVariable("ANSWER_IMAGE_URL", $answer->getImageWebPath());
489 [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
490 $alt = $answer->getImageFile();
491 if (strlen($answer->getAnswertext())) {
492 $alt = $answer->getAnswertext();
493 }
494 $alt = preg_replace("/<[^>]*?>/", "", $alt);
495 $template->setVariable("ATTR", $attr);
496 $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
497 $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
498 $template->parseCurrentBlock();
499 }
500 }
501
502 if ($show_inline_feedback) {
503 $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
504 }
505
506 $template->setCurrentBlock("answer_row");
507 $template->setVariable("ANSWER_ID", $answer_id);
508 $template->setVariable("ANSWER_TEXT", $this->renderLatex(
509 ilLegacyFormElementsUtil::prepareTextareaOutput((string) $answer->getAnswertext(), true)
510 ));
511 $template->setVariable('VALUE_TRUE', 1);
512 $template->setVariable('VALUE_FALSE', 0);
513
514 if (isset($user_solution[$answer->getPosition()])) {
515 $tplVar = $user_solution[$answer->getPosition()] ? 'CHECKED_ANSWER_TRUE' : 'CHECKED_ANSWER_FALSE';
516 $template->setVariable($tplVar, " checked=\"checked\"");
517 }
518
519 $template->parseCurrentBlock();
520 }
521 $questiontext = $this->object->getQuestionForHTMLOutput();
522 if ($show_inline_feedback && $this->hasInlineFeedback()) {
523 $questiontext .= $this->buildFocusAnchorHtml();
524 }
525 $template->setVariable("QUESTIONTEXT", $this->renderLatex(
527 ));
528
529 $template->setVariable("INSTRUCTIONTEXT", $this->object->getInstructionTextTranslation(
530 $this->lng,
531 $this->object->getOptionLabel()
532 ));
533
534 $template->setVariable("OPTION_LABEL_TRUE", $this->object->getTrueOptionLabelTranslation(
535 $this->lng,
536 $this->object->getOptionLabel()
537 ));
538
539 $template->setVariable("OPTION_LABEL_FALSE", $this->object->getFalseOptionLabelTranslation(
540 $this->lng,
541 $this->object->getOptionLabel()
542 ));
543
544 $questionoutput = $template->get();
545 if (!$show_question_only) {
546 // get page object output
547 $questionoutput = $this->getILIASPage($questionoutput);
548 }
549 return $questionoutput;
550 }
551
552 public function getSolutionOutput(
553 int $active_id,
554 ?int $pass = null,
555 bool $graphical_output = false,
556 bool $result_output = false,
557 bool $show_question_only = true,
558 bool $show_feedback = false,
559 bool $show_correct_solution = false,
560 bool $show_manual_scoring = false,
561 bool $show_question_text = true,
562 bool $show_inline_feedback = true
563 ): string {
564 $user_solution = [];
565
566 if (($active_id > 0) && (!$show_correct_solution)) {
567 $solutions = $this->object->getSolutionValues($active_id, $pass);
568 foreach ($solutions as $idx => $solution_value) {
569 //$user_solution[$solution_value['value1']] = $solution_value['value2'];
570 $user_solution[] = [
571 'value1' => $solution_value['value1'],
572 'value2' => $solution_value['value2']
573 ];
574 }
575 } else {
576 // take the correct solution instead of the user solution
577 foreach ($this->object->getAnswers() as $answer) {
578 //$user_solution[$answer->getPosition()] = $answer->getCorrectness();
579 $user_solution[] = [
580 'value1' => $answer->getPosition(),
581 'value2' => $answer->getCorrectness()
582 ];
583 }
584 }
585
586 return $this->renderSolutionOutput(
587 $user_solution,
588 $active_id,
589 $pass,
590 $graphical_output,
591 $result_output,
592 $show_question_only,
593 $show_feedback,
594 $show_correct_solution,
595 $show_manual_scoring,
596 $show_question_text,
597 false,
598 $show_inline_feedback
599 );
600 }
601
602 public function renderSolutionOutput(
603 mixed $user_solutions,
604 int $active_id,
605 ?int $pass,
606 bool $graphical_output = false,
607 bool $result_output = false,
608 bool $show_question_only = true,
609 bool $show_feedback = false,
610 bool $show_correct_solution = false,
611 bool $show_manual_scoring = false,
612 bool $show_question_text = true,
613 bool $show_autosave_title = false,
614 bool $show_inline_feedback = false,
615 ): ?string {
616
617 $user_solution = [];
618 foreach ($user_solutions as $idx => $solution_value) {
619 $user_solution[$solution_value['value1']] = $solution_value['value2'];
620 }
621 $template = new ilTemplate("tpl.il_as_qpl_mc_kprim_output_solution.html", true, true, "components/ILIAS/TestQuestionPool");
622 $keys = $this->getParticipantsAnswerKeySequence();
623 foreach ($keys as $answer_id) {
624 $answer = $this->object->getAnswer($answer_id);
625
626 if (($active_id > 0) &&
627 !$show_correct_solution &&
628 $graphical_output) {
629 $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_NOT_OK);
630 if (isset($user_solution[$answer->getPosition()]) && $user_solution[$answer->getPosition()] == $answer->getCorrectness()) {
631 $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_OK);
632 }
633 $template->setCurrentBlock("icon_ok");
634 $template->setVariable("ICON_OK", $correctness_icon);
635 $template->parseCurrentBlock();
636 }
637 if ($answer->getImageFile() !== null
638 && $answer->getImageFile() !== '') {
639 $template->setCurrentBlock("answer_image");
640 if ($this->object->getThumbSize()) {
641 $template->setVariable("ANSWER_IMAGE_URL", $answer->getThumbWebPath());
642 } else {
643 $template->setVariable("ANSWER_IMAGE_URL", $answer->getImageWebPath());
644 }
645
646 $template->setVariable(
647 "ANSWER_IMAGE_ALT",
649 $answer->getImageFile()
650 )
651 );
652 $template->setVariable(
653 "ANSWER_IMAGE_TITLE",
655 $answer->getImageFile()
656 )
657 );
658 $template->parseCurrentBlock();
659 }
660
661 if ($show_feedback) {
662 $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
663 }
664
665 $template->setCurrentBlock("answer_row");
666 $template->setVariable("ANSWER_TEXT", $this->renderLatex(
667 ilLegacyFormElementsUtil::prepareTextareaOutput($answer->getAnswertext(), true)
668 ));
669
670 if ($this->renderPurposeSupportsFormHtml() || $this->isRenderPurposePrintPdf()) {
671 if (isset($user_solution[$answer->getPosition()])) {
672 if ($user_solution[$answer->getPosition()]) {
673 $template->setVariable("SOLUTION_IMAGE_TRUE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_checked.png")));
674 $template->setVariable("SOLUTION_ALT_TRUE", $this->lng->txt("checked"));
675 $template->setVariable("SOLUTION_IMAGE_FALSE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
676 $template->setVariable("SOLUTION_ALT_FALSE", $this->lng->txt("unchecked"));
677 } else {
678 $template->setVariable("SOLUTION_IMAGE_TRUE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
679 $template->setVariable("SOLUTION_ALT_TRUE", $this->lng->txt("unchecked"));
680 $template->setVariable("SOLUTION_IMAGE_FALSE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_checked.png")));
681 $template->setVariable("SOLUTION_ALT_FALSE", $this->lng->txt("checked"));
682 }
683 } else {
684 $template->setVariable("SOLUTION_IMAGE_TRUE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
685 $template->setVariable("SOLUTION_ALT_TRUE", $this->lng->txt("unchecked"));
686 $template->setVariable("SOLUTION_IMAGE_FALSE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
687 $template->setVariable("SOLUTION_ALT_FALSE", $this->lng->txt("unchecked"));
688 }
689 } else {
690 $template->setVariable('SOL_QID', $this->object->getId());
691 $template->setVariable('SOL_SUFFIX', $show_correct_solution ? 'bestsolution' : 'usersolution');
692 $template->setVariable('SOL_POSITION', $answer->getPosition());
693
694 $template->setVariable('SOL_TRUE_VALUE', 1);
695 $template->setVariable('SOL_FALSE_VALUE', 0);
696
697 if (isset($user_solution[$answer->getPosition()])) {
698 if ($user_solution[$answer->getPosition()]) {
699 $template->setVariable('SOL_TRUE_CHECKED', 'checked');
700 } else {
701 $template->setVariable('SOL_FALSE_CHECKED', 'checked');
702 }
703 }
704 }
705
706 $template->parseCurrentBlock();
707 }
708
709 if ($show_question_text == true) {
710 $questiontext = $this->object->getQuestionForHTMLOutput();
711 if ($show_feedback && $this->hasInlineFeedback()) {
712 $questiontext .= $this->buildFocusAnchorHtml();
713 }
714 $template->setVariable("QUESTIONTEXT", ilLegacyFormElementsUtil::prepareTextareaOutput($questiontext, true));
715
716 $template->setVariable("INSTRUCTIONTEXT", $this->object->getInstructionTextTranslation(
717 $this->lng,
718 $this->object->getOptionLabel()
719 ));
720 }
721
722 $template->setVariable("OPTION_LABEL_TRUE", $this->object->getTrueOptionLabelTranslation(
723 $this->lng,
724 $this->object->getOptionLabel()
725 ));
726
727 $template->setVariable("OPTION_LABEL_FALSE", $this->object->getFalseOptionLabelTranslation(
728 $this->lng,
729 $this->object->getOptionLabel()
730 ));
731
732
733 $questionoutput = $template->get();
734 $feedback = ($show_feedback && !$this->isTestPresentationContext()) ? $this->getGenericFeedbackOutput((int) $active_id, $pass) : "";
735
736 $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "components/ILIAS/TestQuestionPool");
737
738 if (strlen($feedback)) {
739 $cssClass = (
740 $this->hasCorrectSolution($active_id, $pass) ?
742 );
743
744 $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
745 $solutiontemplate->setVariable("FEEDBACK", ilLegacyFormElementsUtil::prepareTextareaOutput($feedback, true));
746 }
747
748 $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
749
750 $solutionoutput = $solutiontemplate->get();
751
752 if (!$show_question_only) {
753 // get page object output
754 $solutionoutput = $this->getILIASPage($solutionoutput);
755 }
756 return $solutionoutput;
757 }
758
760 {
761 $choice_keys = array_keys($this->object->getAnswers());
762
763 if ($this->object->isShuffleAnswersEnabled()) {
764 $choice_keys = $this->object->getShuffler()->transform($choice_keys);
765 }
766
767 return $choice_keys;
768 }
769
770 private function populateSpecificFeedbackInline($user_solution, $answer_id, $template): void
771 {
772 if ($this->object->getSpecificFeedbackSetting() == ilAssConfigurableMultiOptionQuestionFeedback::FEEDBACK_SETTING_CHECKED) {
773 if (isset($user_solution[$answer_id])) {
774 $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
775 if (strlen($fb)) {
776 $template->setCurrentBlock("feedback");
777 $template->setVariable("FEEDBACK", $this->renderLatex(
779 ));
780 $template->parseCurrentBlock();
781 }
782 }
783 }
784
785 if ($this->object->getSpecificFeedbackSetting() == ilAssConfigurableMultiOptionQuestionFeedback::FEEDBACK_SETTING_ALL) {
786 $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
787 if (strlen($fb)) {
788 $template->setCurrentBlock("feedback");
789 $template->setVariable("FEEDBACK", $this->renderLatex(
791 ));
792 $template->parseCurrentBlock();
793 }
794 }
795
796 if ($this->object->getSpecificFeedbackSetting() == ilAssConfigurableMultiOptionQuestionFeedback::FEEDBACK_SETTING_CORRECT) {
797 $answer = $this->object->getAnswer($answer_id);
798
799 if ($answer->getCorrectness()) {
800 $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
801 if (strlen($fb)) {
802 $template->setCurrentBlock("feedback");
803 $template->setVariable("FEEDBACK", $this->renderLatex(
805 ));
806 $template->parseCurrentBlock();
807 }
808 }
809 }
810 }
811
822 {
823 return [];
824 }
825
836 {
837 return [];
838 }
839
840 private function aggregateAnswers($rawSolutionData, $answers): array
841 {
842 $aggregate = [];
843
844 foreach ($answers as $answer) {
845 $answerAgg = [
846 'answertext' => $answer->getAnswerText(), 'count_true' => 0, 'count_false' => 0
847 ];
848
849 foreach ($rawSolutionData as $solutionRecord) {
850 if ($solutionRecord['value1'] == $answer->getPosition()) {
851 if ($solutionRecord['value2']) {
852 $answerAgg['count_true']++;
853 } else {
854 $answerAgg['count_false']++;
855 }
856 }
857 }
858
859 $aggregate[] = $answerAgg;
860 }
861
862 return $aggregate;
863 }
864
865 public function getAnswersFrequency($relevantAnswers, $questionIndex): array
866 {
867 $agg = $this->aggregateAnswers($relevantAnswers, $this->object->getAnswers());
868
869 $answers = [];
870
871 foreach ($agg as $ans) {
872 $answers[] = [
873 'answer' => $ans['answertext'],
874 'frequency_true' => $ans['count_true'],
875 'frequency_false' => $ans['count_false']
876 ];
877 }
878
879 return $answers;
880 }
881
889 public function getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex): ilAnswerFrequencyStatisticTableGUI
890 {
891 $table = new ilKprimChoiceAnswerFreqStatTableGUI($parentGui, $parentCmd, $this->object);
892 $table->setQuestionIndex($questionIndex);
893 $table->setData($this->getAnswersFrequency($relevantAnswers, $questionIndex));
894 $table->initColumns();
895
896 return $table;
897 }
898
900 {
901 // points
902 $points = new ilNumberInputGUI($this->lng->txt('points'), 'points');
903 $points->setRequired(true);
904 $points->setSize(3);
905 $points->allowDecimals(true);
906 $points->setMinValue(0);
907 $points->setMinvalueShouldBeGreater(true);
908 $points->setValue($this->object->getPoints());
909 $form->addItem($points);
910
911 // score partial solution
912 $scorePartialSolution = new ilCheckboxInputGUI($this->lng->txt('score_partsol_enabled'), 'score_partsol_enabled');
913 $scorePartialSolution->setInfo($this->lng->txt('score_partsol_enabled_info'));
914 $scorePartialSolution->setChecked($this->object->isScorePartialSolutionEnabled());
915 $form->addItem($scorePartialSolution);
916
917 // answers
918 $kprimAnswers = new ilKprimChoiceCorrectionsInputGUI($this->lng->txt('answers'), 'kprimanswers');
919 $kprimAnswers->setInfo($this->lng->txt('kprim_answers_info'));
920 $kprimAnswers->setSize(64);
921 $kprimAnswers->setMaxLength(1000);
922 $kprimAnswers->setRequired(true);
923 $kprimAnswers->setQuestionObject($this->object);
924 $kprimAnswers->setValues($this->object->getAnswers());
925 $form->addItem($kprimAnswers);
926 }
927
932 {
933 $this->object->setPoints(
934 (float) str_replace(',', '.', $form->getInput('points'))
935 );
936
937 $this->object->setScorePartialSolutionEnabled(
938 (bool) $form->getInput('score_partsol_enabled')
939 );
940
941 $this->object->setAnswers(
942 $form->getItemByPostVar('kprimanswers')->getValues()
943 );
944 }
945}
populateSpecificFeedbackInline($user_solution, $answer_id, $template)
getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex)
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)
populateAnswerSpecificFormPart(ilPropertyFormGUI $form)
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)
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