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