ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.assQuestionGUI.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
28use ILIAS\Refinery\Factory as Refinery;
30
35abstract class assQuestionGUI
36{
42 public const ALLOWED_PLAIN_TEXT_TAGS = "<em>, <strong>";
43
44 public const SESSION_PREVIEW_DATA_BASE_INDEX = 'ilAssQuestionPreviewAnswers';
45
46 public const FORM_MODE_EDIT = 'edit';
47 public const FORM_MODE_ADJUST = 'adjust';
48
49 public const FORM_ENCODING_URLENCODE = 'application/x-www-form-urlencoded';
50 public const FORM_ENCODING_MULTIPART = 'multipart/form-data';
51
52 public const CORRECTNESS_NOT_OK = 0;
53 public const CORRECTNESS_MOSTLY_OK = 1;
54 public const CORRECTNESS_OK = 2;
55
56 public const RENDER_PURPOSE_PLAYBACK = 'renderPurposePlayback';
57 public const RENDER_PURPOSE_DEMOPLAY = 'renderPurposeDemoplay';
58 public const RENDER_PURPOSE_PREVIEW = 'renderPurposePreview';
59 public const RENDER_PURPOSE_PRINT_PDF = 'renderPurposePrintPdf';
60 public const RENDER_PURPOSE_INPUT_VALUE = 'renderPurposeInputValue';
61
62 public const EDIT_CONTEXT_AUTHORING = 'authoring';
63 public const EDIT_CONTEXT_ADJUSTMENT = 'adjustment';
64
65 public const PRESENTATION_CONTEXT_TEST = 'pContextTest';
66 public const PRESENTATION_CONTEXT_RESULTS = 'pContextResults';
67
68 protected const HAS_SPECIAL_QUESTION_COMMANDS = false;
69
70 protected const SUGGESTED_SOLUTION_COMMANDS_CANCEL = 'cancelSuggestedSolution';
71 protected const SUGGESTED_SOLUTION_COMMANDS_SAVE = 'saveSuggestedSolution';
72 protected const SUGGESTED_SOLUTION_COMMANDS_DEFAULT = 'suggestedsolution';
73
74 private const CMD_SAVE = 'save';
75 private const CMD_SAVE_AND_RETURN = 'saveReturn';
76
77 private const CMD_SYNC_QUESTION = 'syncQuestion';
78 public const CMD_SYNC_QUESTION_AND_RETURN = 'syncQuestionReturn';
79
80 protected const QUESTION_SAVE_CMDS = [
83 ];
84
93 'uploadchoice',
94 'uploadImage',
95 'changeToPictures',
96 'uploadElementImage',
97 'uploadterms',
98 'uploaddefintions'
99 ];
100
101 private $ui;
107 private ilTree $tree;
109 protected ilLogger $logger;
113 protected ilCtrl $ctrl;
118 protected ilLanguage $lng;
119 protected Refinery $refinery;
120
121 protected $error;
122 protected string $errormessage;
123
125 protected int $sequence_no;
126
128 protected int $question_count;
129
130 private $taxonomyIds = [];
131
132 private $targetGuiClass = null;
133
134 private string $questionActionCmd = 'handleQuestionAction';
135
137
139
140
141 private ?string $presentationContext = null;
142
144
146
147 private bool $previousSolutionPrefilled = false;
148
149 protected ?ilPropertyFormGUI $editForm = null;
152 protected bool $parent_type_is_lm = false;
153
155 private ?string $copy_to_new_pool_on_save = null;
156
157 private ?int $move_after_question_with_id = null;
158 private bool $context_allows_sync_to_pool = false;
159 private string $question_sync_modal = '';
160
161 public function __construct()
162 {
164 global $DIC;
165 $this->lng = $DIC['lng'];
166 $this->tpl = $DIC['tpl'];
167 $this->ctrl = $DIC['ilCtrl'];
168 $this->current_user = $DIC['ilUser'];
169 $this->ui = $DIC->ui();
170 $this->ilObjDataCache = $DIC['ilObjDataCache'];
171 $this->access = $DIC->access();
172 $this->ilHelp = $DIC['ilHelp'];
173 $this->tabs_gui = $DIC['ilTabs'];
174 $this->rbacsystem = $DIC['rbacsystem'];
175 $this->tree = $DIC['tree'];
176 $this->db = $DIC->database();
177 $this->logger = $DIC['ilLog'];
178 $this->component_repository = $DIC['component.repository'];
179 $this->refinery = $DIC['refinery'];
180
181 $local_dic = QuestionPoolDIC::dic();
182 $this->forms_helper = new ilTestLegacyFormsHelper();
183 $this->request_data_collector = $local_dic['request_data_collector'];
184 $this->questionrepository = $local_dic['question.general_properties.repository'];
185
186 $this->errormessage = $this->lng->txt("fill_out_all_required_fields");
187 $this->notes_gui = $DIC->notes()->gui();
188 }
189
190 abstract public function editQuestion(
191 bool $checkonly = false,
192 ?bool $is_save_cmd = null
193 ): bool;
194
199 abstract public function getSpecificFeedbackOutput(array $userSolution): string;
200
201 abstract public function getSolutionOutput(
202 int $active_id,
203 ?int $pass = null,
204 bool $graphical_output = false,
205 bool $result_output = false,
206 bool $show_question_only = true,
207 bool $show_feedback = false,
208 bool $show_correct_solution = false,
209 bool $show_manual_scoring = false,
210 bool $show_question_text = true,
211 bool $show_inline_feedback = true
212 ): string;
213
214 abstract public function getPreview(
215 bool $show_question_only = false,
216 bool $show_inline_feedback = false
217 ): string;
218
219 abstract public function getTestOutput(
220 int $active_id,
221 int $pass,
222 bool $is_question_postponed = false,
223 array|bool $user_post_solutions = false,
224 bool $show_specific_inline_feedback = false
225 ): string;
226
227 public function renderSolutionOutput(
228 mixed $user_solutions,
229 int $active_id,
230 ?int $pass,
231 bool $graphical_output = false,
232 bool $result_output = false,
233 bool $show_question_only = true,
234 bool $show_feedback = false,
235 bool $show_correct_solution = false,
236 bool $show_manual_scoring = false,
237 bool $show_question_text = true,
238 bool $show_autosave_title = false,
239 bool $show_inline_feedback = false,
240 ): ?string {
241 return null;
242 }
243
249 public function getObject(): assQuestion
250 {
251 return $this->object;
252 }
253
258 public function setObject(assQuestion $question): void
259 {
260 $this->object = $question;
261 }
262
263 public function setCopyToExistingPoolOnSave(?int $pool_ref_id): void
264 {
265 $this->copy_to_existing_pool_on_save = $pool_ref_id;
266 }
267
269 {
270 return $this->copy_to_existing_pool_on_save;
271 }
272
273 public function setCopyToNewPoolOnSave(?string $pool_title): void
274 {
275 $this->copy_to_new_pool_on_save = $pool_title;
276 }
277
278 public function getCopyToNewPoolOnSave(): ?string
279 {
280 return $this->copy_to_new_pool_on_save;
281 }
282
283 public function setMoveAfterQuestionId(?int $question_id): void
284 {
285 $this->move_after_question_with_id = $question_id;
286 }
287
288 public function getMoveAfterQuestionId(): ?int
289 {
290 return $this->move_after_question_with_id;
291 }
292
293 public function hasInlineFeedback(): bool
294 {
295 return false;
296 }
297
298 public function addHeaderAction(): void
299 {
300 }
301
302 public function redrawHeaderAction(): void
303 {
304 echo $this->getHeaderAction() . $this->ui->mainTemplate()->getOnLoadCodeForAsynch();
305 exit;
306 }
307
308 public function getHeaderAction(): string
309 {
310 $parentObjType = $this->ilObjDataCache->lookupType($this->object->getObjId());
311
312 $dispatcher = new ilCommonActionDispatcherGUI(
314 $this->access,
315 $parentObjType,
316 $this->request_data_collector->getRefId(),
317 $this->object->getObjId()
318 );
319
320 $dispatcher->setSubObject("quest", $this->object->getId());
321
322 $ha = $dispatcher->initHeaderAction();
323 $ha->enableComments(true, false);
324
325 return $ha->getHeaderAction($this->ui->mainTemplate());
326 }
327
328 public function getCommentsPanelHTML(): string
329 {
330 $comment_gui = new ilCommentGUI($this->object->getObjId(), $this->object->getId(), 'quest');
331 return $comment_gui->getListHTML();
332 }
333
334 public function executeCommand()
335 {
336 $this->ilHelp->setScreenIdComponent('qpl');
337
338 $next_class = $this->ctrl->getNextClass($this);
339
340 switch ($next_class) {
341 case 'ilformpropertydispatchgui':
342 $form = $this->buildEditForm();
343 $form_prop_dispatch = new ilFormPropertyDispatchGUI();
344 $form_prop_dispatch->setItem($form->getItemByPostVar(ilUtil::stripSlashes($this->request_data_collector->string('postvar'))));
345 $this->ctrl->forwardCommand($form_prop_dispatch);
346 break;
347 default:
348 $cmd = $this->ctrl->getCmd('editQuestion');
349 switch ($cmd) {
350 case self::SUGGESTED_SOLUTION_COMMANDS_CANCEL:
351 case self::SUGGESTED_SOLUTION_COMMANDS_SAVE:
352 case self::SUGGESTED_SOLUTION_COMMANDS_DEFAULT:
353 case 'saveSuggestedSolutionType':
354 case 'saveContentsSuggestedSolution':
355 case 'deleteSuggestedSolution':
356 case 'linkChilds':
357 case 'cancelExplorer':
358 case 'outSolutionExplorer':
359 case 'addST':
360 case 'addPG':
361 case 'addGIT':
362 case 'save':
363 case 'saveReturn':
364 case self::CMD_SYNC_QUESTION:
365 case self::CMD_SYNC_QUESTION_AND_RETURN:
366 case 'editQuestion':
367 $this->$cmd();
368 break;
369 default:
370 if (method_exists($this, $cmd)) {
371 $this->$cmd();
372 }
373 }
374 }
375 }
376
377 protected function hasSpecialQuestionCommands(): bool
378 {
379 return static::HAS_SPECIAL_QUESTION_COMMANDS;
380 }
381
383 public function getType(): string
384 {
385 return $this->getQuestionType();
386 }
387
388 public function getPresentationContext(): ?string
389 {
390 return $this->presentationContext;
391 }
392
393 public function setPresentationContext(string $presentationContext): void
394 {
395 $this->presentationContext = $presentationContext;
396 }
397
398 public function isTestPresentationContext(): bool
399 {
400 return $this->getPresentationContext() == self::PRESENTATION_CONTEXT_TEST;
401 }
402
403 // hey: previousPassSolutions - setter/getter for Previous Solution Prefilled flag
404 public function isPreviousSolutionPrefilled(): bool
405 {
406 return $this->previousSolutionPrefilled;
407 }
408
409 public function setPreviousSolutionPrefilled(bool $previousSolutionPrefilled): void
410 {
411 $this->previousSolutionPrefilled = $previousSolutionPrefilled;
412 }
413 // hey.
414
415 public function getRenderPurpose(): string
416 {
417 return $this->renderPurpose;
418 }
419
420 public function setRenderPurpose(string $renderPurpose): void
421 {
422 $this->renderPurpose = $renderPurpose;
423 }
424
425 public function isRenderPurposePrintPdf(): bool
426 {
427 return $this->getRenderPurpose() == self::RENDER_PURPOSE_PRINT_PDF;
428 }
429
430 public function isRenderPurposePreview(): bool
431 {
432 return $this->getRenderPurpose() == self::RENDER_PURPOSE_PREVIEW;
433 }
434
435 public function isRenderPurposeInputValue(): bool
436 {
437 return $this->getRenderPurpose() == self::RENDER_PURPOSE_INPUT_VALUE;
438 }
439
440 public function isRenderPurposePlayback(): bool
441 {
442 return $this->getRenderPurpose() == self::RENDER_PURPOSE_PLAYBACK;
443 }
444
445 public function isRenderPurposeDemoplay(): bool
446 {
447 return $this->getRenderPurpose() == self::RENDER_PURPOSE_DEMOPLAY;
448 }
449
450 public function renderPurposeSupportsFormHtml(): bool
451 {
452 if ($this->isRenderPurposePrintPdf()) {
453 return false;
454 }
455
456 if ($this->isRenderPurposeInputValue()) {
457 return false;
458 }
459
460 return true;
461 }
462
463 public function getEditContext(): string
464 {
465 return $this->editContext;
466 }
467
468 public function setEditContext(string $editContext): void
469 {
470 $this->editContext = $editContext;
471 }
472
473 public function isAuthoringEditContext(): bool
474 {
475 return $this->getEditContext() == self::EDIT_CONTEXT_AUTHORING;
476 }
477
478 public function isAdjustmentEditContext(): bool
479 {
480 return $this->getEditContext() == self::EDIT_CONTEXT_ADJUSTMENT;
481 }
482
483 public function setAdjustmentEditContext(): void
484 {
485 $this->setEditContext(self::EDIT_CONTEXT_ADJUSTMENT);
486 }
487
489 {
490 return $this->navigationGUI;
491 }
492
493 public function setNavigationGUI(?ilTestQuestionNavigationGUI $navigationGUI): void
494 {
495 $this->navigationGUI = $navigationGUI;
496 }
497
498 public function setTaxonomyIds(array $taxonomyIds): void
499 {
500 $this->taxonomyIds = $taxonomyIds;
501 }
502
503 public function getTaxonomyIds(): array
504 {
505 return $this->taxonomyIds;
506 }
507
508 public function setTargetGui($linkTargetGui): void
509 {
510 $this->setTargetGuiClass(get_class($linkTargetGui));
511 }
512
513 public function setTargetGuiClass(string $targetGuiClass): void
514 {
515 $this->targetGuiClass = $targetGuiClass;
516 }
517
518 public function getTargetGuiClass(): ?string
519 {
520 return $this->targetGuiClass;
521 }
522
523 public function setQuestionHeaderBlockBuilder(\ilQuestionHeaderBlockBuilder $questionHeaderBlockBuilder): void
524 {
525 $this->questionHeaderBlockBuilder = $questionHeaderBlockBuilder;
526 }
527
528 // fau: testNav - get the question header block bulder (for tweaking)
530 {
531 return $this->questionHeaderBlockBuilder;
532 }
533 // fau.
534
535 public function setQuestionActionCmd(string $questionActionCmd): void
536 {
537 $this->questionActionCmd = $questionActionCmd;
538
539 if (is_object($this->object)) {
540 $this->object->questionActionCmd = $questionActionCmd;
541 }
542 }
543
544 public function getQuestionActionCmd(): string
545 {
546 return $this->questionActionCmd;
547 }
548
553 protected function writePostData(bool $always = false): int
554 {
555 return 0;
556 }
557
558 public function assessment(): void
559 {
560 $stats_table = new ilQuestionCumulatedStatisticsTableGUI($this, 'assessment', '', $this->object, $this->questionrepository);
561 $usage_table = new ilQuestionUsagesTableGUI($this, 'assessment', '', $this->object);
562
563 $this->tpl->setContent(implode('<br />', [
564 $stats_table->getHTML(),
565 $usage_table->getHTML()
566 ]));
567 }
568
572 public static function _getQuestionGUI(string $question_type = '', int $question_id = -1): ?assQuestionGUI
573 {
574 global $DIC;
575 $ilCtrl = $DIC['ilCtrl'];
576 $ilDB = $DIC['ilDB'];
577 $lng = $DIC['lng'];
578
579 if (($question_type === '') && ($question_id > 0)) {
580 $question_type = QuestionPoolDIC::dic()['question.general_properties.repository']
581 ->getForQuestionId($question_id)?->getClassName();
582 }
583
584 if ($question_type === null || $question_type === '') {
585 return null;
586 }
587
588 $question_type_gui = $question_type . 'GUI';
589 $question = new $question_type_gui();
590
591 $feedbackObjectClassname = assQuestion::getFeedbackClassNameByQuestionType($question_type);
592 $question->object->feedbackOBJ = new $feedbackObjectClassname($question->object, $ilCtrl, $ilDB, $lng);
593
594 if ($question_id > 0) {
595 $question->object->loadFromDb($question_id);
596 }
597
598 return $question;
599 }
600
602 {
603 foreach ($this->getPresentationJavascripts() as $jsFile) {
604 $tpl->addJavaScript($jsFile);
605 }
606 }
607
608 public function getPresentationJavascripts(): array
609 {
610 return [];
611 }
612
613 public function getQuestionTemplate(): void
614 {
615 // @todo Björn: Maybe this has to be changed for PHP 7/ILIAS 5.2.x because ass[XYZ]QuestionGUI::editQuestion is called multiple times
616 if (!$this->tpl->blockExists('adm_content')) {
617 $this->tpl->addBlockFile('ADM_CONTENT', 'adm_content', 'tpl.il_as_question.html', 'components/ILIAS/TestQuestionPool');
618 }
619 }
620
621 protected function renderEditForm(ilPropertyFormGUI $form): void
622 {
623 $this->addSaveOnEnterOnLoadCode();
624 $this->getQuestionTemplate();
625 $this->tpl->setVariable('QUESTION_DATA', $form->getHTML() . $this->question_sync_modal);
626 }
627
631 public function getILIASPage(string $html = ""): string
632 {
633 $page_gui = new ilAssQuestionPageGUI($this->object->getId());
634 $page_gui->setFileDownloadLink($this->buildFileDownloadLink());
635 $page_gui->setQuestionHTML(
636 [$this->object->getId() => $html]
637 );
638 $presentation = $page_gui->presentation();
639 $presentation = preg_replace("/src=\"\\.\\//ims", "src=\"" . ILIAS_HTTP_PATH . "/", $presentation);
640 return $presentation;
641 }
642
643 public function outQuestionPage($a_temp_var, $a_postponed = false, $active_id = "", $html = "", $inlineFeedbackEnabled = false): string
644 {
645 if ($this->object->getTestPresentationConfig()->isSolutionInitiallyPrefilled()) {
646 // hey
647 $this->tpl->setOnScreenMessage('info', $this->getPreviousSolutionProvidedMessage());
648 $html .= $this->getPreviousSolutionConfirmationCheckboxHtml();
649 } elseif ($this->object->getTestPresentationConfig()->isUnchangedAnswerPossible()) {
650 $html .= $this->getUseUnchangedAnswerCheckboxHtml();
651 }
652
653 $this->lng->loadLanguageModule("content");
654
655 $page_gui = new ilAssQuestionPageGUI($this->object->getId());
656 $page_gui->setFileDownloadLink($this->buildFileDownloadLink());
657 $page_gui->setOutputMode('presentation');
658 $page_gui->setTemplateTargetVar($a_temp_var);
659
660 if ($this->getNavigationGUI()) {
661 $html .= $this->getNavigationGUI()->getHTML();
662 $page_gui->setQuestionActionsHTML($this->getNavigationGUI()->getActionsHTML());
663 }
664
665 if (strlen($html)) {
666 $page_gui->setQuestionHTML([$this->object->getId() => $html]);
667 }
668
669 $page_gui->setPresentationTitle($this->questionHeaderBlockBuilder->getPresentationTitle());
670 $page_gui->setQuestionInfoHTML($this->questionHeaderBlockBuilder->getQuestionInfoHTML());
671
672 return $page_gui->presentation();
673 }
674
675 protected function getUseUnchangedAnswerCheckboxHtml(): string
676 {
677 $tpl = new ilTemplate('tpl.tst_question_additional_behaviour_checkbox.html', true, true, 'components/ILIAS/TestQuestionPool');
678 $tpl->setVariable('TXT_FORCE_FORM_DIFF_LABEL', $this->object->getTestPresentationConfig()->getUseUnchangedAnswerLabel());
679 return $tpl->get();
680 }
681
682 protected function getPreviousSolutionProvidedMessage(): string
683 {
684 return $this->lng->txt('use_previous_solution_advice');
685 }
686
688 {
689 $tpl = new ilTemplate('tpl.tst_question_additional_behaviour_checkbox.html', true, true, 'components/ILIAS/TestQuestionPool');
690 $tpl->setVariable('TXT_FORCE_FORM_DIFF_LABEL', $this->lng->txt('use_previous_solution'));
691 return $tpl->get();
692 }
693
694 public function syncQuestion(): void
695 {
696 $original_id = $this->object->getOriginalId();
697 if ($original_id !== null) {
698 $this->object->syncWithOriginal();
699 $this->tpl->setOnScreenMessage('success', $this->lng->txt("msg_obj_modified"), true);
700 }
701 }
702
703 public function saveReturn(): void
704 {
705 $old_id = $this->request_data_collector->getQuestionId();
706 $this->setAdditionalContentEditingModeFromPost();
707 $result = $this->writePostData();
708 if ($result !== 0) {
709 $this->tabs_gui->setTabActive('edit_question');
710 return;
711 }
712
713 $this->object->getCurrentUser()->setPref('tst_lastquestiontype', $this->object->getQuestionType());
714 $this->object->getCurrentUser()->writePref('tst_lastquestiontype', $this->object->getQuestionType());
715 $this->object->saveToDb($old_id);
716
717 $this->questionrepository->questionExistsInPool($this->object->getOriginalId());
718 $this->tpl->setOnScreenMessage('success', $this->lng->txt('msg_obj_modified'), true);
719 $this->ctrl->redirectByClass(ilAssQuestionPreviewGUI::class, ilAssQuestionPreviewGUI::CMD_SHOW);
720 }
721
722 public function saveQuestion(): bool
723 {
724 $this->setAdditionalContentEditingModeFromPost();
725 $result = $this->writePostData();
726 $this->tabs_gui->activateTab('edit_question');
727
728 if ($result !== 0) {
729 return false;
730 }
731
732 $this->object->getCurrentUser()->setPref('tst_lastquestiontype', $this->object->getQuestionType());
733 $this->object->getCurrentUser()->writePref('tst_lastquestiontype', $this->object->getQuestionType());
734
735 if ($this->request_data_collector->getQuestionId() === 0) {
736 if ($this->object->getId() < 1) {
737 $this->object->createNewQuestion();
738 }
739 $this->setQuestionTabs();
740 }
741
742 if ($this->needsSyncQuery()) {
743 $cmd = strpos($this->ctrl->getCmd(), 'Return') === false
744 ? self::CMD_SYNC_QUESTION
745 : self::CMD_SYNC_QUESTION_AND_RETURN;
746 $this->question_sync_modal = $this->getQuestionSyncModal($cmd);
747 }
748
749 $this->object->saveToDb();
750 return true;
751 }
752
754 {
755 $additional_content_editing_mode = $this->request_data_collector->string('additional_content_editing_mode');
756 if ($additional_content_editing_mode !== ''
757 && in_array($additional_content_editing_mode, $this->object->getValidAdditionalContentEditingModes())) {
758 $this->object->setAdditionalContentEditingMode($additional_content_editing_mode);
759 }
760 }
761
762 protected function setTestSpecificProperties(): void
763 {
764 if ($this->request_data_collector->isset('pool_ref')) {
765 $this->copy_to_existing_pool_on_save = $this->request_data_collector->int('pool_ref');
766 }
767
768 if ($this->request_data_collector->isset('pool_title')) {
769 $this->copy_to_new_pool_on_save = $this->request_data_collector->string('pool_title');
770 }
771
772 if ($this->request_data_collector->isset('move_after_question_with_id')) {
773 $this->move_after_question_with_id = $this->request_data_collector->int('move_after_question_with_id');
774 }
775 }
776
780 public function getContextPath($cont_obj, int $a_endnode_id, int $a_startnode_id = 1): string
781 {
782 $path = "";
783
784 $tmpPath = $cont_obj->getLMTree()->getPathFull($a_endnode_id, $a_startnode_id);
785
786 // count -1, to exclude the learning module itself
787 for ($i = 1; $i < (count($tmpPath) - 1); $i++) {
788 if ($path != "") {
789 $path .= " > ";
790 }
791
792 $path .= $tmpPath[$i]["title"];
793 }
794
795 return $path;
796 }
797
798 public function setSequenceNumber(int $nr): void
799 {
800 $this->sequence_no = $nr;
801 }
802
803 public function getSequenceNumber(): int
804 {
805 return $this->sequence_no;
806 }
807
808 public function setQuestionCount(int $a_question_count): void
809 {
810 $this->question_count = $a_question_count;
811 }
812
813 public function getQuestionCount(): int
814 {
815 return $this->question_count;
816 }
817
818 public function getErrorMessage(): string
819 {
820 return $this->errormessage;
821 }
822
823 public function setErrorMessage(string $errormessage): void
824 {
825 $this->errormessage = $errormessage;
826 }
827
828 public function addErrorMessage(string $errormessage): void
829 {
830 $this->errormessage .= ((strlen($this->errormessage)) ? "<br />" : "") . $errormessage;
831 }
832
833 public function getQuestionType(): string
834 {
835 return $this->object->getQuestionType();
836 }
837
838 public function getAsValueAttribute(string $a_value): string
839 {
840 $result = "";
841 if (strlen($a_value)) {
842 $result = " value=\"$a_value\" ";
843 }
844 return $result;
845 }
846
848 {
849 if (!$this->object->getSelfAssessmentEditingMode()) {
850 $form->addCommandButton("saveReturn", $this->lng->txt("save_return"));
851 }
852 $form->addCommandButton("save", $this->lng->txt("save"));
853 }
854
856 {
857 $title = new ilTextInputGUI($this->lng->txt('title'), 'title');
858 $title->setMaxLength(100);
859 $title->setValue($this->object->getTitle());
860 $title->setRequired(true);
861 $form->addItem($title);
862
863 if (!$this->object->getSelfAssessmentEditingMode()) {
864 // author
865 $author = new ilTextInputGUI($this->lng->txt('author'), 'author');
866 $author->setValue($this->object->getAuthor());
867 $author->setMaxLength(512);
868 $author->setRequired(true);
869 $form->addItem($author);
870
871 // description
872 $description = new ilTextInputGUI($this->lng->txt('description'), 'comment');
873 $description->setValue($this->object->getComment());
874 $description->setRequired(false);
875 $description->setMaxLength(1000);
876 $form->addItem($description);
877 } else {
878 // author as hidden field
879 $hi = new ilHiddenInputGUI('author');
880 $author = ilLegacyFormElementsUtil::prepareFormOutput($this->object->getAuthor());
881 if (trim($author) == "") {
882 $author = "-";
883 }
884 $hi->setValue($author);
885 $form->addItem($hi);
886 }
887
888 // lifecycle
889 $lifecycle = new ilSelectInputGUI($this->lng->txt('qst_lifecycle'), 'lifecycle');
890 $lifecycle->setOptions($this->object->getLifecycle()->getSelectOptions($this->lng));
891 $lifecycle->setValue($this->object->getLifecycle()->getIdentifier());
892 $form->addItem($lifecycle);
893
894 // questiontext
895 $question = new ilTextAreaInputGUI($this->lng->txt('question'), 'question');
896 $question->setValue($this->object->getQuestion());
897 $question->setRequired(true);
898 $question->setRows(10);
899 $question->setCols(80);
900
901 if (!$this->object->getSelfAssessmentEditingMode()) {
902 if ($this->object->getAdditionalContentEditingMode() !== assQuestion::ADDITIONAL_CONTENT_EDITING_MODE_IPE) {
903 $question->setUseRte(true);
904 $question->setRteTags(ilRTESettings::_getUsedHTMLTags('assessment'));
905 $question->setRTESupport($this->object->getId(), 'qpl', 'assessment');
906 }
907 } else {
909 $question->setUseTagsForRteOnly(false);
910 }
911 $question->setInfo($this->lng->txt('latex_edit_info'));
912 $form->addItem($question);
913
914 $question_type = new ilHiddenInputGUI('question_type');
915 $question_type->setValue((string) $this->getQuestionType());
916 $form->addItem($question_type);
917
918 if ($this->copy_to_existing_pool_on_save !== null) {
919 $pool_ref = new ilHiddenInputGUI('pool_ref');
920 $pool_ref->setValue((string) $this->copy_to_existing_pool_on_save);
921 $form->addItem($pool_ref);
922 }
923
924 if ($this->copy_to_new_pool_on_save !== null) {
925 $pool_title = new ilHiddenInputGUI('pool_title');
926 $pool_title->setValue($this->copy_to_new_pool_on_save);
927 $form->addItem($pool_title);
928 }
929
930 if ($this->move_after_question_with_id !== null) {
931 $move_after_question_id = new ilHiddenInputGUI('move_after_question_with_id');
932 $move_after_question_id->setValue((string) $this->move_after_question_with_id);
933 $form->addItem($move_after_question_id);
934 }
935
936 $additional_content_editing_mode = new ilHiddenInputGUI('additional_content_editing_mode');
937 $additional_content_editing_mode->setValue($this->object->getAdditionalContentEditingMode());
938 $form->addItem($additional_content_editing_mode);
939
940 $this->addNumberOfTriesToFormIfNecessary($form);
941 }
942
944 {
945 if (!$this->object->getSelfAssessmentEditingMode()) {
946 return;
947 }
948
949 $nr_tries = $this->object->getNrOfTries() ?? $this->object->getDefaultNrOfTries();
950
951 if ($nr_tries < 1) {
952 $nr_tries = "";
953 }
954
955 $ni = new ilNumberInputGUI($this->lng->txt("qst_nr_of_tries"), "nr_of_tries");
956 $ni->setValue((string) $nr_tries);
957 $ni->setMinValue(0);
958 $ni->setSize(5);
959 $ni->setMaxLength(5);
960 $form->addItem($ni);
961 }
962
963 protected function saveTaxonomyAssignments(): void
964 {
965 if (count($this->getTaxonomyIds())) {
966 foreach ($this->getTaxonomyIds() as $taxonomyId) {
967 $postvar = "tax_node_assign_$taxonomyId";
968
969 $tax_node_assign = new ilTaxAssignInputGUI($taxonomyId, true, '', $postvar);
970 // TODO: determine tst/qpl when tax assigns become maintainable within tests
971 $tax_node_assign->saveInput("qpl", $this->object->getObjId(), "quest", $this->object->getId());
972 }
973 }
974 }
975
976 protected function populateTaxonomyFormSection(ilPropertyFormGUI $form): void
977 {
978 if ($this->getTaxonomyIds() !== []) {
979 $sectHeader = new ilFormSectionHeaderGUI();
980 $sectHeader->setTitle($this->lng->txt('qpl_qst_edit_form_taxonomy_section'));
981 $form->addItem($sectHeader);
982
983 foreach ($this->getTaxonomyIds() as $taxonomyId) {
984 $taxonomy = new ilObjTaxonomy($taxonomyId);
985 $label = sprintf($this->lng->txt('qpl_qst_edit_form_taxonomy'), $taxonomy->getTitle());
986 $postvar = "tax_node_assign_$taxonomyId";
987
988 $taxSelect = new ilTaxSelectInputGUI($taxonomy->getId(), $postvar, true);
989 $taxSelect->setTitle($label);
990
991
992 $taxNodeAssignments = new ilTaxNodeAssignment(ilObject::_lookupType($this->object->getObjId()), $this->object->getObjId(), 'quest', $taxonomyId);
993 $assignedNodes = $taxNodeAssignments->getAssignmentsOfItem($this->object->getId());
994
995 $taxSelect->setValue(array_map(function ($assignedNode) {
996 return $assignedNode['node_id'];
997 }, $assignedNodes));
998 $form->addItem($taxSelect);
999 }
1000 }
1001 }
1002
1006 public function getGenericFeedbackOutput(int $active_id, ?int $pass): string
1007 {
1008 $manual_feedback = ilObjTest::getManualFeedback($active_id, $this->object->getId(), $pass);
1009 if ($manual_feedback !== '') {
1010 return $manual_feedback;
1011 }
1012
1013 $output = $this->genericFeedbackOutputBuilder($active_id, $pass);
1014
1015 if ($this->object->isAdditionalContentEditingModePageObject()) {
1016 return $output;
1017 }
1018 return $this->renderLatex(ilLegacyFormElementsUtil::prepareTextareaOutput($output, true));
1019 }
1020
1022 int $active_id,
1023 ?int $pass
1024 ): string {
1025 if ($pass === null) {
1026 return '';
1027 }
1028 $reached_points = $this->object->calculateReachedPoints($active_id, $pass);
1029 $max_points = $this->object->getMaximumPoints();
1030
1031 $is_correct = false;
1032 if ($reached_points == $max_points) {
1033 $is_correct = true;
1034 }
1035
1036 return $this->object->feedbackOBJ->getGenericFeedbackTestPresentation(
1037 $this->object->getId(),
1038 $is_correct
1039 );
1040 }
1041
1043 {
1044 return $this->renderLatex(ilLegacyFormElementsUtil::prepareTextareaOutput(
1045 $this->object->feedbackOBJ->getGenericFeedbackTestPresentation($this->object->getId(), true),
1046 true
1047 ));
1048 }
1049
1051 {
1052 return $this->renderLatex(
1054 $this->object->feedbackOBJ->getGenericFeedbackTestPresentation($this->object->getId(), false),
1055 true
1056 )
1057 );
1058 }
1059
1060 public function outQuestionType(): string
1061 {
1062 $count = $this->questionrepository->usageCount($this->object->getId());
1063
1064 if ($this->questionrepository->questionExistsInPool($this->object->getId()) && $count) {
1065 if ($this->rbacsystem->checkAccess("write", $this->request_data_collector->getRefId())) {
1066 $this->tpl->setOnScreenMessage('info', sprintf($this->lng->txt("qpl_question_is_in_use"), $count));
1067 }
1068 }
1069
1070 return $this->lng->txt($this->object->getQuestionType());
1071 }
1072
1073 protected function getTypeOptions(): array
1074 {
1075 foreach (SuggestedSolution::TYPES as $k => $v) {
1076 $options[$k] = $this->lng->txt($v);
1077 }
1078 return $options;
1079 }
1080
1081 public function saveSuggestedSolution(): void
1082 {
1083 $this->suggestedsolution(true);
1084 }
1085
1086 public function cancelSuggestedSolution(): void
1087 {
1088 $this->suggestedsolution();
1089 }
1090
1091 public function suggestedsolution(bool $save = false): void
1092 {
1093 if ($save && $this->request_data_collector->int('deleteSuggestedSolution') === 1) {
1094 $this->object->deleteSuggestedSolutions();
1095 $this->tpl->setOnScreenMessage('success', $this->lng->txt("msg_obj_modified"), true);
1096 $this->ctrl->redirect($this, 'suggestedsolution');
1097 }
1098
1099 $output = '';
1100
1101 $solution = $this->object->getSuggestedSolution();
1102 $options = $this->getTypeOptions();
1103
1104 $solution_type = $this->ctrl->getCmd() === 'cancelSuggestedSolution'
1105 ? $solution->getType()
1106 : $this->request_data_collector->string('solutiontype');
1107 if ($solution_type === SuggestedSolution::TYPE_FILE
1108 && ($solution === null || $solution->getType() !== SuggestedSolution::TYPE_FILE)
1109 ) {
1110 $solution = $this->getSuggestedSolutionsRepo()->create(
1111 $this->object->getId(),
1112 SuggestedSolution::TYPE_FILE
1113 );
1114 }
1115
1116 $solution_filename = $this->request_data_collector->string('filename');
1117 if ($save && !empty($solution_filename)) {
1118 $solution = $solution->withTitle($solution_filename);
1119 }
1120
1121 if ($solution !== null) {
1122 $form = new ilPropertyFormGUI();
1123 $form->setFormAction($this->ctrl->getFormAction($this));
1124 $form->setTitle($this->lng->txt('solution_hint'));
1125 $form->setMultipart(true);
1126 $form->setTableWidth('100%');
1127 $form->setId('suggestedsolutiondisplay');
1128
1129 $title = new ilSolutionTitleInputGUI($this->lng->txt('showSuggestedSolution'), 'solutiontype');
1130 $template = new ilTemplate(
1131 'tpl.il_as_qpl_suggested_solution_input_presentation.html',
1132 true,
1133 true,
1134 'components/ILIAS/TestQuestionPool'
1135 );
1136
1137 if ($solution->isOfTypeLink()) {
1138 $href = $this->object->getInternalLinkHref($solution->getInternalLink());
1139 $template->setCurrentBlock('preview');
1140 $template->setVariable('TEXT_SOLUTION', $this->lng->txt('suggested_solution'));
1141 $template->setVariable(
1142 'VALUE_SOLUTION',
1143 " <a href='{$href}' target='content'>{$this->lng->txt('view')}</a> "
1144 );
1145 $template->parseCurrentBlock();
1146 } elseif (
1147 $solution->isOfTypeFile()
1148 && $solution->getFilename()
1149 ) {
1150 $href = $this->object->getSuggestedSolutionPathWeb() . $solution->getFilename();
1151 $link = " <a href='{$href}' target='content'>"
1152 . ilLegacyFormElementsUtil::prepareFormOutput($solution->getTitle())
1153 . '</a> ';
1154 $template->setCurrentBlock('preview');
1155 $template->setVariable('TEXT_SOLUTION', $this->lng->txt('suggested_solution'));
1156 $template->setVariable('VALUE_SOLUTION', $link);
1157 $template->parseCurrentBlock();
1158 }
1159
1160 $template->setVariable('TEXT_TYPE', $this->lng->txt('type'));
1161 $template->setVariable('VALUE_TYPE', $options[$solution->getType()]);
1162
1163 $title->setHtml($template->get());
1164 $deletesolution = new ilCheckboxInputGUI('', 'deleteSuggestedSolution');
1165 $deletesolution->setOptionTitle($this->lng->txt('deleteSuggestedSolution'));
1166 $title->addSubItem($deletesolution);
1167 $form->addItem($title);
1168
1169 if ($solution->isOfTypeFile()) {
1170 $file = new ilFileInputGUI($this->lng->txt('fileDownload'), 'file');
1171 $file->setRequired(true);
1172 $file->enableFileNameSelection('filename');
1173
1174 if ($save && $_FILES && $_FILES['file']['tmp_name'] && $file->checkInput()) {
1175 if (!file_exists($this->object->getSuggestedSolutionPath())) {
1176 ilFileUtils::makeDirParents($this->object->getSuggestedSolutionPath());
1177 }
1178
1180 $_FILES['file']['tmp_name'],
1181 $_FILES['file']['name'],
1182 $this->object->getSuggestedSolutionPath() . $_FILES['file']['name']
1183 );
1184 if ($res) {
1185 ilFileUtils::renameExecutables($this->object->getSuggestedSolutionPath());
1186
1187 // remove an old file download
1188 if ($solution->getFilename()) {
1189 @unlink($this->object->getSuggestedSolutionPath() . $solution->getFilename());
1190 }
1191
1192 $file->setValue($_FILES['file']['name']);
1193 $solution = $solution
1194 ->withFilename($_FILES['file']['name'])
1195 ->withMime($_FILES['file']['type'])
1196 ->withSize($_FILES['file']['size'])
1197 ->withTitle($this->request_data_collector->string('filename'));
1198
1199 $this->getSuggestedSolutionsRepo()->update([$solution]);
1200
1201 $this->tpl->setOnScreenMessage('success', $this->lng->txt('suggested_solution_added_successfully'), true);
1202 $this->ctrl->redirect($this, 'suggestedsolution');
1203 } else {
1204 // BH: $res as info string? wtf? it holds a bool or something else!!?
1205 $this->tpl->setOnScreenMessage('info', $res);
1206 }
1207 } else {
1208 if ($solution->getFilename()) {
1209 $file->setValue($solution->getFilename());
1210 $file->setFilename($solution->getTitle());
1211 }
1212 }
1213 $form->addItem($file);
1214 $hidden = new ilHiddenInputGUI('solutiontype');
1215 $hidden->setValue('file');
1216 $form->addItem($hidden);
1217 }
1218 if ($this->access->checkAccess('write', '', $this->request_data_collector->getRefId())) {
1219 $form->addCommandButton('cancelSuggestedSolution', $this->lng->txt('cancel'));
1220 $form->addCommandButton('saveSuggestedSolution', $this->lng->txt('save'));
1221 }
1222
1223 if ($save) {
1224 if ($form->checkInput()) {
1225 if ($solution->isOfTypeFile()) {
1226 $solution = $solution->withTitle($this->request_data_collector->string('filename'));
1227 }
1228
1229 if (!$solution->isOfTypeLink()) {
1230 $this->getSuggestedSolutionsRepo()->update([$solution]);
1231 }
1232
1233 $this->tpl->setOnScreenMessage('success', $this->lng->txt('msg_obj_modified'), true);
1234 $this->ctrl->redirect($this, 'suggestedsolution');
1235 }
1236 }
1237
1238 $output = $form->getHTML();
1239 }
1240
1241 $savechange = $this->ctrl->getCmd() === 'saveSuggestedSolutionType';
1242
1243 $changeoutput = '';
1244 if ($this->access->checkAccess('write', '', $this->request_data_collector->getRefId())) {
1245 $formchange = new ilPropertyFormGUI();
1246 $formchange->setFormAction($this->ctrl->getFormAction($this));
1247
1248 $title = $solution ? $this->lng->txt('changeSuggestedSolution') : $this->lng->txt('addSuggestedSolution');
1249 $formchange->setTitle($title);
1250 $formchange->setMultipart(false);
1251 $formchange->setTableWidth('100%');
1252 $formchange->setId('suggestedsolution');
1253
1254 $solutiontype = new ilRadioGroupInputGUI($this->lng->txt('suggestedSolutionType'), 'solutiontype');
1255 foreach ($options as $opt_value => $opt_caption) {
1256 $solutiontype->addOption(new ilRadioOption($opt_caption, $opt_value));
1257 }
1258 if ($solution) {
1259 $solutiontype->setValue($solution->getType());
1260 }
1261 $solutiontype->setRequired(true);
1262 $formchange->addItem($solutiontype);
1263
1264 $formchange->addCommandButton('saveSuggestedSolutionType', $this->lng->txt('select'));
1265
1266 if ($savechange) {
1267 $formchange->checkInput();
1268 }
1269 $changeoutput = $formchange->getHTML();
1270 }
1271 $this->tabs_gui->activateTab('suggested_solution');
1272 $this->tpl->setVariable('ADM_CONTENT', $changeoutput . $output);
1273 }
1274
1275 public function outSolutionExplorer(): void
1276 {
1277 $type = $this->request_data_collector->string("link_new_type");
1278 $search = $this->request_data_collector->string("search_link_type");
1279 $this->ctrl->setParameter($this, "link_new_type", $type);
1280 $this->ctrl->setParameter($this, "search_link_type", $search);
1281 $this->ctrl->saveParameter($this, ["subquestion_index", "link_new_type", "search_link_type"]);
1282
1283 $this->tpl->setOnScreenMessage('info', $this->lng->txt("select_object_to_link"));
1284
1285 $parent_ref_id = $this->tree->getParentId($this->request_data_collector->getRefId());
1286 $exp = new ilSolutionExplorer($this->ctrl->getLinkTarget($this, 'suggestedsolution'), get_class($this));
1287 $exp->setExpand($this->request_data_collector->raw('expand_sol') ? $this->request_data_collector->raw('expand_sol') : $parent_ref_id);
1288 $exp->setExpandTarget($this->ctrl->getLinkTarget($this, 'outSolutionExplorer'));
1289 $exp->setTargetGet("ref_id");
1290 $exp->setRefId($this->request_data_collector->getRefId());
1291 $exp->addFilter($type);
1292 $exp->setSelectableType($type);
1293 if ($this->request_data_collector->isset('expandCurrentPath') && $this->request_data_collector->raw('expandCurrentPath')) {
1294 $exp->expandPathByRefId($parent_ref_id);
1295 }
1296
1297 // build html-output
1298 $exp->setOutput(0);
1299
1300 $template = new ilTemplate("tpl.il_as_qpl_explorer.html", true, true, "components/ILIAS/TestQuestionPool");
1301 $template->setVariable("EXPLORER_TREE", $exp->getOutput());
1302 $template->setVariable("BUTTON_CANCEL", $this->lng->txt("cancel"));
1303 $template->setVariable("FORMACTION", $this->ctrl->getFormAction($this, "suggestedsolution"));
1304 $this->tpl->setVariable("ADM_CONTENT", $template->get());
1305 }
1306
1307 public function saveSuggestedSolutionType(): void
1308 {
1309 $solution_type = $this->request_data_collector->string('solutiontype');
1310
1311 switch ($solution_type) {
1312 case 'lm':
1313 $type = 'lm';
1314 $search = 'lm';
1315 break;
1316 case 'git':
1317 $type = 'glo';
1318 $search = 'glo';
1319 break;
1320 case 'st':
1321 $type = 'lm';
1322 $search = 'st';
1323 break;
1324 case 'pg':
1325 $type = 'lm';
1326 $search = 'pg';
1327 break;
1328 case 'file':
1329 case 'text':
1330 default:
1331 $this->suggestedsolution();
1332 return;
1333 }
1334
1335 if (isset($solution_type)) {
1336 $this->ctrl->setParameter($this, 'expandCurrentPath', 1);
1337 }
1338 $this->ctrl->setParameter($this, 'link_new_type', $type);
1339 $this->ctrl->setParameter($this, 'search_link_type', $search);
1340 $this->ctrl->redirect($this, 'outSolutionExplorer');
1341 }
1342
1343 public function cancelExplorer(): void
1344 {
1345 $this->ctrl->redirect($this, 'suggestedsolution');
1346 }
1347
1348 public function outPageSelector(): void
1349 {
1350 $this->ctrl->setParameter($this, 'q_id', $this->object->getId());
1351
1352 $cont_obj_gui = new ilObjContentObjectGUI('', $this->request_data_collector->int('source_id'), true);
1353 $cont_obj = $cont_obj_gui->getObject();
1354 $pages = ilLMPageObject::getPageList($cont_obj->getId());
1355 $shownpages = [];
1356 $tree = $cont_obj->getLMTree();
1357 $chapters = $tree->getSubtree($tree->getNodeData($tree->getRootId()));
1358
1359 $rows = [];
1360
1361 foreach ($chapters as $chapter) {
1362 $chapterpages = $tree->getChildsByType($chapter['obj_id'], 'pg');
1363 foreach ($chapterpages as $page) {
1364 if ($page['type'] == $this->request_data_collector->raw('search_link_type')) {
1365 array_push($shownpages, $page['obj_id']);
1366
1367 if ($tree->isInTree($page['obj_id'])) {
1368 $path_str = $this->getContextPath($cont_obj, $page['obj_id']);
1369 } else {
1370 $path_str = '---';
1371 }
1372
1373 $this->ctrl->setParameter($this, $page['type'], $page['obj_id']);
1374 $rows[] = [
1375 'title' => $page['title'],
1376 'description' => ilLegacyFormElementsUtil::prepareFormOutput($path_str),
1377 'text_add' => $this->lng->txt('add'),
1378 'href_add' => $this->ctrl->getLinkTarget($this, 'add' . strtoupper($page['type']))
1379 ];
1380 }
1381 }
1382 }
1383 foreach ($pages as $page) {
1384 if (!in_array($page['obj_id'], $shownpages)) {
1385 $this->ctrl->setParameter($this, $page['type'], $page['obj_id']);
1386 $rows[] = [
1387 'title' => $page['title'],
1388 'description' => '---',
1389 'text_add' => $this->lng->txt('add'),
1390 'href_add' => $this->ctrl->getLinkTarget($this, 'add' . strtoupper($page['type']))
1391 ];
1392 }
1393 }
1394
1395 $table = new ilQuestionInternalLinkSelectionTableGUI($this, 'cancelExplorer', __METHOD__);
1396 $table->setTitle($this->lng->txt('obj_' . ilUtil::stripSlashes($this->request_data_collector->string('search_link_type'))));
1397 $table->setData($rows);
1398
1399 $this->tpl->setContent($table->getHTML());
1400 }
1401
1402 public function outChapterSelector(): void
1403 {
1404 $this->ctrl->setParameter($this, 'q_id', $this->object->getId());
1405
1406 $cont_obj_gui = new ilObjContentObjectGUI('', $this->request_data_collector->int('source_id'), true);
1407 $cont_obj = $cont_obj_gui->getObject();
1408 $ctree = $cont_obj->getLMTree();
1409 $nodes = $ctree->getSubtree($ctree->getNodeData($ctree->getRootId()));
1410
1411 $rows = [];
1412
1413 foreach ($nodes as $node) {
1414 if ($node['type'] == $this->request_data_collector->raw('search_link_type')) {
1415 $this->ctrl->setParameter($this, $node['type'], $node['obj_id']);
1416 $rows[] = [
1417 'title' => $node['title'],
1418 'description' => '',
1419 'text_add' => $this->lng->txt('add'),
1420 'href_add' => $this->ctrl->getLinkTarget($this, 'add' . strtoupper($node['type']))
1421 ];
1422 }
1423 }
1424
1425 $table = new ilQuestionInternalLinkSelectionTableGUI($this, 'cancelExplorer', __METHOD__);
1426 $table->setTitle($this->lng->txt('obj_' . ilUtil::stripSlashes($this->request_data_collector->string('search_link_type'))));
1427 $table->setData($rows);
1428
1429 $this->tpl->setContent($table->getHTML());
1430 }
1431
1432 public function outGlossarySelector(): void
1433 {
1434 $this->ctrl->setParameter($this, 'q_id', $this->object->getId());
1435
1436 $glossary = new ilObjGlossary($this->request_data_collector->int('source_id'), true);
1437 $terms = $glossary->getTermList();
1438
1439 $rows = [];
1440
1441 foreach ($terms as $term) {
1442 $this->ctrl->setParameter($this, 'git', $term['id']);
1443 $rows[] = [
1444 'title' => $term['term'],
1445 'description' => '',
1446 'text_add' => $this->lng->txt('add'),
1447 'href_add' => $this->ctrl->getLinkTarget($this, 'addGIT')
1448 ];
1449 }
1450
1451 $table = new ilQuestionInternalLinkSelectionTableGUI($this, 'cancelExplorer', __METHOD__);
1452 $table->setTitle($this->lng->txt('glossary_term'));
1453 $table->setData($rows);
1454
1455 $this->tpl->setContent($table->getHTML());
1456 }
1457
1458 protected function createSuggestedSolutionLinkingTo(string $type, string $target)
1459 {
1460 $repo = $this->getSuggestedSolutionsRepo();
1461 $question_id = $this->object->getId();
1462 $subquestion_index = $this->request_data_collector->int('subquestion_index');
1463 $subquestion_index = ($subquestion_index > 0) ? $subquestion_index : 0;
1464
1465 $solution = $repo->create($question_id, $type)
1466 ->withSubquestionIndex($subquestion_index)
1467 ->withInternalLink($target);
1468
1469 $repo->update([$solution]);
1470 }
1471
1472 public function linkChilds(): void
1473 {
1474 $this->ctrl->saveParameter($this, ["subquestion_index", "link_new_type", "search_link_type"]);
1475 switch ($this->request_data_collector->string("search_link_type")) {
1476 case "pg":
1477 $this->outPageSelector();
1478 break;
1479 case "st":
1480 $this->outChapterSelector();
1481 break;
1482 case "glo":
1483 $this->outGlossarySelector();
1484 break;
1485 case "lm":
1486 $target = "il__lm_" . $this->request_data_collector->raw("source_id");
1487 $this->createSuggestedSolutionLinkingTo('lm', $target);
1488 $this->tpl->setOnScreenMessage('success', $this->lng->txt("suggested_solution_added_successfully"), true);
1489 $this->ctrl->redirect($this, 'suggestedsolution');
1490 break;
1491 }
1492 }
1493
1494 public function addPG(): void
1495 {
1496 $target = "il__pg_" . $this->request_data_collector->raw("pg");
1497 $this->createSuggestedSolutionLinkingTo('pg', $target);
1498 $this->tpl->setOnScreenMessage('success', $this->lng->txt("suggested_solution_added_successfully"), true);
1499 $this->ctrl->redirect($this, 'suggestedsolution');
1500 }
1501
1502 public function addST(): void
1503 {
1504 $target = "il__st_" . $this->request_data_collector->raw("st");
1505 $this->createSuggestedSolutionLinkingTo('st', $target);
1506 $this->tpl->setOnScreenMessage('success', $this->lng->txt("suggested_solution_added_successfully"), true);
1507 $this->ctrl->redirect($this, 'suggestedsolution');
1508 }
1509
1510 public function addGIT(): void
1511 {
1512 $target = "il__git_" . $this->request_data_collector->raw("git");
1513 $this->createSuggestedSolutionLinkingTo('git', $target);
1514 $this->tpl->setOnScreenMessage('success', $this->lng->txt("suggested_solution_added_successfully"), true);
1515 $this->ctrl->redirect($this, 'suggestedsolution');
1516 }
1517
1518 public function isSaveCommand(): bool
1519 {
1520 return in_array($this->ctrl->getCmd(), self::QUESTION_SAVE_CMDS);
1521 }
1522
1523 public static function getCommandsFromClassConstants(
1524 string $guiClassName,
1525 string $cmdConstantNameBegin = 'CMD_'
1526 ): array {
1527 $reflectionClass = new ReflectionClass($guiClassName);
1528
1529 $commands = null;
1530
1531 if ($reflectionClass instanceof ReflectionClass) {
1532 $commands = [];
1533
1534 foreach ($reflectionClass->getConstants() as $constName => $constValue) {
1535 if (substr($constName, 0, strlen($cmdConstantNameBegin)) == $cmdConstantNameBegin) {
1536 $commands[] = $constValue;
1537 }
1538 }
1539 }
1540
1541 return $commands;
1542 }
1543
1544 public function setQuestionTabs(): void
1545 {
1546 $this->tabs_gui->clearTargets();
1547
1548 if ($this->object->getId() > 0) {
1549 $this->setDefaultTabs($this->tabs_gui);
1550 $this->setQuestionSpecificTabs($this->tabs_gui);
1551 $this->tabs_gui->activateTab('edit_question');
1552 }
1553 $this->addBackTab($this->tabs_gui);
1554 }
1555
1556 protected function setDefaultTabs(ilTabsGUI $tabs_gui): void
1557 {
1558 $this->ctrl->setParameterByClass(ilAssQuestionPageGUI::class, 'q_id', $this->object->getId());
1559 $this->ctrl->setParameterByClass(static::class, 'q_id', $this->object->getId());
1560
1561 $this->addTab_Question($tabs_gui);
1562 $this->addTab_QuestionFeedback($tabs_gui);
1563 $this->addTab_SuggestedSolution($tabs_gui, static::class);
1564 }
1565
1566 protected function setQuestionSpecificTabs(ilTabsGUI $tabs_gui): void
1567 {
1568 }
1569
1570 public function addTab_SuggestedSolution(ilTabsGUI $tabs, string $classname): void
1571 {
1572 $this->ctrl->setParameterByClass($classname, 'q_id', $this->object->getId());
1573 $tabs->addTarget(
1574 'suggested_solution',
1575 $this->ctrl->getLinkTargetByClass($classname, 'suggestedsolution'),
1576 [
1577 'suggestedsolution',
1578 'saveSuggestedSolution',
1579 'outSolutionExplorer',
1580 'cancel',
1581 'addSuggestedSolution',
1582 'cancelExplorer' ,
1583 'linkChilds',
1584 'removeSuggestedSolution'
1585 ]
1586 );
1587 }
1588
1589 final public function getEditQuestionTabCommands(): array
1590 {
1591 return array_merge($this->getBasicEditQuestionTabCommands(), $this->getAdditionalEditQuestionCommands());
1592 }
1593
1594 protected function getBasicEditQuestionTabCommands(): array
1595 {
1596 return ['editQuestion', 'save', 'originalSyncForm'];
1597 }
1598
1599 protected function getAdditionalEditQuestionCommands(): array
1600 {
1601 return [];
1602 }
1603
1604 protected function addTab_QuestionFeedback(ilTabsGUI $tabs): void
1605 {
1606 $tabCommands = self::getCommandsFromClassConstants(ilAssQuestionFeedbackEditingGUI::class);
1607
1608 $this->ctrl->setParameterByClass(ilAssQuestionFeedbackEditingGUI::class, 'q_id', $this->object->getId());
1609 $tabLink = $this->ctrl->getLinkTargetByClass(ilAssQuestionFeedbackEditingGUI::class, ilAssQuestionFeedbackEditingGUI::CMD_SHOW);
1610
1611 $tabs->addTarget('feedback', $tabLink, $tabCommands, $this->ctrl->getCmdClass(), '');
1612 }
1613
1614 protected function addTab_Question(ilTabsGUI $tabs_gui): void
1615 {
1616 $tabs_gui->addTarget(
1617 'edit_question',
1618 $this->ctrl->getLinkTargetByClass(
1619 static::class,
1620 'editQuestion'
1621 ),
1622 'editQuestion',
1623 '',
1624 '',
1625 false
1626 );
1627 }
1628
1629 protected function hasCorrectSolution($activeId, $passIndex): bool
1630 {
1631 $reachedPoints = $this->object->getAdjustedReachedPoints((int) $activeId, (int) $passIndex, true);
1632 $maximumPoints = $this->object->getMaximumPoints();
1633
1634 return $reachedPoints == $maximumPoints;
1635 }
1636
1637 public function isAutosaveable(): bool
1638 {
1639 return $this->object instanceof QuestionAutosaveable;
1640 }
1641
1642 protected function writeQuestionGenericPostData(): void
1643 {
1644 $this->object->setTitle($this->request_data_collector->string('title'));
1645 $this->object->setAuthor($this->request_data_collector->string('author'));
1646 $this->object->setComment($this->request_data_collector->string('comment'));
1647
1648 $nr_of_tries = $this->request_data_collector->int('nr_of_tries');
1649 if ($this->object->getSelfAssessmentEditingMode()) {
1650 $this->object->setNrOfTries($nr_of_tries);
1651 }
1652
1653 try {
1655 $this->request_data_collector->string('lifecycle')
1656 );
1657 $this->object->setLifecycle($lifecycle);
1659 }
1660
1661 $this->object->setQuestion(
1663 $this->request_data_collector->string('question')
1664 )
1665 );
1666
1667 $this->setTestSpecificProperties();
1668 }
1669
1670 final public function outQuestionForTest(
1671 string $formaction,
1672 int $active_id,
1673 ?int $pass,
1674 bool $is_question_postponed = false,
1675 array|bool $user_post_solutions = false,
1676 bool $show_specific_inline_feedback = false
1677 ): void {
1678 $formaction = $this->completeTestOutputFormAction($formaction, $active_id, $pass);
1679
1680 $test_output = $this->getTestOutput(
1681 $active_id,
1682 $pass,
1683 $is_question_postponed,
1684 $user_post_solutions,
1685 $show_specific_inline_feedback
1686 );
1687
1688 $this->magicAfterTestOutput();
1689
1690 $this->tpl->setVariable("QUESTION_OUTPUT", $test_output);
1691 $this->tpl->setVariable("FORMACTION", $formaction);
1692 $this->tpl->setVariable("ENCTYPE", 'enctype="' . $this->getFormEncodingType() . '"');
1693 $this->tpl->setVariable("FORM_TIMESTAMP", (string) time());
1694 }
1695
1697 string $form_action,
1698 int $active_id,
1699 int $pass
1700 ): string {
1701 return $form_action;
1702 }
1703
1704 public function magicAfterTestOutput(): void
1705 {
1706 return;
1707 }
1708
1709 public function getFormEncodingType(): string
1710 {
1711 return self::FORM_ENCODING_URLENCODE;
1712 }
1713
1714 protected function addBackTab(ilTabsGUI $tabs_gui): void
1715 {
1716 if ($this->object->getId() <= 0) {
1717 $tabs_gui->setBackTarget(
1718 $this->lng->txt('cancel'),
1719 $this->ctrl->getParentReturnByClass(
1721 ilObject::_lookupType($this->object->getObjId())
1722 ) . 'GUI'
1723 )
1724 );
1725 return;
1726 }
1727 $this->ctrl->setParameterByClass(
1728 ilAssQuestionPreviewGUI::class,
1729 'q_id',
1730 $this->object->getId()
1731 );
1732 $this->ctrl->saveParameterByClass(ilAssQuestionPreviewGUI::class, 'prev_qid');
1733 $tabs_gui->setBackTarget(
1734 $this->lng->txt('backtocallingpage'),
1735 $this->ctrl->getLinkTargetByClass(
1736 ilAssQuestionPreviewGUI::class,
1738 )
1739 );
1740 $this->ctrl->clearParameterByClass(ilAssQuestionPreviewGUI::class, 'prev_qid');
1741 }
1742
1743 public function setPreviewSession(ilAssQuestionPreviewSession $preview_session): void
1744 {
1745 $this->preview_session = $preview_session;
1746 }
1747
1752 {
1753 return $this->preview_session;
1754 }
1755
1757 {
1758 $form = new ilPropertyFormGUI();
1759 $form->setFormAction($this->ctrl->getFormAction($this));
1760 $form->setId($this->getType());
1761 $form->setTitle($this->outQuestionType());
1762 $form->setTableWidth('100%');
1763 $form->setMultipart(true);
1764 return $form;
1765 }
1766
1767 protected function escapeTemplatePlaceholders(string $text): string
1768 {
1769 return str_replace(['{','}'], ['&#123;','&#125;'], $text);
1770 }
1771
1772 protected function buildEditForm(): ilPropertyFormGUI
1773 {
1774 $this->editQuestion(true); // TODO bheyser: editQuestion should be added to the abstract base class with a unified signature
1775 return $this->editForm;
1776 }
1777
1778 public function buildFocusAnchorHtml(): string
1779 {
1780 return '<div id="focus"></div>';
1781 }
1782
1784 {
1785 return true;
1786 }
1787
1788 public function getSubQuestionsIndex(): array
1789 {
1790 return [0];
1791 }
1792
1793 public function getAnswersFrequency($relevantAnswers, $questionIndex): array
1794 {
1795 return [];
1796 }
1797
1798 public function getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex): ilAnswerFrequencyStatisticTableGUI
1799 {
1800 $table = new ilAnswerFrequencyStatisticTableGUI($parentGui, $parentCmd, $this->object);
1801 $table->setQuestionIndex($questionIndex);
1802 $table->setData($this->getAnswersFrequency($relevantAnswers, $questionIndex));
1803 $table->initColumns();
1804 return $table;
1805 }
1806
1808 {
1809 }
1810
1812 {
1813 }
1814
1816 {
1817 }
1818
1819
1820 protected function generateCorrectnessIconsForCorrectness(int $correctness): string
1821 {
1822 switch ($correctness) {
1823 case self::CORRECTNESS_NOT_OK:
1824 $icon_name = 'standard/icon_not_ok.svg';
1825 $label = $this->lng->txt("answer_is_wrong");
1826 break;
1827 case self::CORRECTNESS_MOSTLY_OK:
1828 $icon_name = 'standard/icon_mostly_ok.svg';
1829 $label = $this->lng->txt("answer_is_not_correct_but_positive");
1830 break;
1831 case self::CORRECTNESS_OK:
1832 $icon_name = 'standard/icon_ok.svg';
1833 $label = $this->lng->txt("answer_is_right");
1834 break;
1835 default:
1836 return '';
1837 }
1838 $path = ilUtil::getImagePath($icon_name);
1839 $icon = $this->ui->factory()->symbol()->icon()->custom(
1840 $path,
1841 $label
1842 );
1843 return $this->ui->renderer()->render($icon);
1844 }
1845
1854 public static function prepareTextareaOutput(
1855 ?string $txt_output,
1856 bool $prepare_for_latex_output = false,
1857 bool $omitNl2BrWhenTextArea = false
1858 ): string {
1859 if ($txt_output === null || $txt_output === '') {
1860 return '';
1861 }
1862
1863 $result = $txt_output;
1864 $is_html = false;
1865
1866 if (strlen(strip_tags($result)) < strlen($result)) {
1867 $is_html = true;
1868 }
1869
1870 // removed: did not work with magic_quotes_gpc = On
1871 if (!$is_html) {
1872 if (!$omitNl2BrWhenTextArea) {
1873 // if the string does not contain HTML code, replace the newlines with HTML line breaks
1874 $result = preg_replace("/[\n]/", "<br />", $result);
1875 }
1876 } else {
1877 // patch for problems with the <pre> tags in tinyMCE
1878 if (preg_match_all("/(<pre>.*?<\/pre>)/ims", $result, $matches)) {
1879 foreach ($matches[0] as $found) {
1880 $replacement = "";
1881 if (strpos("\n", $found) === false) {
1882 $replacement = "\n";
1883 }
1884 $removed = preg_replace("/<br\s*?\/>/ims", $replacement, $found);
1885 $result = str_replace($found, $removed, $result);
1886 }
1887 }
1888 }
1889
1890 if ($prepare_for_latex_output) {
1891 $result = ilRTE::replaceLatexSpan($result);
1892
1893 // replace special characters to prevent problems with the ILIAS template system
1894 // eg. if someone uses {1} as an answer, nothing will be shown without the replacement
1895 $result = str_replace("{", "&#123;", $result);
1896 $result = str_replace("}", "&#125;", $result);
1897 $result = str_replace("\\", "&#92;", $result);
1898 }
1899
1900 return $result;
1901 }
1902
1906 protected function renderLatex($content)
1907 {
1908 return $this->ui->renderer()->render($this->ui->factory()->legacy()->latexContent($content));
1909 }
1910
1911 protected ?SuggestedSolutionsDatabaseRepository $suggestedsolution_repo = null;
1913 {
1914 if (is_null($this->suggestedsolution_repo)) {
1915 $dic = QuestionPoolDIC::dic();
1916 $this->suggestedsolution_repo = $dic['question.repo.suggestedsolutions'];
1917 }
1918 return $this->suggestedsolution_repo;
1919 }
1920
1925 protected function cleanupAnswerText(array $answer_text, bool $is_rte): array
1926 {
1927 if (!is_array($answer_text)) {
1928 return [];
1929 }
1930
1931 if ($is_rte) {
1933 $answer_text,
1934 false,
1936 );
1937 }
1938
1940 $answer_text,
1941 true,
1942 self::ALLOWED_PLAIN_TEXT_TAGS
1943 );
1944 }
1945
1946 public function isInLearningModuleContext(): bool
1947 {
1948 return $this->parent_type_is_lm;
1949 }
1950 public function setInLearningModuleContext(bool $flag): void
1951 {
1952 $this->parent_type_is_lm = $flag;
1953 }
1954
1955 protected function addSaveOnEnterOnLoadCode(): void
1956 {
1957 $this->tpl->addOnloadCode("
1958 let form = document.querySelector('#ilContentContainer form');
1959 let button = form.querySelector('input[name=\"cmd[save]\"]');
1960 if (form && button) {
1961 form.addEventListener('keydown', function (e) {
1962 if (e.key === 'Enter'
1963 && e.target.type !== 'textarea'
1964 && e.target.type !== 'submit'
1965 && e.target.type !== 'file'
1966 ) {
1967 e.preventDefault();
1968 form.requestSubmit(button);
1969 }
1970 })
1971 }
1972 ");
1973 }
1974
1975 public function cmdNeedsExistingQuestion(string $cmd): bool
1976 {
1977 return in_array($cmd, static::ADDITIONAL_CMDS_NEEDING_EXISTING_QST);
1978 }
1979
1980 public function setContextAllowsSyncToPool(bool $sync_allowed): void
1981 {
1982 $this->context_allows_sync_to_pool = $sync_allowed;
1983 }
1984
1985 public function needsSyncQuery(): bool
1986 {
1987 return $this->context_allows_sync_to_pool
1988 && $this->object->hasWritableOriginalInQuestionPool();
1989 }
1990
1991 public function getQuestionSyncModal(string $cmd, string $cmd_class = ''): string
1992 {
1993 if ($cmd_class === '') {
1994 $cmd_class = static::class;
1995 }
1996 $modal = $this->ui->factory()->modal()->interruptive(
1997 $this->lng->txt('confirm'),
1998 $this->lng->txt('confirm_sync_questions'),
1999 $this->ctrl->getFormActionByClass($cmd_class, $cmd)
2000 )->withAffectedItems([
2001 $this->ui->factory()->modal()->interruptiveItem()->standard(
2002 (string) $this->object->getOriginalId(),
2003 $this->object->getTitleForHTMLOutput()
2004 )
2005 ])->withActionButtonLabel($this->lng->txt('sync_question_to_pool'));
2006 return $this->ui->renderer()->render(
2007 $modal->withOnLoad($modal->getShowSignal())
2008 );
2009 }
2010
2012 int $active_id,
2013 int $pass,
2014 bool $graphical_output = false,
2015 bool $result_output = false,
2016 bool $show_question_only = true,
2017 bool $show_feedback = false,
2018 bool $show_correct_solution = false,
2019 bool $show_manual_scoring = false,
2020 bool $show_question_text = true,
2021 bool $show_autosave_title = false,
2022 bool $show_inline_feedback = false
2023 ): ?string {
2024 $autosave_solutions = $this->object->getSolutionValues($active_id, $pass, false);
2025 if ($autosave_solutions === []) {
2026 return null;
2027 }
2028 return $this->renderSolutionOutput(
2029 $autosave_solutions,
2030 $active_id,
2031 $pass,
2032 $graphical_output,
2033 $result_output,
2034 $show_question_only,
2035 $show_feedback,
2036 $show_correct_solution,
2037 $show_manual_scoring,
2038 $show_question_text,
2039 $show_autosave_title,
2040 $show_inline_feedback
2041 );
2042 }
2043
2044 public function buildFileDownloadLink(): string
2045 {
2046 if (strtolower($this->request_data_collector->string('cmdClass')) === 'ilassquestionpreviewgui') {
2047 return $this->ctrl->getLinkTargetByClass(ilObjQuestionPoolGUI::class, 'downloadFile');
2048 }
2049 return $this->ctrl->getLinkTargetByClass(ilObjTestGUI::class, 'downloadFile');
2050 }
2051
2052 protected function resetSavedPreviewSession(): void
2053 {
2054 $this->preview_session = new ilAssQuestionPreviewSession(
2055 $this->current_user->getId(),
2056 $this->object->getId()
2057 );
2058 $this->preview_session->setRandomizerSeed(null);
2059 $this->preview_session->setParticipantsSolution(null);
2060 $this->preview_session->setInstantResponseActive(false);
2061 }
2062}
$lifecycle
Builds data types.
Definition: Factory.php:36
cmdNeedsExistingQuestion(string $cmd)
populateTaxonomyFormSection(ilPropertyFormGUI $form)
setInLearningModuleContext(bool $flag)
getAsValueAttribute(string $a_value)
getQuestionSyncModal(string $cmd, string $cmd_class='')
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
const SESSION_PREVIEW_DATA_BASE_INDEX
setMoveAfterQuestionId(?int $question_id)
ilAssQuestionPreviewSession $preview_session
getAutoSavedSolutionOutput(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)
const SUGGESTED_SOLUTION_COMMANDS_SAVE
addTab_Question(ilTabsGUI $tabs_gui)
getType()
needed for page editor compliance
const ALLOWED_PLAIN_TEXT_TAGS
sk - 12.05.2023: This const is also used in ilKprimChoiceWizardInputGUI.
outQuestionForTest(string $formaction, int $active_id, ?int $pass, bool $is_question_postponed=false, array|bool $user_post_solutions=false, bool $show_specific_inline_feedback=false)
completeTestOutputFormAction(string $form_action, int $active_id, int $pass)
setCopyToNewPoolOnSave(?string $pool_title)
renderLatex($content)
Wrap content with latex in a LatexContent UI component and render it to be processed by MathJax in th...
ilObjectDataCache $ilObjDataCache
getContextPath($cont_obj, int $a_endnode_id, int $a_startnode_id=1)
get context path in content object tree
static getCommandsFromClassConstants(string $guiClassName, string $cmdConstantNameBegin='CMD_')
getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex)
static _getQuestionGUI(string $question_type='', int $question_id=-1)
Creates a question gui representation and returns the alias to the question gui.
int $sequence_no
sequence number in test
escapeTemplatePlaceholders(string $text)
addBackTab(ilTabsGUI $tabs_gui)
editQuestion(bool $checkonly=false, ?bool $is_save_cmd=null)
setPreviousSolutionPrefilled(bool $previousSolutionPrefilled)
setQuestionSpecificTabs(ilTabsGUI $tabs_gui)
setPresentationContext(string $presentationContext)
readonly RequestDataCollector $request_data_collector
readonly ilTestLegacyFormsHelper $forms_helper
setTargetGui($linkTargetGui)
const ADDITIONAL_CMDS_NEEDING_EXISTING_QST
There are functions that need an existing question.
setRenderPurpose(string $renderPurpose)
getILIASPage(string $html="")
Returns the ILIAS Page around a question.
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
ilComponentRepository $component_repository
ilGlobalPageTemplate $tpl
prepareReprintableCorrectionsForm(ilPropertyFormGUI $form)
addBasicQuestionFormProperties(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)
setQuestionHeaderBlockBuilder(\ilQuestionHeaderBlockBuilder $questionHeaderBlockBuilder)
renderEditForm(ilPropertyFormGUI $form)
int $question_count
question count in test
setObject(assQuestion $question)
getPreview(bool $show_question_only=false, bool $show_inline_feedback=false)
setTargetGuiClass(string $targetGuiClass)
cleanupAnswerText(array $answer_text, bool $is_rte)
sk - 12.05.2023: This is one more of those that we need, but don't want.
addTab_SuggestedSolution(ilTabsGUI $tabs, string $classname)
setPreviewSession(ilAssQuestionPreviewSession $preview_session)
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
const SUGGESTED_SOLUTION_COMMANDS_DEFAULT
createSuggestedSolutionLinkingTo(string $type, string $target)
ilRbacSystem $rbacsystem
getGenericFeedbackOutput(int $active_id, ?int $pass)
getSpecificFeedbackOutput(array $userSolution)
Returns the answer specific feedback for the question.
setContextAllowsSyncToPool(bool $sync_allowed)
getAnswersFrequency($relevantAnswers, $questionIndex)
addErrorMessage(string $errormessage)
populateJavascriptFilesRequiredForWorkForm(ilGlobalTemplateInterface $tpl)
genericFeedbackOutputBuilder(int $active_id, ?int $pass)
setDefaultTabs(ilTabsGUI $tabs_gui)
setEditContext(string $editContext)
setCopyToExistingPoolOnSave(?int $pool_ref_id)
setQuestionCount(int $a_question_count)
addQuestionFormCommandButtons(ilPropertyFormGUI $form)
static prepareTextareaOutput(?string $txt_output, bool $prepare_for_latex_output=false, bool $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output where latex code may be in it If the text is HTML-free,...
ilQuestionHeaderBlockBuilder $questionHeaderBlockBuilder
setErrorMessage(string $errormessage)
ilTestQuestionNavigationGUI $navigationGUI
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)
ilPropertyFormGUI $editForm
writePostData(bool $always=false)
Evaluates a posted edit form and writes the form data in the question object.
setTaxonomyIds(array $taxonomyIds)
GeneralQuestionPropertiesRepository $questionrepository
hasCorrectSolution($activeId, $passIndex)
suggestedsolution(bool $save=false)
addTab_QuestionFeedback(ilTabsGUI $tabs)
setQuestionActionCmd(string $questionActionCmd)
const SUGGESTED_SOLUTION_COMMANDS_CANCEL
generateCorrectnessIconsForCorrectness(int $correctness)
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,)
ilAccessHandler $access
setNavigationGUI(?ilTestQuestionNavigationGUI $navigationGUI)
addNumberOfTriesToFormIfNecessary(ilPropertyFormGUI $form)
const ADDITIONAL_CONTENT_EDITING_MODE_IPE
static getFeedbackClassNameByQuestionType(string $questionType)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static stripSlashesRecursive($a_data, bool $a_strip_html=true, string $a_allow="")
Question page GUI class.
static getSelfAssessmentTags()
Get tags allowed in question tags in self assessment mode.
This class represents a checkbox property in a property form.
Class ilCommonActionDispatcherGUI.
Class ilCtrl provides processing control methods.
This class represents a file property in a property form.
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
static renameExecutables(string $a_dir)
static moveUploadedFile(string $a_file, string $a_name, string $a_target, bool $a_raise_errors=true, string $a_mode="move_uploaded")
move uploaded file
This class represents a section header in a property form.
get(string $part=self::DEFAULT_BLOCK)
Renders the given block and returns the html string.
setVariable(string $variable, $value='')
Sets the given variable to the given value.
Help GUI class.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This class represents a hidden form property in a property form.
static getPageList(int $lm_id)
language handling
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)
Component logger with individual log levels by component id.
This class represents a number property in a property form.
Class ilObjContentObjectGUI.
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...
static getManualFeedback(int $active_id, int $question_id, ?int $pass)
Retrieves the feedback comment for a question in a test if it is finalized.
User class.
class ilObjectDataCache
static getClassByType(string $obj_type)
static _lookupType(int $id, bool $reference=false)
This class represents a property form user interface.
addCommandButton(string $a_cmd, string $a_text, string $a_id="")
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...
static _getUsedHTMLTags(string $module='')
static _getUsedHTMLTagsAsString(string $module='')
static replaceLatexSpan(string $text)
Replace the latex delimiters used by the rich text editor Unfortunately these can't be processed by M...
This class represents a property in a property form.
This class represents an option in a radio group.
class ilRbacSystem system function like checkAccess, addActiveRole ... Supporting system functions ar...
This class represents a selection list property in a property form.
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...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setBackTarget(string $a_title, string $a_target, string $a_frame="")
addTarget(string $a_text, string $a_link, $a_cmd="", $a_cmdClass="", string $a_frame="", bool $a_activate=false, bool $a_dir_text=false)
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...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
special template class to simplify handling of ITX/PEAR
This class represents a text area property in a property form.
This class represents a text property in a property form.
Tree class data representation in hierachical trees using the Nested Set Model with Gaps by Joe Celco...
isInTree(?int $a_node_id)
get all information of a node.
getNodeData(int $a_node_id, ?int $a_tree_pk=null)
get all information of a node.
getChildsByType(int $a_node_id, string $a_type)
get child nodes of given node by object type
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 stripOnlySlashes(string $a_str)
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
return['delivery_method'=> 'php',]
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
exit
addJavaScript(string $a_js_file, bool $a_add_version_parameter=true, int $a_batch=2)
Add a javascript file that should be included in the header.
Interface ilAccessHandler This interface combines all available interfaces which can be called via gl...
Readable part of repository interface to ilComponentDataDB.
Interface ilDBInterface.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$dic
Definition: ltiresult.php:33
$path
Definition: ltiservices.php:30
$res
Definition: ltiservices.php:69
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
global $lng
Definition: privfeed.php:31
if(!file_exists('../ilias.ini.php'))
global $DIC
Definition: shib_login.php:26