ILIAS  release_7 Revision v7.30-3-g800a261c036
class.ilTestPlayerAbstractGUI.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once './Modules/Test/classes/inc.AssessmentConstants.php';
5require_once './Modules/Test/classes/class.ilTestPlayerCommands.php';
6require_once './Modules/Test/classes/class.ilTestServiceGUI.php';
7require_once './Modules/TestQuestionPool/classes/class.assQuestion.php';
8require_once './Services/UIComponent/Button/classes/class.ilSubmitButton.php';
9require_once 'Modules/Test/classes/class.ilTestPlayerNavButton.php';
10
26{
27 const PRESENTATION_MODE_VIEW = 'view';
28 const PRESENTATION_MODE_EDIT = 'edit';
29
30 public $ref_id;
32 public $sequence;
33 public $cmdCtrl;
36
41
45 protected $processLocker;
46
50 protected $testSession;
51
55 protected $assSettings;
56
60 protected $testSequence = null;
61
67 public function __construct($a_object)
68 {
69 parent::__construct($a_object);
70 $this->ref_id = $_GET["ref_id"];
71
72 global $DIC;
73 $rbacsystem = $DIC['rbacsystem'];
74 $ilUser = $DIC['ilUser'];
75 $lng = $DIC['lng'];
76 require_once 'Modules/Test/classes/class.ilTestPasswordChecker.php';
77 $this->passwordChecker = new ilTestPasswordChecker($rbacsystem, $ilUser, $this->object, $lng);
78
79 $this->processLocker = null;
80 $this->testSession = null;
81 $this->assSettings = null;
82 }
83
84 protected function checkReadAccess()
85 {
86 global $DIC;
87 $rbacsystem = $DIC['rbacsystem'];
88
89 if (!$rbacsystem->checkAccess("read", $this->object->getRefId())) {
90 // only with read access it is possible to run the test
91 $this->ilias->raiseError($this->lng->txt("cannot_execute_test"), $this->ilias->error_obj->MESSAGE);
92 }
93 }
94
95 protected function checkTestExecutable()
96 {
97 $executable = $this->object->isExecutable($this->testSession, $this->testSession->getUserId());
98
99 if (!$executable['executable']) {
100 ilUtil::sendInfo($executable['errormessage'], true);
101 $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
102 }
103 }
104
106 {
107 global $DIC; /* @var ILIAS\DI\Container $DIC */
108
109 if ($testSession->getUserId() != $DIC->user()->getId()) {
110 throw new ilTestException('active id given does not relate to current user!');
111 }
112 }
113
115 {
116 if ($testSession->getActiveId()) {
117 return;
118 }
119
120 global $DIC;
121 $ilUser = $DIC['ilUser'];
122
123 $testSession->setUserId($ilUser->getId());
124
125 if ($testSession->isAnonymousUser()) {
126 if (!$testSession->doesAccessCodeInSessionExists()) {
127 return;
128 }
129
130 $testSession->setAnonymousId($testSession->getAccessCodeFromSession());
131 }
132
133 $testSession->saveToDb();
134 }
135
136 protected function initProcessLocker($activeId)
137 {
138 global $DIC;
139 $ilDB = $DIC['ilDB'];
140
141 require_once 'Modules/Test/classes/class.ilTestProcessLockerFactory.php';
142 $processLockerFactory = new ilTestProcessLockerFactory($this->assSettings, $ilDB);
143 $this->processLocker = $processLockerFactory->withContextId((int) $activeId)->getLocker();
144 }
145
152 public function saveTagsCmd()
153 {
154 include_once("./Services/Tagging/classes/class.ilTaggingGUI.php");
155 $tagging_gui = new ilTaggingGUI();
156 $tagging_gui->setObject($this->object->getId(), $this->object->getType());
157 $tagging_gui->saveInput();
158 $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
159 }
160
164 public function updateWorkingTime()
165 {
166 if ($_SESSION["active_time_id"]) {
167 $this->object->updateWorkingTime($_SESSION["active_time_id"]);
168 }
169
170 $_SESSION["active_time_id"] = $this->object->startWorkingTime(
171 $this->testSession->getActiveId(),
172 $this->testSession->getPass()
173 );
174 }
175
176 // fau: testNav - new function removeIntermediateSolution()
182 {
183 $questionId = $this->getCurrentQuestionId();
184
185 $this->getQuestionInstance($questionId)->removeIntermediateSolution(
186 $this->testSession->getActiveId(),
187 $this->testSession->getPass()
188 );
189 }
190 // fau.
191
195 abstract public function saveQuestionSolution($authorized = true, $force = false);
196
197 abstract protected function canSaveResult();
198
199 public function suspendTestCmd()
200 {
201 $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
202 }
203
212 {
213 global $DIC;
214 $ilUser = $DIC['ilUser'];
215 $active_id = $this->testSession->getActiveId();
216 $starting_time = $this->object->getStartingTimeOfUser($active_id);
217 if ($starting_time === false) {
218 return false;
219 } else {
220 return $this->object->isMaxProcessingTimeReached($starting_time, $active_id);
221 }
222 }
223
224 protected function determineInlineScoreDisplay()
225 {
226 $show_question_inline_score = false;
227 if ($this->object->getAnswerFeedbackPoints()) {
228 $show_question_inline_score = true;
229 return $show_question_inline_score;
230 }
231 return $show_question_inline_score;
232 }
233
235 {
236 $this->tpl->setCurrentBlock('test_nav_toolbar');
237 $this->tpl->setVariable('TEST_NAV_TOOLBAR', $toolbarGUI->getHTML());
238 $this->tpl->parseCurrentBlock();
239 }
240
241 protected function populateQuestionNavigation($sequenceElement, $disabled, $primaryNext)
242 {
243 if (!$this->isFirstQuestionInSequence($sequenceElement)) {
244 $this->populatePreviousButtons($disabled);
245 }
246
247 if (!$this->isLastQuestionInSequence($sequenceElement)) {
248 $this->populateNextButtons($disabled, $primaryNext);
249 }
250 }
251
252 protected function populatePreviousButtons($disabled)
253 {
254 $this->populateUpperPreviousButtonBlock($disabled);
255 $this->populateLowerPreviousButtonBlock($disabled);
256 }
257
258 protected function populateNextButtons($disabled, $primaryNext)
259 {
260 $this->populateUpperNextButtonBlock($disabled, $primaryNext);
261 $this->populateLowerNextButtonBlock($disabled, $primaryNext);
262 }
263
264 protected function populateLowerNextButtonBlock($disabled, $primaryNext)
265 {
266 $button = $this->buildNextButtonInstance($disabled, $primaryNext);
267 $button->setId('bottomnextbutton');
268
269 $this->tpl->setCurrentBlock("next_bottom");
270 $this->tpl->setVariable("BTN_NEXT_BOTTOM", $button->render());
271 $this->tpl->parseCurrentBlock();
272 }
273
274 protected function populateUpperNextButtonBlock($disabled, $primaryNext)
275 {
276 $button = $this->buildNextButtonInstance($disabled, $primaryNext);
277 $button->setId('nextbutton');
278
279 $this->tpl->setCurrentBlock("next");
280 $this->tpl->setVariable("BTN_NEXT", $button->render());
281 $this->tpl->parseCurrentBlock();
282 }
283
284 protected function populateLowerPreviousButtonBlock($disabled)
285 {
286 $button = $this->buildPreviousButtonInstance($disabled);
287 $button->setId('bottomprevbutton');
288
289 $this->tpl->setCurrentBlock("prev_bottom");
290 $this->tpl->setVariable("BTN_PREV_BOTTOM", $button->render());
291 $this->tpl->parseCurrentBlock();
292 }
293
294 protected function populateUpperPreviousButtonBlock($disabled)
295 {
296 $button = $this->buildPreviousButtonInstance($disabled);
297 $button->setId('prevbutton');
298
299 $this->tpl->setCurrentBlock("prev");
300 $this->tpl->setVariable("BTN_PREV", $button->render());
301 $this->tpl->parseCurrentBlock();
302 }
303
309 private function buildNextButtonInstance($disabled, $primaryNext)
310 {
312 // fau: testNav - set glyphicon and primary
313 $button->setPrimary($primaryNext);
314 $button->setRightGlyph('glyphicon glyphicon-arrow-right');
315 // fau.
316 $button->setNextCommand(ilTestPlayerCommands::NEXT_QUESTION);
317 $button->setUrl($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::NEXT_QUESTION));
318 $button->setCaption('next_question');
319 $button->addCSSClass('ilTstNavElem');
320 //$button->setDisabled($disabled);
321 return $button;
322 }
323
328 private function buildPreviousButtonInstance($disabled)
329 {
331 // fau: testNav - set glyphicon and primary
332 $button->setLeftGlyph('glyphicon glyphicon-arrow-left');
333 // fau.
334 $button->setNextCommand(ilTestPlayerCommands::PREVIOUS_QUESTION);
335 $button->setUrl($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::PREVIOUS_QUESTION));
336 $button->setCaption('previous_question');
337 $button->addCSSClass('ilTstNavElem');
338 //$button->setDisabled($disabled);
339 return $button;
340 }
341
345 protected function populateSpecificFeedbackBlock(assQuestionGUI $question_gui) : bool
346 {
347 $solutionValues = $question_gui->object->getSolutionValues(
348 $this->testSession->getActiveId(),
349 null
350 );
351
352 $feedback = $question_gui->getSpecificFeedbackOutput(
353 $question_gui->object->fetchIndexedValuesFromValuePairs($solutionValues)
354 );
355
356 if (!empty($feedback)) {
357 $this->tpl->setCurrentBlock("specific_feedback");
358 $this->tpl->setVariable("SPECIFIC_FEEDBACK", $feedback);
359 $this->tpl->parseCurrentBlock();
360 return true;
361 }
362 return false;
363 }
364
368 protected function populateGenericFeedbackBlock(assQuestionGUI $question_gui, $solutionCorrect) : bool
369 {
370 // fix #031263: add pass
371 $feedback = $question_gui->getGenericFeedbackOutput($this->testSession->getActiveId(), $this->testSession->getPass());
372
373 if (strlen($feedback)) {
374 $cssClass = (
375 $solutionCorrect ?
377 );
378
379 $this->tpl->setCurrentBlock("answer_feedback");
380 $this->tpl->setVariable("ANSWER_FEEDBACK", $feedback);
381 $this->tpl->setVariable("ILC_FB_CSS_CLASS", $cssClass);
382 $this->tpl->parseCurrentBlock();
383 return true;
384 }
385 return false;
386 }
387
388 protected function populateScoreBlock($reachedPoints, $maxPoints)
389 {
390 $scoreInformation = sprintf(
391 $this->lng->txt("you_received_a_of_b_points"),
392 $reachedPoints,
393 $maxPoints
394 );
395
396 $this->tpl->setCurrentBlock("received_points_information");
397 $this->tpl->setVariable("RECEIVED_POINTS_INFORMATION", $scoreInformation);
398 $this->tpl->parseCurrentBlock();
399 }
400
401 protected function populateSolutionBlock($solutionoutput)
402 {
403 if (strlen($solutionoutput)) {
404 $this->tpl->setCurrentBlock("solution_output");
405 $this->tpl->setVariable("CORRECT_SOLUTION", $this->lng->txt("tst_best_solution_is"));
406 $this->tpl->setVariable("QUESTION_FEEDBACK", $solutionoutput);
407 $this->tpl->parseCurrentBlock();
408 }
409 }
410
411 protected function populateSyntaxStyleBlock()
412 {
413 $this->tpl->setCurrentBlock("SyntaxStyle");
414 $this->tpl->setVariable(
415 "LOCATION_SYNTAX_STYLESHEET",
417 );
418 $this->tpl->parseCurrentBlock();
419 }
420
421 protected function populateContentStyleBlock()
422 {
423 include_once("./Services/Style/Content/classes/class.ilObjStyleSheet.php");
424 $this->tpl->setCurrentBlock("ContentStyle");
425 $this->tpl->setVariable(
426 "LOCATION_CONTENT_STYLESHEET",
428 );
429 $this->tpl->parseCurrentBlock();
430 }
431
437 public function setAnonymousIdCmd()
438 {
439 if ($this->testSession->isAnonymousUser()) {
440 $this->testSession->setAccessCodeToSession($_POST['anonymous_id']);
441 }
442
443 $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
444 }
445
452 protected function startPlayerCmd()
453 {
454 $testStartLock = $this->getLockParameter();
455 $isFirstTestStartRequest = false;
456
457 $this->processLocker->executeTestStartLockOperation(function () use ($testStartLock, &$isFirstTestStartRequest) {
458 if ($this->testSession->lookupTestStartLock() != $testStartLock) {
459 $this->testSession->persistTestStartLock($testStartLock);
460 $isFirstTestStartRequest = true;
461 }
462 });
463
464 if ($isFirstTestStartRequest) {
465 $this->handleUserSettings();
466 $this->ctrl->redirect($this, ilTestPlayerCommands::INIT_TEST);
467 }
468
469 $this->ctrl->setParameterByClass('ilObjTestGUI', 'lock', $testStartLock);
470 $this->ctrl->redirectByClass("ilobjtestgui", "redirectToInfoScreen");
471 }
472
473 public function getLockParameter()
474 {
475 if (isset($_POST['lock']) && strlen($_POST['lock'])) {
476 return $_POST['lock'];
477 } elseif (isset($_GET['lock']) && strlen($_GET['lock'])) {
478 return $_GET['lock'];
479 }
480
481 return null;
482 }
483
487 abstract protected function resumePlayerCmd();
488
492 protected function initTestCmd()
493 {
494 if ($this->object->checkMaximumAllowedUsers() == false) {
496 }
497
498 if ($this->testSession->isAnonymousUser()
499 && !$this->testSession->doesAccessCodeInSessionExists()) {
500 $accessCode = $this->testSession->createNewAccessCode();
501
502 $this->testSession->setAccessCodeToSession($accessCode);
503 $this->testSession->setAnonymousId($accessCode);
504 $this->testSession->saveToDb();
505
506 $this->ctrl->redirect($this, ilTestPlayerCommands::DISPLAY_ACCESS_CODE);
507 }
508
509 if (!$this->testSession->isAnonymousUser()) {
510 $this->testSession->unsetAccessCodeInSession();
511 }
512 $this->ctrl->redirect($this, ilTestPlayerCommands::START_TEST);
513 }
514
515 public function displayAccessCodeCmd()
516 {
517 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_anonymous_code_presentation.html", "Modules/Test");
518 $this->tpl->setCurrentBlock("adm_content");
519 $this->tpl->setVariable("TEXT_ANONYMOUS_CODE_CREATED", $this->lng->txt("tst_access_code_created"));
520 $this->tpl->setVariable("TEXT_ANONYMOUS_CODE", $this->testSession->getAccessCodeFromSession());
521 $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
522 $this->tpl->setVariable("CMD_CONFIRM", ilTestPlayerCommands::ACCESS_CODE_CONFIRMED);
523 $this->tpl->setVariable("TXT_CONFIRM", $this->lng->txt("continue_work"));
524 $this->tpl->parseCurrentBlock();
525 }
526
527 public function accessCodeConfirmedCmd()
528 {
529 $this->ctrl->redirect($this, ilTestPlayerCommands::START_TEST);
530 }
531
535 public function handleUserSettings()
536 {
537 global $DIC;
538 $ilUser = $DIC['ilUser'];
539
540 if ($_POST["chb_javascript"]) {
541 $ilUser->writePref("tst_javascript", 1);
542 } else {
543 $ilUser->writePref("tst_javascript", 0);
544 }
545
546 // hide previous results
547 if ($this->object->getNrOfTries() != 1) {
548 if ($this->object->getUsePreviousAnswers() == 1) {
549 if ($_POST["chb_use_previous_answers"]) {
550 $ilUser->writePref("tst_use_previous_answers", 1);
551 } else {
552 $ilUser->writePref("tst_use_previous_answers", 0);
553 }
554 }
555 }
556 }
557
562 public function redirectAfterAutosaveCmd()
563 {
564 $active_id = $this->testSession->getActiveId();
565 $actualpass = ilObjTest::_getPass($active_id);
566
567 $this->performTestPassFinishedTasks($actualpass);
568
569 $this->testSession->setLastFinishedPass($this->testSession->getPass());
570 $this->testSession->increaseTestPass();
571
572 $url = $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::AFTER_TEST_PASS_FINISHED, '', false, false);
573
574 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_redirect_autosave.html", "Modules/Test");
575 $this->tpl->setVariable("TEXT_REDIRECT", $this->lng->txt("redirectAfterSave"));
576 $this->tpl->setVariable("URL", $url);
577 }
578
580 {
581 $active_id = $this->testSession->getActiveId();
582 $actualpass = ilObjTest::_getPass($active_id);
583
584 $this->performTestPassFinishedTasks($actualpass);
585
586 $this->testSession->setLastFinishedPass($this->testSession->getPass());
587 $this->testSession->increaseTestPass();
588
589 $url = $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::AFTER_TEST_PASS_FINISHED, '', false, false);
590
591 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_redirect_autosave.html", "Modules/Test");
592 $this->tpl->setVariable("TEXT_REDIRECT", $this->lng->txt("redirectAfterSave"));
593 $this->tpl->setVariable("URL", $url);
594 }
595
596 abstract protected function getCurrentQuestionId();
597
602 public function autosaveCmd()
603 {
604 $result = "";
605 if (is_array($_POST) && count($_POST) > 0) {
606 if (!$this->canSaveResult() || $this->isParticipantsAnswerFixed($this->getCurrentQuestionId())) {
607 $result = '-IGNORE-';
608 } else {
609 // answer is changed from authorized solution, so save the change as intermediate solution
610 if ($this->getAnswerChangedParameter()) {
611 $res = $this->saveQuestionSolution(false, true);
612 }
613 // answer is not changed from authorized solution, so delete an intermediate solution
614 else {
615 $db_res = $this->removeIntermediateSolution();
616 $res = is_int($db_res);
617 }
618 if ($res) {
619 $result = $this->lng->txt("autosave_success");
620 } else {
621 $result = $this->lng->txt("autosave_failed");
622 }
623 }
624 }
625 echo $result;
626 exit;
627 }
628
633 public function autosaveOnTimeLimitCmd()
634 {
635 if (!$this->isParticipantsAnswerFixed($this->getCurrentQuestionId())) {
636 // time limit saves the user solution as authorized
637 $this->saveQuestionSolution(true, true);
638 }
639 $this->ctrl->redirect($this, ilTestPlayerCommands::REDIRECT_ON_TIME_LIMIT);
640 }
641
642
643 // fau: testNav - new function detectChangesCmd()
649 protected function detectChangesCmd()
650 {
651 $questionId = $this->getCurrentQuestionId();
652 $state = $this->getQuestionInstance($questionId)->lookupForExistingSolutions(
653 $this->testSession->getActiveId(),
654 $this->testSession->getPass()
655 );
656 $result = array();
657 $result['isAnswered'] = $state['authorized'];
658 $result['isAnswerChanged'] = $state['intermediate'];
659
660 echo json_encode($result);
661 exit;
662 }
663 // fau.
664
665 protected function submitIntermediateSolutionCmd()
666 {
667 $this->saveQuestionSolution(false, true);
668 // fau: testNav - set the 'answer changed' parameter when an intermediate solution is submitted
669 $this->setAnswerChangedParameter(true);
670 // fau.
671 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
672 }
673
677 public function toggleSideListCmd()
678 {
679 global $DIC;
680 $ilUser = $DIC['ilUser'];
681
682 $show_side_list = $ilUser->getPref('side_list_of_questions');
683 $ilUser->writePref('side_list_of_questions', !$show_side_list);
684 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
685 }
686
688 {
689 // fau: testNav - handle intermediate submit when marking the question
691 // fau.
692 $this->markQuestionCmd();
693 }
694
698 protected function markQuestionCmd()
699 {
700 $questionId = $this->testSequence->getQuestionForSequence(
702 );
703
704 $this->object->setQuestionSetSolved(1, $questionId, $this->testSession->getUserId());
705
706 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
707 }
708
710 {
711 // fau: testNav - handle intermediate submit when unmarking the question
713 // fau.
714 $this->unmarkQuestionCmd();
715 }
716
720 protected function unmarkQuestionCmd()
721 {
722 $questionId = $this->testSequence->getQuestionForSequence(
724 );
725
726 $this->object->setQuestionSetSolved(0, $questionId, $this->testSession->getUserId());
727
728 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
729 }
730
734 protected function confirmFinishCmd()
735 {
736 $this->finishTestCmd(false);
737 }
738
742 protected function confirmFinishTestCmd()
743 {
747 global $DIC;
748 $ilUser = $DIC['ilUser'];
749
750 require_once 'Services/Utilities/classes/class.ilConfirmationGUI.php';
751 $confirmation = new ilConfirmationGUI();
752 $confirmation->setFormAction($this->ctrl->getFormAction($this, 'confirmFinish'));
753 $confirmation->setHeaderText($this->lng->txt("tst_finish_confirmation_question"));
754 $confirmation->setConfirm($this->lng->txt("tst_finish_confirm_button"), 'confirmFinish');
755 $confirmation->setCancel($this->lng->txt("tst_finish_confirm_cancel_button"), ilTestPlayerCommands::BACK_FROM_FINISHING);
756
757 $this->populateHelperGuiContent($confirmation);
758 }
759
760 public function finishTestCmd($requires_confirmation = true)
761 {
762 unset($_SESSION["tst_next"]);
763
764 $active_id = $this->testSession->getActiveId();
765 $actualpass = ilObjTest::_getPass($active_id);
766
767 $allObligationsAnswered = ilObjTest::allObligationsAnswered($this->testSession->getTestId(), $active_id, $actualpass);
768
769 /*
770 * The following "endgames" are possible prior to actually finishing the test:
771 * - Obligations (Ability to finish the test.)
772 * If not all obligatory questions are answered, the user is presented a list
773 * showing the deficits.
774 * - Examview (Will to finish the test.)
775 * With the examview, the participant can review all answers given in ILIAS or a PDF prior to
776 * commencing to the finished test.
777 * - Last pass allowed (Reassuring the will to finish the test.)
778 * If passes are limited, on the last pass, an additional confirmation is to be displayed.
779 */
780
781
782 if ($this->object->areObligationsEnabled() && !$allObligationsAnswered) {
783 if ($this->object->getListOfQuestions()) {
784 $this->ctrl->redirect($this, ilTestPlayerCommands::QUESTION_SUMMARY_INC_OBLIGATIONS);
785 } else {
787 }
788
789 return;
790 }
791
792 // Examview enabled & !reviewed & requires_confirmation? test_submission_overview (review gui)
793 if ($this->object->getEnableExamview() && !isset($_GET['reviewed']) && $requires_confirmation) {
794 $this->ctrl->redirectByClass('ilTestSubmissionReviewGUI', "show");
795 return;
796 }
797
798 // Last try in limited tries & !confirmed
799 if (($requires_confirmation) && ($actualpass == $this->object->getNrOfTries() - 1)) {
800 // show confirmation page
801 return $this->confirmFinishTestCmd();
802 }
803
804 // Last try in limited tries & confirmed?
805 if (($actualpass == $this->object->getNrOfTries() - 1) && (!$requires_confirmation)) {
806 // @todo: php7 ask mister test
807 #$ilAuth->setIdle(ilSession::getIdleValue(), false);
808 #$ilAuth->setExpire(0);
809 switch ($this->object->getMailNotification()) {
810 case 1:
811 $this->object->sendSimpleNotification($active_id);
812 break;
813 case 2:
814 $this->object->sendAdvancedNotification($active_id);
815 break;
816 }
817 }
818
819 // Non-last try finish
820 if (!$_SESSION['tst_pass_finish']) {
821 if (!$_SESSION['tst_pass_finish']) {
822 $_SESSION['tst_pass_finish'] = 1;
823 }
824 if ($this->object->getMailNotificationType() == 1) {
825 switch ($this->object->getMailNotification()) {
826 case 1:
827 $this->object->sendSimpleNotification($active_id);
828 break;
829 case 2:
830 $this->object->sendAdvancedNotification($active_id);
831 break;
832 }
833 }
834 }
835
836 // no redirect request loops after test pass finished tasks has been performed
837
838 $this->performTestPassFinishedTasks($actualpass);
839
840 $this->ctrl->redirect($this, ilTestPlayerCommands::AFTER_TEST_PASS_FINISHED);
841 }
842
843 protected function performTestPassFinishedTasks($finishedPass)
844 {
845 require_once 'Modules/Test/classes/class.ilTestPassFinishTasks.php';
846
847 $finishTasks = new ilTestPassFinishTasks($this->testSession->getActiveId(), $this->object->getId());
848 $finishTasks->performFinishTasks($this->processLocker);
849 }
850
851 protected function afterTestPassFinishedCmd()
852 {
853 $activeId = $this->testSession->getActiveId();
854 $lastFinishedPass = $this->testSession->getLastFinishedPass();
855
856 // handle test signature
857 if ($this->isTestSignRedirectRequired($activeId, $lastFinishedPass)) {
858 $this->ctrl->redirectByClass('ilTestSignatureGUI', 'invokeSignaturePlugin');
859 }
860
861 // show final statement
862 if (!$_GET['skipfinalstatement']) {
863 if ($this->object->getShowFinalStatement()) {
864 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_FINAL_STATMENT);
865 }
866 }
867
868 // redirect after test
869 $redirection_mode = $this->object->getRedirectionMode();
870 $redirection_url = $this->object->getRedirectionUrl();
871 if ($redirection_url && $redirection_mode) {
872 if ($redirection_mode == REDIRECT_KIOSK) {
873 if ($this->object->getKioskMode()) {
874 ilUtil::redirect($redirection_url);
875 }
876 } else {
877 ilUtil::redirect($redirection_url);
878 }
879 }
880
881 // default redirect (pass overview when enabled, otherwise infoscreen)
882 $this->redirectBackCmd();
883 }
884
885 protected function isTestSignRedirectRequired($activeId, $lastFinishedPass)
886 {
887 if (!$this->object->getSignSubmission()) {
888 return false;
889 }
890
891 if (!is_null(ilSession::get("signed_{$activeId}_{$lastFinishedPass}"))) {
892 return false;
893 }
894
895 global $DIC;
896 $ilPluginAdmin = $DIC['ilPluginAdmin'];
897
898 $activePlugins = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, 'Test', 'tsig');
899
900 if (!count($activePlugins)) {
901 return false;
902 }
903
904 return true;
905 }
906
912 protected function archiveParticipantSubmission($active, $pass)
913 {
914 global $DIC;
915 $ilObjDataCache = $DIC['ilObjDataCache'];
916
917 require_once 'Modules/Test/classes/class.ilTestResultHeaderLabelBuilder.php';
918 $testResultHeaderLabelBuilder = new ilTestResultHeaderLabelBuilder($this->lng, $ilObjDataCache);
919
920 $objectivesList = null;
921
922 if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
923 $testSequence = $this->testSequenceFactory->getSequenceByActiveIdAndPass($this->testSession->getActiveId(), $this->testSession->getPass());
924 $testSequence->loadFromDb();
925 $testSequence->loadQuestions();
926
927 require_once 'Modules/Course/classes/Objectives/class.ilLOTestQuestionAdapter.php';
928 $objectivesAdapter = ilLOTestQuestionAdapter::getInstance($this->testSession);
929
930 $objectivesList = $this->buildQuestionRelatedObjectivesList($objectivesAdapter, $testSequence);
931 $objectivesList->loadObjectivesTitles();
932
933 $testResultHeaderLabelBuilder->setObjectiveOrientedContainerId($this->testSession->getObjectiveOrientedContainerId());
934 $testResultHeaderLabelBuilder->setUserId($this->testSession->getUserId());
935 $testResultHeaderLabelBuilder->setTestObjId($this->object->getId());
936 $testResultHeaderLabelBuilder->setTestRefId($this->object->getRefId());
937 $testResultHeaderLabelBuilder->initObjectiveOrientedMode();
938 }
939
940 $results = $this->object->getTestResult(
941 $active,
942 $pass,
943 false,
944 !$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()
945 );
946
947 require_once 'class.ilTestEvaluationGUI.php';
948 $testevaluationgui = new ilTestEvaluationGUI($this->object);
949 $results_output = $testevaluationgui->getPassListOfAnswers(
950 $results,
951 $active,
952 $pass,
953 false,
954 false,
955 false,
956 false,
957 false,
958 $objectivesList,
959 $testResultHeaderLabelBuilder
960 );
961
962 require_once './Modules/Test/classes/class.ilTestArchiver.php';
963 global $DIC;
964 $ilSetting = $DIC['ilSetting'];
965 $inst_id = $ilSetting->get('inst_id', null);
966 $archiver = new ilTestArchiver($this->object->getId());
967
968 $path = ilUtil::getWebspaceDir() . '/assessment/' . $this->object->getId() . '/exam_pdf';
969 if (!is_dir($path)) {
971 }
972 $filename = realpath($path) . '/exam_N' . $inst_id . '-' . $this->object->getId()
973 . '-' . $active . '-' . $pass . '.pdf';
974
976 //$template->setVariable("PDF_FILE_LOCATION", $filename);
977 // Participant submission
978 $archiver->handInParticipantSubmission($active, $pass, $filename, $results_output);
979 //$archiver->handInParticipantMisc( $active, $pass, 'signature_gedoens.sig', $filename );
980 //$archiver->handInParticipantQuestionMaterial( $active, $pass, 123, 'file_upload.pdf', $filename );
981
982 global $DIC;
983 $ilias = $DIC['ilias'];
984 $questions = $this->object->getQuestions();
985 foreach ($questions as $question_id) {
986 $question_object = $this->object->getQuestionDataset($question_id);
987 if ($question_object->type_tag == 'assFileUpload') {
988 // Pfad: /data/default/assessment/tst_2/14/21/files/file_14_4_1370417414.png
989 // /data/ - klar
990 // /assessment/ - Konvention
991 // /tst_2/ = /tst_<test_id> (ilObjTest)
992 // /14/ = /<active_fi>/
993 // /21/ = /<question_id>/ (question_object)
994 // /files/ - Konvention
995 // file_14_4_1370417414.png = file_<active_fi>_<pass>_<some timestamp>.<ext>
996
997 $candidate_path =
998 $ilias->ini_ilias->readVariable('server', 'absolute_path') . ilTestArchiver::DIR_SEP
999 . $ilias->ini_ilias->readVariable('clients', 'path') . ilTestArchiver::DIR_SEP
1000 . $ilias->client_id . ilTestArchiver::DIR_SEP
1001 . 'assessment' . ilTestArchiver::DIR_SEP
1002 . 'tst_' . $this->object->test_id . ilTestArchiver::DIR_SEP
1003 . $active . ilTestArchiver::DIR_SEP
1004 . $question_id . ilTestArchiver::DIR_SEP
1005 . 'files' . ilTestArchiver::DIR_SEP;
1006 $handle = opendir($candidate_path);
1007 while ($handle !== false && ($file = readdir($handle)) !== false) {
1008 if ($file != null) {
1009 $filename_start = 'file_' . $active . '_' . $pass . '_';
1010
1011 if (strpos($file, $filename_start) === 0) {
1012 $archiver->handInParticipantQuestionMaterial($active, $pass, $question_id, $file, $file);
1013 }
1014 }
1015 }
1016 }
1017 }
1018 $passdata = $this->object->getTestResult(
1019 $active,
1020 $pass,
1021 false,
1022 !$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()
1023 );
1024 $overview = $testevaluationgui->getPassListOfAnswers(
1025 $passdata,
1026 $active,
1027 $pass,
1028 true,
1029 false,
1030 false,
1031 true,
1032 false,
1033 $objectivesList,
1034 $testResultHeaderLabelBuilder
1035 );
1036 $filename = realpath(ilUtil::getWebspaceDir()) . '/assessment/scores-' . $this->object->getId() . '-' . $active . '-' . $pass . '.pdf';
1038 $archiver->handInTestResult($active, $pass, $filename);
1039 unlink($filename);
1040
1041 return;
1042 }
1043 public function redirectBackCmd()
1044 {
1045 global $DIC; /* @var ILIAS\DI\Container $DIC */
1046 require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
1047 $testPassesSelector = new ilTestPassesSelector($DIC['ilDB'], $this->object);
1048 $testPassesSelector->setActiveId($this->testSession->getActiveId());
1049 $testPassesSelector->setLastFinishedPass($this->testSession->getLastFinishedPass());
1050
1051 if (count($testPassesSelector->getReportablePasses())) {
1052 if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
1053 $this->ctrl->redirectByClass(array('ilTestResultsGUI', 'ilTestEvalObjectiveOrientedGUI'));
1054 }
1055
1056 $this->ctrl->redirectByClass(array('ilTestResultsGUI', 'ilMyTestResultsGUI', 'ilTestEvaluationGUI'));
1057 }
1058
1059 $this->backToInfoScreenCmd();
1060 }
1061
1062 protected function backToInfoScreenCmd()
1063 {
1064 $this->ctrl->redirectByClass('ilObjTestGUI', 'redirectToInfoScreen');
1065 }
1066
1067 /*
1068 * Presents the final statement of a test
1069 */
1070 public function showFinalStatementCmd()
1071 {
1072 $template = new ilTemplate("tpl.il_as_tst_final_statement.html", true, true, "Modules/Test");
1073 $this->ctrl->setParameter($this, "skipfinalstatement", 1);
1074 $template->setVariable("FORMACTION", $this->ctrl->getFormAction($this, ilTestPlayerCommands::AFTER_TEST_PASS_FINISHED));
1075 $template->setVariable("FINALSTATEMENT", $this->object->prepareTextareaOutput($this->object->getFinalStatement(), true));
1076 $template->setVariable("BUTTON_CONTINUE", $this->lng->txt("btn_next"));
1077 $this->tpl->setVariable($this->getContentBlockName(), $template->get());
1078 }
1079
1080 public function getKioskHead()
1081 {
1082 global $DIC;
1083 $ilUser = $DIC['ilUser'];
1084
1085 //this is an abomination for release_8!
1086 //proper "kiosk-handling" is _very_ much encouraged for 9.
1087 $this->tpl->addCSS('Modules/Test/templates/default/test_kiosk_header.css');
1088 //end of hack
1089
1090 $template = new ilTemplate('tpl.il_as_tst_kiosk_head.html', true, true, 'Modules/Test');
1091 if ($this->object->getShowKioskModeTitle()) {
1092 $template->setCurrentBlock("kiosk_show_title");
1093 $template->setVariable("TEST_TITLE", $this->object->getTitle());
1094 $template->parseCurrentBlock();
1095 }
1096 if ($this->object->getShowKioskModeParticipant()) {
1097 $template->setCurrentBlock("kiosk_show_participant");
1098 $template->setVariable("PARTICIPANT_NAME_TXT", $this->lng->txt("login_as"));
1099 $template->setVariable("PARTICIPANT_NAME", $ilUser->getFullname());
1100 $template->setVariable("PARTICIPANT_LOGIN", $ilUser->getLogin());
1101 $template->setVariable("PARTICIPANT_MATRICULATION", $ilUser->getMatriculation());
1102 $template->setVariable("PARTICIPANT_EMAIL", $ilUser->getEmail());
1103 $template->parseCurrentBlock();
1104 }
1105 if ($this->object->isShowExamIdInTestPassEnabled()) {
1106 $exam_id = ilObjTest::buildExamId(
1107 $this->testSession->getActiveId(),
1108 $this->testSession->getPass(),
1109 $this->object->getId()
1110 );
1111
1112 $template->setCurrentBlock("kiosk_show_exam_id");
1113 $template->setVariable("EXAM_ID_TXT", $this->lng->txt("exam_id"));
1114 $template->setVariable("EXAM_ID", $exam_id);
1115 $template->parseCurrentBlock();
1116 }
1117 return $template->get();
1118 }
1119
1123 protected function prepareTestPage($presentationMode, $sequenceElement, $questionId)
1124 {
1125 global $DIC;
1126 $ilUser = $DIC['ilUser'];
1127 $ilNavigationHistory = $DIC['ilNavigationHistory'];
1128
1129 $ilNavigationHistory->addItem(
1130 $this->testSession->getRefId(),
1131 $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::RESUME_PLAYER),
1132 'tst'
1133 );
1134
1135 $this->initTestPageTemplate();
1137 $this->populateSyntaxStyleBlock();
1138
1139 if ($this->isMaxProcessingTimeReached()) {
1140 $this->maxProcessingTimeReached();
1141 return;
1142 }
1143
1144 if ($this->object->endingTimeReached()) {
1145 $this->endingTimeReached();
1146 return;
1147 }
1148
1149 if ($this->isOptionalQuestionAnsweringConfirmationRequired($sequenceElement)) {
1150 $this->ctrl->setParameter($this, "sequence", $sequenceElement);
1152 return;
1153 }
1154
1155 if ($this->object->getKioskMode()) {
1156 $this->populateKioskHead();
1157 }
1158
1159 $this->tpl->setVariable("TEST_ID", $this->object->getTestId());
1160 $this->tpl->setVariable("LOGIN", $ilUser->getLogin());
1161 $this->tpl->setVariable("SEQ_ID", $sequenceElement);
1162 $this->tpl->setVariable("QUEST_ID", $questionId);
1163
1164 if ($this->object->getEnableProcessingTime()) {
1165 $this->outProcessingTime($this->testSession->getActiveId());
1166 }
1167
1168 $this->tpl->setVariable("PAGETITLE", "- " . $this->object->getTitle());
1169
1170 if ($this->object->isShowExamIdInTestPassEnabled() && !$this->object->getKioskMode()) {
1171 $this->tpl->setCurrentBlock('exam_id_footer');
1172 $this->tpl->setVariable('EXAM_ID_VAL', ilObjTest::lookupExamId(
1173 $this->testSession->getActiveId(),
1174 $this->testSession->getPass(),
1175 $this->object->getId()
1176 ));
1177 $this->tpl->setVariable('EXAM_ID_TXT', $this->lng->txt('exam_id'));
1178 $this->tpl->parseCurrentBlock();
1179 }
1180
1181 if ($this->object->getListOfQuestions()) {
1182 $this->showSideList($presentationMode, $sequenceElement);
1183 }
1184 }
1185
1186 abstract protected function isOptionalQuestionAnsweringConfirmationRequired($sequenceElement);
1187
1188 abstract protected function isShowingPostponeStatusReguired($questionId);
1189
1190 protected function showQuestionViewable(assQuestionGUI $questionGui, $formAction, $isQuestionWorkedThrough, $instantResponse)
1191 {
1192 $questionNavigationGUI = $this->buildReadOnlyStateQuestionNavigationGUI($questionGui->object->getId());
1193 $questionNavigationGUI->setQuestionWorkedThrough($isQuestionWorkedThrough);
1194 $questionGui->setNavigationGUI($questionNavigationGUI);
1195
1196 // fau: testNav - set answere status in question header
1197 $questionGui->getQuestionHeaderBlockBuilder()->setQuestionAnswered($isQuestionWorkedThrough);
1198 // fau.
1199
1200 $answerFeedbackEnabled = (
1201 $instantResponse && $this->object->getSpecificAnswerFeedback()
1202 );
1203
1204 $solutionoutput = $questionGui->getSolutionOutput(
1205 $this->testSession->getActiveId(), #active_id
1206 $this->testSession->getPass(), #pass
1207 false, #graphical_output
1208 false, #result_output
1209 true, #show_question_only
1210 $answerFeedbackEnabled, #show_feedback
1211 false, #show_correct_solution
1212 false, #show_manual_scoring
1213 true #show_question_text
1214 );
1215
1216 $pageoutput = $questionGui->outQuestionPage(
1217 "",
1218 $this->isShowingPostponeStatusReguired($questionGui->object->getId()),
1219 $this->testSession->getActiveId(),
1220 $solutionoutput
1221 );
1222
1223 //$this->tpl->setCurrentBlock('readonly_css_class');
1224 //$this->tpl->touchBlock('readonly_css_class');
1225 global $DIC;
1226 $f = $DIC->ui()->factory();
1227 $renderer = $DIC->ui()->renderer();
1228
1229 $this->tpl->setVariable(
1230 'LOCKSTATE_INFOBOX',
1231 $renderer->render($f->messageBox()->info($this->lng->txt("tst_player_answer_saved_and_locked")))
1232 );
1233
1234 $this->tpl->parseCurrentBlock();
1235
1236 $this->tpl->setVariable('QUESTION_OUTPUT', $pageoutput);
1237
1238 $this->tpl->setVariable("FORMACTION", $formAction);
1239 $this->tpl->setVariable("ENCTYPE", 'enctype="' . $questionGui->getFormEncodingType() . '"');
1240 $this->tpl->setVariable("FORM_TIMESTAMP", time());
1241 }
1242
1243 protected function showQuestionEditable(assQuestionGUI $questionGui, $formAction, $isQuestionWorkedThrough, $instantResponse)
1244 {
1245 $questionNavigationGUI = $this->buildEditableStateQuestionNavigationGUI(
1246 $questionGui->object->getId(),
1247 $this->populateCharSelectorIfRequired()
1248 );
1249 if ($isQuestionWorkedThrough) {
1250 $questionNavigationGUI->setDiscardSolutionButtonEnabled(true);
1251 // fau: testNav - set answere status in question header
1252 $questionGui->getQuestionHeaderBlockBuilder()->setQuestionAnswered(true);
1253 // fau.
1254 } elseif ($this->object->isPostponingEnabled()) {
1255 $questionNavigationGUI->setSkipQuestionLinkTarget(
1256 $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::SKIP_QUESTION)
1257 );
1258 }
1259 $questionGui->setNavigationGUI($questionNavigationGUI);
1260
1261 $isPostponed = $this->isShowingPostponeStatusReguired($questionGui->object->getId());
1262
1263 $answerFeedbackEnabled = (
1264 $instantResponse && $this->object->getSpecificAnswerFeedback()
1265 );
1266
1267 if (isset($_GET['save_error']) && $_GET['save_error'] == 1 && isset($_SESSION['previouspost'])) {
1268 $userPostSolution = $_SESSION['previouspost'];
1269 unset($_SESSION['previouspost']);
1270 } else {
1271 $userPostSolution = false;
1272 }
1273
1274 // fau: testNav - add special checkbox for mc question
1275 // moved to another patch block
1276 // fau.
1277
1278 // hey: prevPassSolutions - determine solution pass index and configure gui accordingly
1279 $qstConfig = $questionGui->object->getTestPresentationConfig();
1280
1281 if ($questionGui instanceof assMultipleChoiceGUI) {
1282 $qstConfig->setWorkedThrough($isQuestionWorkedThrough);
1283 $qstConfig->setIsUnchangedAnswerPossible($this->object->getMCScoring());
1284 }
1285
1286 if ($qstConfig->isPreviousPassSolutionReuseAllowed()) {
1287 $passIndex = $this->determineSolutionPassIndex($questionGui); // last pass having solution stored
1288 if ($passIndex < $this->testSession->getPass()) { // it's the previous pass if current pass is higher
1289 $qstConfig->setSolutionInitiallyPrefilled(true);
1290 }
1291 } else {
1292 $passIndex = $this->testSession->getPass();
1293 }
1294 // hey.
1295
1296 // Answer specific feedback is rendered into the display of the test question with in the concrete question types outQuestionForTest-method.
1297 // Notation of the params prior to getting rid of this crap in favor of a class
1298 $questionGui->outQuestionForTest(
1299 $formAction, #form_action
1300 $this->testSession->getActiveId(), #active_id
1301 // hey: prevPassSolutions - prepared pass index having no, current or previous solution
1302 $passIndex, #pass
1303 // hey.
1304 $isPostponed, #is_postponed
1305 $userPostSolution, #user_post_solution
1306 $answerFeedbackEnabled #answer_feedback == inline_specific_feedback
1307 );
1308 // The display of specific inline feedback and specific feedback in an own block is to honor questions, which
1309 // have the possibility to embed the specific feedback into their output while maintaining compatibility to
1310 // questions, which do not have such facilities. E.g. there can be no "specific inline feedback" for essay
1311 // questions, while the multiple-choice questions do well.
1312
1313
1314 $this->populateModals();
1315
1316 // fau: testNav - pouplate the new question edit control instead of the deprecated intermediate solution saver
1317 $this->populateQuestionEditControl($questionGui);
1318 // fau.
1319 }
1320
1321 // hey: prevPassSolutions - determine solution pass index
1322 protected function determineSolutionPassIndex(assQuestionGUI $questionGui)
1323 {
1324 require_once './Modules/Test/classes/class.ilObjTest.php';
1325
1326 if (ilObjTest::_getUsePreviousAnswers($this->testSession->getActiveId(), true)) {
1327 $currentSolutionAvailable = $questionGui->object->authorizedOrIntermediateSolutionExists(
1328 $this->testSession->getActiveId(),
1329 $this->testSession->getPass()
1330 );
1331
1332 if (!$currentSolutionAvailable) {
1333 $previousPass = $questionGui->object->getSolutionMaxPass(
1334 $this->testSession->getActiveId()
1335 );
1336
1337 $previousSolutionAvailable = $questionGui->object->authorizedSolutionExists(
1338 $this->testSession->getActiveId(),
1339 $previousPass
1340 );
1341
1342 if ($previousSolutionAvailable) {
1343 return $previousPass;
1344 }
1345 }
1346 }
1347
1348 return $this->testSession->getPass();
1349 }
1350 // hey.
1351
1352 abstract protected function showQuestionCmd();
1353
1354 abstract protected function editSolutionCmd();
1355
1356 abstract protected function submitSolutionCmd();
1357
1358 // fau: testNav - new function to revert probably auto-saved changes and show the last submitted question state
1359 protected function revertChangesCmd()
1360 {
1362 $this->setAnswerChangedParameter(false);
1363 $this->ctrl->saveParameter($this, 'sequence');
1364 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
1365 }
1366 // fau.
1367
1368 abstract protected function discardSolutionCmd();
1369
1370 abstract protected function skipQuestionCmd();
1371
1372 abstract protected function startTestCmd();
1380 public function checkOnlineTestAccess()
1381 {
1382 global $DIC;
1383 $ilUser = $DIC['ilUser'];
1384
1385 // check if user is invited to participate
1386 $user = $this->object->getInvitedUsers($ilUser->getId());
1387 if (!is_array($user) || count($user) != 1) {
1388 ilUtil::sendInfo($this->lng->txt("user_not_invited"), true);
1389 $this->ctrl->redirectByClass("ilobjtestgui", "backToRepository");
1390 }
1391
1392 $user = array_pop($user);
1393 // check if client ip is set and if current remote addr is equal to stored client-ip
1394 if (strcmp($user["clientip"], "") != 0 && strcmp($user["clientip"], $_SERVER["REMOTE_ADDR"]) != 0) {
1395 ilUtil::sendInfo($this->lng->txt("user_wrong_clientip"), true);
1396 $this->ctrl->redirectByClass("ilobjtestgui", "backToRepository");
1397 }
1398 }
1399
1400
1404 public function isTestAccessible()
1405 {
1406 return !$this->isNrOfTriesReached()
1407 and !$this->isMaxProcessingTimeReached()
1408 and $this->object->startingTimeReached()
1409 and !$this->object->endingTimeReached();
1410 }
1411
1415 public function isNrOfTriesReached()
1416 {
1417 return $this->object->hasNrOfTriesRestriction() && $this->object->isNrOfTriesReached($this->testSession->getPass());
1418 }
1419
1425 public function endingTimeReached()
1426 {
1427 ilUtil::sendInfo(sprintf($this->lng->txt("detail_ending_time_reached"), ilDatePresentation::formatDate(new ilDateTime($this->object->getEndingTime(), IL_CAL_UNIX))));
1428 $this->testSession->increasePass();
1429 $this->testSession->setLastSequence(0);
1430 $this->testSession->saveToDb();
1431
1432 $this->redirectBackCmd();
1433 }
1434
1443 {
1444 $this->suspendTestCmd();
1445 }
1446
1452 public function confirmSubmitAnswers()
1453 {
1454 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_submit_answers_confirm.html", "Modules/Test");
1455 $this->tpl->setCurrentBlock("adm_content");
1456 if ($this->object->isTestFinished($this->testSession->getActiveId())) {
1457 $this->tpl->setCurrentBlock("not_submit_allowed");
1458 $this->tpl->setVariable("TEXT_ALREADY_SUBMITTED", $this->lng->txt("tst_already_submitted"));
1459 $this->tpl->setVariable("BTN_OK", $this->lng->txt("tst_show_answer_sheet"));
1460 } else {
1461 $this->tpl->setCurrentBlock("submit_allowed");
1462 $this->tpl->setVariable("TEXT_CONFIRM_SUBMIT_RESULTS", $this->lng->txt("tst_confirm_submit_answers"));
1463 $this->tpl->setVariable("BTN_OK", $this->lng->txt("tst_submit_results"));
1464 }
1465 $this->tpl->setVariable("BTN_BACK", $this->lng->txt("back"));
1466 $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this, "finalSubmission"));
1467 $this->tpl->parseCurrentBlock();
1468 }
1469
1470 public function outProcessingTime($active_id)
1471 {
1472 global $DIC;
1473 $ilUser = $DIC['ilUser'];
1474
1475 $starting_time = $this->object->getStartingTimeOfUser($active_id);
1476 $processing_time = $this->object->getProcessingTimeInSeconds($active_id);
1477 $processing_time_minutes = floor($processing_time / 60);
1478 $processing_time_seconds = $processing_time - $processing_time_minutes * 60;
1479 $str_processing_time = "";
1480 if ($processing_time_minutes > 0) {
1481 $str_processing_time = $processing_time_minutes . " " . ($processing_time_minutes == 1 ? $this->lng->txt("minute") : $this->lng->txt("minutes"));
1482 }
1483 if ($processing_time_seconds > 0) {
1484 if (strlen($str_processing_time) > 0) {
1485 $str_processing_time .= " " . $this->lng->txt("and") . " ";
1486 }
1487 $str_processing_time .= $processing_time_seconds . " " . ($processing_time_seconds == 1 ? $this->lng->txt("second") : $this->lng->txt("seconds"));
1488 }
1489 $time_left = $starting_time + $processing_time - time();
1490 $time_left_minutes = floor($time_left / 60);
1491 $time_left_seconds = $time_left - $time_left_minutes * 60;
1492 $str_time_left = "";
1493 if ($time_left_minutes > 0) {
1494 $str_time_left = $time_left_minutes . " " . ($time_left_minutes == 1 ? $this->lng->txt("minute") : $this->lng->txt("minutes"));
1495 }
1496 if ($time_left < 300) {
1497 if ($time_left_seconds > 0) {
1498 if (strlen($str_time_left) > 0) {
1499 $str_time_left .= " " . $this->lng->txt("and") . " ";
1500 }
1501 $str_time_left .= $time_left_seconds . " " . ($time_left_seconds == 1 ? $this->lng->txt("second") : $this->lng->txt("seconds"));
1502 }
1503 }
1504 $date = getdate($starting_time);
1505 $formattedStartingTime = ilDatePresentation::formatDate(new ilDateTime($date, IL_CAL_FKT_GETDATE));
1506 $datenow = getdate();
1507 $this->tpl->setCurrentBlock("enableprocessingtime");
1508 $this->tpl->setVariable(
1509 "USER_WORKING_TIME",
1510 sprintf(
1511 $this->lng->txt("tst_time_already_spent"),
1512 $formattedStartingTime,
1513 $str_processing_time
1514 )
1515 );
1516 $this->tpl->setVariable("USER_REMAINING_TIME", sprintf($this->lng->txt("tst_time_already_spent_left"), $str_time_left));
1517 $this->tpl->parseCurrentBlock();
1518
1519 // jQuery is required by tpl.workingtime.js
1520 require_once "./Services/jQuery/classes/class.iljQueryUtil.php";
1522 $template = new ilTemplate("tpl.workingtime.js", true, true, 'Modules/Test');
1523 $template->setVariable("STRING_MINUTE", $this->lng->txt("minute"));
1524 $template->setVariable("STRING_MINUTES", $this->lng->txt("minutes"));
1525 $template->setVariable("STRING_SECOND", $this->lng->txt("second"));
1526 $template->setVariable("STRING_SECONDS", $this->lng->txt("seconds"));
1527 $template->setVariable("STRING_TIMELEFT", $this->lng->txt("tst_time_already_spent_left"));
1528 $template->setVariable("AND", strtolower($this->lng->txt("and")));
1529 $template->setVariable("YEAR", $date["year"]);
1530 $template->setVariable("MONTH", $date["mon"] - 1);
1531 $template->setVariable("DAY", $date["mday"]);
1532 $template->setVariable("HOUR", $date["hours"]);
1533 $template->setVariable("MINUTE", $date["minutes"]);
1534 $template->setVariable("SECOND", $date["seconds"]);
1535 if ($this->object->isEndingTimeEnabled()) {
1536 $date_time = new ilDateTime($this->object->getEndingTime(), IL_CAL_UNIX);
1537 preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $date_time->get(IL_CAL_TIMESTAMP), $matches);
1538 if (!empty($matches)) {
1539 $template->setVariable("ENDYEAR", $matches[1]);
1540 $template->setVariable("ENDMONTH", $matches[2] - 1);
1541 $template->setVariable("ENDDAY", $matches[3]);
1542 $template->setVariable("ENDHOUR", $matches[4]);
1543 $template->setVariable("ENDMINUTE", $matches[5]);
1544 $template->setVariable("ENDSECOND", $matches[6]);
1545 }
1546 }
1547 $template->setVariable("YEARNOW", $datenow["year"]);
1548 $template->setVariable("MONTHNOW", $datenow["mon"] - 1);
1549 $template->setVariable("DAYNOW", $datenow["mday"]);
1550 $template->setVariable("HOURNOW", $datenow["hours"]);
1551 $template->setVariable("MINUTENOW", $datenow["minutes"]);
1552 $template->setVariable("SECONDNOW", $datenow["seconds"]);
1553 $template->setVariable("PTIME_M", $processing_time_minutes);
1554 $template->setVariable("PTIME_S", $processing_time_seconds);
1555 if ($this->ctrl->getCmd() == 'outQuestionSummary') {
1556 $template->setVariable("REDIRECT_URL", $this->ctrl->getFormAction($this, 'redirectAfterDashboard'));
1557 } else {
1558 $template->setVariable("REDIRECT_URL", "");
1559 }
1560 $template->setVariable("CHECK_URL", $this->ctrl->getLinkTarget($this, 'checkWorkingTime', '', true));
1561 $this->tpl->addOnLoadCode($template->get());
1562 }
1563
1571 public function checkWorkingTimeCmd() : void
1572 {
1573 $active_id = $this->testSession->getActiveId();
1574 echo (string) $this->object->getProcessingTimeInSeconds($active_id);
1575 exit;
1576 }
1577
1578 protected function showSideList($presentationMode, $currentSequenceElement)
1579 {
1580 global $DIC;
1581 $ilUser = $DIC['ilUser'];
1582
1583 $sideListActive = $ilUser->getPref('side_list_of_questions');
1584
1585 if ($sideListActive) {
1586 $questionSummaryData = $this->service->getQuestionSummaryData($this->testSequence, false);
1587
1588 require_once 'Modules/Test/classes/class.ilTestQuestionSideListGUI.php';
1589 $questionSideListGUI = new ilTestQuestionSideListGUI($this->ctrl, $this->lng);
1590 $questionSideListGUI->setTargetGUI($this);
1591 $questionSideListGUI->setQuestionSummaryData($questionSummaryData);
1592 $questionSideListGUI->setCurrentSequenceElement($currentSequenceElement);
1593 // fau: testNav - set side list presentation mode to "view" to allow navigation when question is in edit mode
1594 $questionSideListGUI->setCurrentPresentationMode(ilTestPlayerAbstractGUI::PRESENTATION_MODE_VIEW);
1595 $questionSideListGUI->setDisabled(false);
1596 // $questionSideListGUI->setCurrentPresentationMode($presentationMode);
1597 // $questionSideListGUI->setDisabled($presentationMode == self::PRESENTATION_MODE_EDIT);
1598 // fau.
1599 $this->tpl->setVariable('LIST_OF_QUESTIONS', $questionSideListGUI->getHTML());
1600 }
1601 }
1602
1603 abstract protected function isQuestionSummaryFinishTestButtonRequired();
1604
1608 public function outQuestionSummaryCmd($fullpage = true, $contextFinishTest = false, $obligationsInfo = false, $obligationsFilter = false)
1609 {
1610 global $DIC;
1611 $help = $DIC->help();
1612
1613 $help->setScreenIdComponent("tst");
1614 $help->setScreenId("assessment");
1615 $help->setSubScreenId("question_summary");
1616
1617 if ($fullpage) {
1618 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_question_summary.html", "Modules/Test");
1619 }
1620
1621 $obligationsFulfilled = \ilObjTest::allObligationsAnswered(
1622 $this->object->getId(),
1623 $this->testSession->getActiveId(),
1624 $this->testSession->getPass()
1625 );
1626
1627 if ($obligationsInfo && $this->object->areObligationsEnabled() && !$obligationsFulfilled) {
1628 ilUtil::sendFailure($this->lng->txt('not_all_obligations_answered'));
1629 }
1630
1631 if ($this->object->getKioskMode() && $fullpage) {
1632 $head = $this->getKioskHead();
1633 if (strlen($head)) {
1634 $this->tpl->setCurrentBlock("kiosk_options");
1635 $this->tpl->setVariable("KIOSK_HEAD", $head);
1636 $this->tpl->parseCurrentBlock();
1637 }
1638 }
1639
1640
1641 $active_id = $this->testSession->getActiveId();
1642 $questionSummaryData = $this->service->getQuestionSummaryData($this->testSequence, $obligationsFilter);
1643
1644 $this->ctrl->setParameter($this, "sequence", $_GET["sequence"]);
1645
1646 if ($fullpage) {
1647 include_once "./Modules/Test/classes/tables/class.ilListOfQuestionsTableGUI.php";
1648 $table_gui = new ilListOfQuestionsTableGUI($this, 'showQuestion');
1649
1650 $table_gui->setShowPointsEnabled(!$this->object->getTitleOutput());
1651 $table_gui->setShowMarkerEnabled($this->object->getShowMarker());
1652 $table_gui->setObligationsNotAnswered(!$obligationsFulfilled);
1653 $table_gui->setShowObligationsEnabled($this->object->areObligationsEnabled());
1654 $table_gui->setObligationsFilterEnabled($obligationsFilter);
1655 $table_gui->setFinishTestButtonEnabled($this->isQuestionSummaryFinishTestButtonRequired());
1656
1657 $table_gui->init();
1658
1659 $table_gui->setData($questionSummaryData);
1660
1661 $this->tpl->setVariable('TABLE_LIST_OF_QUESTIONS', $table_gui->getHTML());
1662
1663 if ($this->object->getEnableProcessingTime()) {
1664 $this->outProcessingTime($active_id);
1665 }
1666
1667 if ($this->object->isShowExamIdInTestPassEnabled()) {
1668 $this->tpl->setCurrentBlock('exam_id_footer');
1669 $this->tpl->setVariable('EXAM_ID_VAL', ilObjTest::lookupExamId(
1670 $this->testSession->getActiveId(),
1671 $this->testSession->getPass(),
1672 $this->object->getId()
1673 ));
1674 $this->tpl->setVariable('EXAM_ID_TXT', $this->lng->txt('exam_id'));
1675 $this->tpl->parseCurrentBlock();
1676 }
1677 }
1678 }
1679
1681 {
1682 return $this->outQuestionSummaryCmd(true, true, true, false);
1683 }
1684
1686 {
1687 return $this->outQuestionSummaryCmd(true, true, true, true);
1688 }
1689
1691 {
1692 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_max_allowed_users_reached.html", "Modules/Test");
1693 $this->tpl->setCurrentBlock("adm_content");
1694 $this->tpl->setVariable("MAX_ALLOWED_USERS_MESSAGE", sprintf($this->lng->txt("tst_max_allowed_users_message"), $this->object->getAllowedUsersTimeGap()));
1695 $this->tpl->setVariable("MAX_ALLOWED_USERS_HEADING", sprintf($this->lng->txt("tst_max_allowed_users_heading"), $this->object->getAllowedUsersTimeGap()));
1696 $this->tpl->setVariable("CMD_BACK_TO_INFOSCREEN", ilTestPlayerCommands::BACK_TO_INFO_SCREEN);
1697 $this->tpl->setVariable("TXT_BACK_TO_INFOSCREEN", $this->lng->txt("tst_results_back_introduction"));
1698 $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
1699 $this->tpl->parseCurrentBlock();
1700 }
1701
1702 public function backFromFinishingCmd()
1703 {
1704 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
1705 }
1706
1712 public function outCorrectSolution()
1713 {
1714 $this->tpl->addBlockFile("ADM_CONTENT", "adm_content", "tpl.il_as_tst_correct_solution.html", "Modules/Test");
1715
1716 include_once("./Services/Style/Content/classes/class.ilObjStyleSheet.php");
1717 $this->tpl->setCurrentBlock("ContentStyle");
1718 $this->tpl->setVariable("LOCATION_CONTENT_STYLESHEET", ilObjStyleSheet::getContentStylePath(0));
1719 $this->tpl->parseCurrentBlock();
1720
1721 $this->tpl->setCurrentBlock("SyntaxStyle");
1722 $this->tpl->setVariable("LOCATION_SYNTAX_STYLESHEET", ilObjStyleSheet::getSyntaxStylePath());
1723 $this->tpl->parseCurrentBlock();
1724
1725 $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
1726 if ($this->object->getShowSolutionAnswersOnly()) {
1727 $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print_hide_content.css", "Modules/Test"), "print");
1728 }
1729
1730 $this->tpl->setCurrentBlock("adm_content");
1731 $solution = $this->getCorrectSolutionOutput($_GET["evaluation"], $_GET["active_id"], $_GET["pass"]);
1732 $this->tpl->setVariable("OUTPUT_SOLUTION", $solution);
1733 $this->tpl->setVariable("TEXT_BACK", $this->lng->txt("back"));
1734 $this->ctrl->saveParameter($this, "pass");
1735 $this->ctrl->saveParameter($this, "active_id");
1736 $this->tpl->setVariable("URL_BACK", $this->ctrl->getLinkTarget($this, "outUserResultsOverview"));
1737 $this->tpl->parseCurrentBlock();
1738 }
1739
1749 public function showListOfAnswers($active_id, $pass = null, $top_data = "", $bottom_data = "")
1750 {
1751 global $DIC;
1752 $ilUser = $DIC['ilUser'];
1753
1754 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_finish_list_of_answers.html", "Modules/Test");
1755
1756 $result_array = &$this->object->getTestResult(
1757 $active_id,
1758 $pass,
1759 false,
1760 !$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()
1761 );
1762
1763 $counter = 1;
1764 // output of questions with solutions
1765 foreach ($result_array as $question_data) {
1766 $question = $question_data["qid"];
1767 if (is_numeric($question)) {
1768 $this->tpl->setCurrentBlock("printview_question");
1769 $question_gui = $this->object->createQuestionGUI("", $question);
1770 $template = new ilTemplate("tpl.il_as_qpl_question_printview.html", true, true, "Modules/TestQuestionPool");
1771 $template->setVariable("COUNTER_QUESTION", $counter . ". ");
1772 $template->setVariable("QUESTION_TITLE", $question_gui->object->getTitle());
1773
1774 $show_question_only = ($this->object->getShowSolutionAnswersOnly()) ? true : false;
1775 $result_output = $question_gui->getSolutionOutput($active_id, $pass, false, false, $show_question_only, $this->object->getShowSolutionFeedback());
1776 $template->setVariable("SOLUTION_OUTPUT", $result_output);
1777 $this->tpl->setVariable("QUESTION_OUTPUT", $template->get());
1778 $this->tpl->parseCurrentBlock();
1779 $counter++;
1780 }
1781 }
1782
1783 $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
1784 if ($this->object->getShowSolutionAnswersOnly()) {
1785 $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print_hide_content.css", "Modules/Test"), "print");
1786 }
1787 if (strlen($top_data)) {
1788 $this->tpl->setCurrentBlock("top_data");
1789 $this->tpl->setVariable("TOP_DATA", $top_data);
1790 $this->tpl->parseCurrentBlock();
1791 }
1792
1793 if (strlen($bottom_data)) {
1794 $this->tpl->setCurrentBlock("bottom_data");
1795 $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
1796 $this->tpl->setVariable("BOTTOM_DATA", $bottom_data);
1797 $this->tpl->parseCurrentBlock();
1798 }
1799
1800 $this->tpl->setCurrentBlock("adm_content");
1801 $this->tpl->setVariable("TXT_ANSWER_SHEET", $this->lng->txt("tst_list_of_answers"));
1802 $user_data = $this->getAdditionalUsrDataHtmlAndPopulateWindowTitle($this->testSession, $active_id, true);
1803 $signature = $this->getResultsSignature();
1804 $this->tpl->setVariable("USER_DETAILS", $user_data);
1805 $this->tpl->setVariable("SIGNATURE", $signature);
1806 $this->tpl->setVariable("TITLE", $this->object->getTitle());
1807 $this->tpl->setVariable("TXT_TEST_PROLOG", $this->lng->txt("tst_your_answers"));
1808 $invited_user = &$this->object->getInvitedUsers($ilUser->getId());
1809 $pagetitle = $this->object->getTitle() . " - " . $this->lng->txt("clientip") .
1810 ": " . $invited_user[$ilUser->getId()]["clientip"] . " - " .
1811 $this->lng->txt("matriculation") . ": " .
1812 $invited_user[$ilUser->getId()]["matriculation"];
1813 $this->tpl->setVariable("PAGETITLE", $pagetitle);
1814 $this->tpl->parseCurrentBlock();
1815 }
1816
1822 public function getContentBlockName()
1823 {
1824 return "ADM_CONTENT";
1825
1826 if ($this->object->getKioskMode()) {
1827 $this->tpl->setBodyClass("kiosk");
1828 $this->tpl->hideFooter();
1829 return "CONTENT";
1830 } else {
1831 return "ADM_CONTENT";
1832 }
1833 }
1834
1836 {
1837 $this->ctrl->redirectByClass(
1838 array('ilRepositoryGUI', 'ilObjTestGUI', 'ilTestEvaluationGUI'),
1839 "outUserResultsOverview"
1840 );
1841 }
1842
1846 protected function showRequestedHintListCmd()
1847 {
1848 // fau: testNav - handle intermediate submit for viewing requested hints
1849 $this->handleIntermediateSubmit();
1850 // fau.
1851
1852 $this->ctrl->setParameter($this, 'pmode', self::PRESENTATION_MODE_EDIT);
1853
1854 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintRequestGUI.php';
1855 $this->ctrl->redirectByClass('ilAssQuestionHintRequestGUI', ilAssQuestionHintRequestGUI::CMD_SHOW_LIST);
1856 }
1857
1861 protected function confirmHintRequestCmd()
1862 {
1863 // fau: testNav - handle intermediate submit for confirming hint requests
1864 $this->handleIntermediateSubmit();
1865 // fau.
1866
1867 $this->ctrl->setParameter($this, 'pmode', self::PRESENTATION_MODE_EDIT);
1868
1869 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintRequestGUI.php';
1870 $this->ctrl->redirectByClass('ilAssQuestionHintRequestGUI', ilAssQuestionHintRequestGUI::CMD_CONFIRM_REQUEST);
1871 }
1872
1873 abstract protected function isFirstQuestionInSequence($sequenceElement);
1874
1875 abstract protected function isLastQuestionInSequence($sequenceElement);
1876
1877
1878 abstract protected function handleQuestionActionCmd();
1879
1880 abstract protected function showInstantResponseCmd();
1881
1882 abstract protected function nextQuestionCmd();
1883
1884 abstract protected function previousQuestionCmd();
1885
1886 protected function prepareSummaryPage()
1887 {
1888 $this->tpl->addBlockFile(
1889 $this->getContentBlockName(),
1890 'adm_content',
1891 'tpl.il_as_tst_question_summary.html',
1892 'Modules/Test'
1893 );
1894
1895 if ($this->object->getKioskMode()) {
1896 $this->populateKioskHead();
1897 }
1898 }
1899
1900 protected function initTestPageTemplate()
1901 {
1902 $this->tpl->addBlockFile(
1903 $this->getContentBlockName(),
1904 'adm_content',
1905 'tpl.il_as_tst_output.html',
1906 'Modules/Test'
1907 );
1908 }
1909
1910 protected function populateKioskHead()
1911 {
1912 $head = $this->getKioskHead();
1913
1914 if (strlen($head)) {
1915 $this->tpl->setCurrentBlock("kiosk_options");
1916 $this->tpl->setVariable("KIOSK_HEAD", $head);
1917 $this->tpl->parseCurrentBlock();
1918 }
1919 }
1920
1922 {
1929 if ($this->testSession->isPasswordChecked() === true) {
1930 return;
1931 }
1932
1933 if ($this->ctrl->getNextClass() == 'iltestpasswordprotectiongui') {
1934 return;
1935 }
1936
1937 if (!$this->passwordChecker->isPasswordProtectionPageRedirectRequired()) {
1938 $this->testSession->setPasswordChecked(true);
1939 return;
1940 }
1941
1942 $this->ctrl->setParameter($this, 'lock', $this->getLockParameter());
1943
1944 $nextCommand = $this->ctrl->getCmdClass() . '::' . $this->ctrl->getCmd();
1945 $this->ctrl->setParameterByClass('ilTestPasswordProtectionGUI', 'nextCommand', $nextCommand);
1946 $this->ctrl->redirectByClass('ilTestPasswordProtectionGUI', 'showPasswordForm');
1947 }
1948
1949 protected function isParticipantsAnswerFixed($questionId)
1950 {
1951 if ($this->object->isInstantFeedbackAnswerFixationEnabled() && $this->testSequence->isQuestionChecked($questionId)) {
1952 return true;
1953 }
1954
1955 if ($this->object->isFollowupQuestionAnswerFixationEnabled() && $this->testSequence->isNextQuestionPresented($questionId)) {
1956 return true;
1957 }
1958
1959 return false;
1960 }
1961
1966 {
1967 return $this->lng->txt("save_introduction");
1968 }
1969
1970 protected function initAssessmentSettings()
1971 {
1972 $this->assSettings = new ilSetting('assessment');
1973 }
1974
1979 {
1980 $questionList = $this->buildTestPassQuestionList();
1981 $questionList->load();
1982
1983 $testResults = $this->object->getTestResult($testSession->getActiveId(), $testSession->getPass(), true);
1984
1985 require_once 'Modules/Test/classes/class.ilTestSkillEvaluation.php';
1986 $skillEvaluation = new ilTestSkillEvaluation($this->db, $this->object->getTestId(), $this->object->getRefId());
1987
1988 $skillEvaluation->setUserId($testSession->getUserId());
1989 $skillEvaluation->setActiveId($testSession->getActiveId());
1990 $skillEvaluation->setPass($testSession->getPass());
1991
1992 $skillEvaluation->setNumRequiredBookingsForSkillTriggering($this->assSettings->get(
1993 'ass_skl_trig_num_answ_barrier',
1995 ));
1996
1997
1998 $skillEvaluation->init($questionList);
1999 $skillEvaluation->evaluate($testResults);
2000
2001 $skillEvaluation->handleSkillTriggering();
2002 }
2003
2004 abstract protected function buildTestPassQuestionList();
2005
2007 {
2008 require_once 'Modules/Test/classes/confirmations/class.ilTestAnswerOptionalQuestionsConfirmationGUI.php';
2009 $confirmation = new ilTestAnswerOptionalQuestionsConfirmationGUI($this->lng);
2010
2011 $confirmation->setFormAction($this->ctrl->getFormAction($this));
2012 $confirmation->setCancelCmd('cancelAnswerOptionalQuestions');
2013 $confirmation->setConfirmCmd('confirmAnswerOptionalQuestions');
2014
2015 $confirmation->build($this->object->isFixedTest());
2016
2017 $this->populateHelperGuiContent($confirmation);
2018 }
2019
2021 {
2022 $this->testSequence->setAnsweringOptionalQuestionsConfirmed(true);
2023 $this->testSequence->saveToDb();
2024
2025 $this->ctrl->setParameter($this, 'activecommand', 'gotoquestion');
2026 $this->ctrl->redirect($this, 'redirectQuestion');
2027 }
2028
2030 {
2031 if ($this->object->getListOfQuestions()) {
2032 $this->ctrl->setParameter($this, 'activecommand', 'summary');
2033 } else {
2034 $this->ctrl->setParameter($this, 'activecommand', 'previous');
2035 }
2036
2037 $this->ctrl->redirect($this, 'redirectQuestion');
2038 }
2039
2043 protected function populateHelperGuiContent($helperGui)
2044 {
2045 if ($this->object->getKioskMode()) {
2046 //$this->tpl->setBodyClass("kiosk");
2047 $this->tpl->hideFooter();
2048 $this->tpl->addBlockfile('CONTENT', 'adm_content', "tpl.il_as_tst_kiosk_mode_content.html", "Modules/Test");
2049 $this->tpl->setContent($this->ctrl->getHTML($helperGui));
2050 } else {
2051 $this->tpl->setVariable($this->getContentBlockName(), $this->ctrl->getHTML($helperGui));
2052 }
2053 }
2054
2059 {
2060 global $DIC;
2061 $ilSetting = $DIC['ilSetting'];
2062
2063 if ($ilSetting->get('char_selector_availability') > 0) {
2064 require_once 'Services/UIComponent/CharSelector/classes/class.ilCharSelectorGUI.php';
2065 $char_selector = ilCharSelectorGUI::_getCurrentGUI($this->object);
2066 if ($char_selector->getConfig()->getAvailability() == ilCharSelectorConfig::ENABLED) {
2067 $char_selector->addToPage();
2068 $this->tpl->setCurrentBlock('char_selector');
2069 $this->tpl->setVariable("CHAR_SELECTOR_TEMPLATE", $char_selector->getSelectorHtml());
2070 $this->tpl->parseCurrentBlock();
2071
2072 return true;
2073 }
2074 }
2075
2076 return false;
2077 }
2078
2079 protected function getTestNavigationToolbarGUI()
2080 {
2081 global $DIC;
2082 $ilUser = $DIC['ilUser'];
2083
2084 require_once 'Modules/Test/classes/class.ilTestNavigationToolbarGUI.php';
2085 $navigationToolbarGUI = new ilTestNavigationToolbarGUI($this->ctrl, $this->lng, $this);
2086
2087 $navigationToolbarGUI->setSuspendTestButtonEnabled($this->object->getShowCancel());
2088 $navigationToolbarGUI->setQuestionTreeButtonEnabled($this->object->getListOfQuestions());
2089 $navigationToolbarGUI->setQuestionTreeVisible($ilUser->getPref('side_list_of_questions'));
2090 $navigationToolbarGUI->setQuestionListButtonEnabled($this->object->getListOfQuestions());
2091 $navigationToolbarGUI->setFinishTestCommand($this->getFinishTestCommand());
2092
2093 return $navigationToolbarGUI;
2094 }
2095
2096 protected function buildReadOnlyStateQuestionNavigationGUI($questionId)
2097 {
2098 require_once 'Modules/Test/classes/class.ilTestQuestionNavigationGUI.php';
2099 $navigationGUI = new ilTestQuestionNavigationGUI($this->lng);
2100
2101 if (!$this->isParticipantsAnswerFixed($questionId)) {
2102 $navigationGUI->setEditSolutionCommand(ilTestPlayerCommands::EDIT_SOLUTION);
2103 }
2104
2105 if ($this->object->getShowMarker()) {
2106 include_once "./Modules/Test/classes/class.ilObjTest.php";
2107 $solved_array = ilObjTest::_getSolvedQuestions($this->testSession->getActiveId(), $questionId);
2108 $solved = 0;
2109
2110 if (count($solved_array) > 0) {
2111 $solved = array_pop($solved_array);
2112 $solved = $solved["solved"];
2113 }
2114 // fau: testNav - change question mark command to link target
2115 if ($solved == 1) {
2116 $navigationGUI->setQuestionMarkLinkTarget($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::UNMARK_QUESTION));
2117 $navigationGUI->setQuestionMarked(true);
2118 } else {
2119 $navigationGUI->setQuestionMarkLinkTarget($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::MARK_QUESTION));
2120 $navigationGUI->setQuestionMarked(false);
2121 }
2122 }
2123 // fau.
2124
2125 return $navigationGUI;
2126 }
2127
2128 protected function buildEditableStateQuestionNavigationGUI($questionId, $charSelectorAvailable)
2129 {
2130 require_once 'Modules/Test/classes/class.ilTestQuestionNavigationGUI.php';
2131 $navigationGUI = new ilTestQuestionNavigationGUI($this->lng);
2132
2133 if ($this->object->isForceInstantFeedbackEnabled()) {
2134 $navigationGUI->setSubmitSolutionCommand(ilTestPlayerCommands::SUBMIT_SOLUTION);
2135 } else {
2136 // fau: testNav - use simple "submitSolution" button instead of "submitSolutionAndNext"
2137 $navigationGUI->setSubmitSolutionCommand(ilTestPlayerCommands::SUBMIT_SOLUTION);
2138 // fau.
2139 }
2140
2141 // fau: testNav - add a 'revert changes' link for editable question
2142 $navigationGUI->setRevertChangesLinkTarget($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::REVERT_CHANGES));
2143 // fau.
2144
2145
2146 // feedback
2147 switch (1) {
2148 case $this->object->getSpecificAnswerFeedback():
2149 case $this->object->getGenericAnswerFeedback():
2150 case $this->object->getAnswerFeedbackPoints():
2151 case $this->object->getInstantFeedbackSolution():
2152
2153 $navigationGUI->setAnswerFreezingEnabled($this->object->isInstantFeedbackAnswerFixationEnabled());
2154
2155 if ($this->object->isForceInstantFeedbackEnabled()) {
2156 $navigationGUI->setForceInstantResponseEnabled(true);
2157 $navigationGUI->setInstantFeedbackCommand(ilTestPlayerCommands::SUBMIT_SOLUTION);
2158 } else {
2159 $navigationGUI->setInstantFeedbackCommand(ilTestPlayerCommands::SHOW_INSTANT_RESPONSE);
2160 }
2161 }
2162
2163 // hints
2164 if ($this->object->isOfferingQuestionHintsEnabled()) {
2165 $activeId = $this->testSession->getActiveId();
2166 $pass = $this->testSession->getPass();
2167
2168 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
2169 $questionHintTracking = new ilAssQuestionHintTracking($questionId, $activeId, $pass);
2170
2171 if ($questionHintTracking->requestsPossible()) {
2172 $navigationGUI->setRequestHintCommand(ilTestPlayerCommands::CONFIRM_HINT_REQUEST);
2173 }
2174
2175 if ($questionHintTracking->requestsExist()) {
2176 $navigationGUI->setShowHintsCommand(ilTestPlayerCommands::SHOW_REQUESTED_HINTS_LIST);
2177 }
2178 }
2179
2180 $navigationGUI->setCharSelectorEnabled($charSelectorAvailable);
2181
2182 if ($this->object->getShowMarker()) {
2183 include_once "./Modules/Test/classes/class.ilObjTest.php";
2184 $solved_array = ilObjTest::_getSolvedQuestions($this->testSession->getActiveId(), $questionId);
2185 $solved = 0;
2186
2187 if (count($solved_array) > 0) {
2188 $solved = array_pop($solved_array);
2189 $solved = $solved["solved"];
2190 }
2191
2192 // fau: testNav - change question mark command to link target
2193 if ($solved == 1) {
2194 $navigationGUI->setQuestionMarkLinkTarget($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::UNMARK_QUESTION_SAVE));
2195 $navigationGUI->setQuestionMarked(true);
2196 } else {
2197 $navigationGUI->setQuestionMarkLinkTarget($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::MARK_QUESTION_SAVE));
2198 $navigationGUI->setQuestionMarked(false);
2199 }
2200 }
2201 // fau.
2202 return $navigationGUI;
2203 }
2204
2208 protected function getFinishTestCommand()
2209 {
2210 if (!$this->object->getListOfQuestionsEnd()) {
2211 return 'finishTest';
2212 }
2213
2214 if ($this->object->areObligationsEnabled()) {
2215 $allObligationsAnswered = ilObjTest::allObligationsAnswered(
2216 $this->testSession->getTestId(),
2217 $this->testSession->getActiveId(),
2218 $this->testSession->getPass()
2219 );
2220
2221 if (!$allObligationsAnswered) {
2222 return 'outQuestionSummaryWithObligationsInfo';
2223 }
2224 }
2225
2226 return 'outQuestionSummary';
2227 }
2228
2229 // fau: testNav - populateIntermediateSolutionSaver is obsolete and can be deletd.
2230 // /**
2231 // * @param assQuestionGUI $questionGui
2232 // */
2233 // protected function populateIntermediateSolutionSaver(assQuestionGUI $questionGui)
2234 // {
2235 // $this->tpl->addJavaScript(ilUtil::getJSLocation("autosave.js", "Modules/Test"));
2236//
2237 // $this->tpl->setVariable("AUTOSAVE_URL", $this->ctrl->getFormAction(
2238 // $this, ilTestPlayerCommands::AUTO_SAVE, "", true
2239 // ));
2240//
2241 // if( $questionGui->isAutosaveable() && $this->object->getAutosave() )
2242 // {
2243 // $formAction = $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::AUTO_SAVE, '', false, false);
2244//
2245 // $this->tpl->touchBlock('autosave');
2246 // $this->tpl->setVariable("AUTOSAVEFORMACTION", $formAction);
2247 // $this->tpl->setVariable("AUTOSAVEINTERVAL", $this->object->getAutosaveIval());
2248 // }
2249 // }
2250 // fau.
2251
2252 // fau: testNav - new function populateInstantResponseModal()
2253 protected function populateInstantResponseModal(assQuestionGUI $questionGui, $navUrl)
2254 {
2255 $questionGui->setNavigationGUI(null);
2256 $questionGui->getQuestionHeaderBlockBuilder()->setQuestionAnswered(true);
2257
2258 $answerFeedbackEnabled = $this->object->getSpecificAnswerFeedback();
2259
2260 $solutionoutput = $questionGui->getSolutionOutput(
2261 $this->testSession->getActiveId(), #active_id
2262 $this->testSession->getPass(), #pass
2263 false, #graphical_output
2264 false, #result_output
2265 true, #show_question_only
2266 $answerFeedbackEnabled, #show_feedback
2267 false, #show_correct_solution
2268 false, #show_manual_scoring
2269 true #show_question_text
2270 );
2271
2272 $pageoutput = $questionGui->outQuestionPage(
2273 "",
2274 $this->isShowingPostponeStatusReguired($questionGui->object->getId()),
2275 $this->testSession->getActiveId(),
2276 $solutionoutput
2277 );
2278
2279 $tpl = new ilTemplate('tpl.tst_player_response_modal.html', true, true, 'Modules/Test');
2280
2281 // populate the instant response blocks in the
2282 $saved_tpl = $this->tpl;
2283 $this->tpl = $tpl;
2284 $this->populateInstantResponseBlocks($questionGui, true);
2285 $this->tpl = $saved_tpl;
2286
2287 $tpl->setVariable('QUESTION_OUTPUT', $pageoutput);
2288
2289 $button = ilLinkButton::getInstance();
2290 $button->setId('tst_confirm_feedback');
2291 $button->setUrl($navUrl);
2292 $button->setCaption('proceed');
2293 $button->setPrimary(true);
2294 $tpl->setVariable('BUTTON', $button->render());
2295
2296
2297 require_once('Services/UIComponent/Modal/classes/class.ilModalGUI.php');
2298 $modal = ilModalGUI::getInstance();
2299 $modal->setType(ilModalGUI::TYPE_LARGE);
2300 $modal->setId('tst_question_feedback_modal');
2301 $modal->setHeading($this->lng->txt('tst_instant_feedback'));
2302 $modal->setBody($tpl->get());
2303
2304 $this->tpl->addOnLoadCode("$('#tst_question_feedback_modal').modal('show');");
2305 $this->tpl->setVariable('INSTANT_RESPONSE_MODAL', $modal->getHTML());
2306 }
2307 // fau;
2308
2312 protected function populateInstantResponseBlocks(assQuestionGUI $questionGui, $authorizedSolution)
2313 {
2314 $response_available = false;
2315 $jump_to_response = false;
2316
2317 // This controls if the solution should be shown.
2318 // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Solutions"
2319 if ($this->object->getInstantFeedbackSolution()) {
2320 $show_question_inline_score = $this->determineInlineScoreDisplay();
2321
2322 // Notation of the params prior to getting rid of this crap in favor of a class
2323 $solutionoutput = $questionGui->getSolutionOutput(
2324 $this->testSession->getActiveId(), #active_id
2325 null, #pass
2326 false, #graphical_output
2327 $show_question_inline_score, #result_output
2328 true, #show_question_only
2329 false, #show_feedback
2330 true, #show_correct_solution
2331 false, #show_manual_scoring
2332 false #show_question_text
2333 );
2334 $solutionoutput = str_replace('<h1 class="ilc_page_title_PageTitle"></h1>', '', $solutionoutput);
2335 $this->populateSolutionBlock($solutionoutput);
2336 $response_available = true;
2337 $jump_to_response = true;
2338 }
2339
2340 $reachedPoints = $questionGui->object->getAdjustedReachedPoints(
2341 $this->testSession->getActiveId(),
2342 null,
2343 $authorizedSolution
2344 );
2345
2346 $maxPoints = $questionGui->object->getMaximumPoints();
2347
2348 $solutionCorrect = ($reachedPoints == $maxPoints);
2349
2350 // This controls if the score should be shown.
2351 // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Results (Only Points)"
2352 if ($this->object->getAnswerFeedbackPoints()) {
2353 $this->populateScoreBlock($reachedPoints, $maxPoints);
2354 $response_available = true;
2355 $jump_to_response = true;
2356 }
2357
2358 // This controls if the generic feedback should be shown.
2359 // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Solutions"
2360 if ($this->object->getGenericAnswerFeedback()) {
2361 if ($this->populateGenericFeedbackBlock($questionGui, $solutionCorrect)) {
2362 $response_available = true;
2363 $jump_to_response = true;
2364 }
2365 }
2366
2367 // This controls if the specific feedback should be shown.
2368 // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Answer-Specific Feedback"
2369 if ($this->object->getSpecificAnswerFeedback()) {
2370 if ($questionGui->hasInlineFeedback()) {
2371 // Don't jump to the feedback below the question if some feedback is shown within the question
2372 $jump_to_response = false;
2373 } elseif ($this->populateSpecificFeedbackBlock($questionGui)) {
2374 $response_available = true;
2375 $jump_to_response = true;
2376 }
2377 }
2378
2379 $this->populateFeedbackBlockHeader($jump_to_response);
2380 if (!$response_available) {
2381 if ($questionGui->hasInlineFeedback()) {
2382 $this->populateFeedbackBlockMessage($this->lng->txt('tst_feedback_is_given_inline'));
2383 } else {
2384 $this->populateFeedbackBlockMessage($this->lng->txt('tst_feedback_not_available_for_answer'));
2385 }
2386 }
2387 }
2388
2389 protected function populateFeedbackBlockHeader($withFocusAnchor)
2390 {
2391 if ($withFocusAnchor) {
2392 $this->tpl->setCurrentBlock('inst_resp_id');
2393 $this->tpl->setVariable('INSTANT_RESPONSE_FOCUS_ID', 'focus');
2394 $this->tpl->parseCurrentBlock();
2395 }
2396
2397 $this->tpl->setCurrentBlock('instant_response_header');
2398 $this->tpl->setVariable('INSTANT_RESPONSE_HEADER', $this->lng->txt('tst_feedback'));
2399 $this->tpl->parseCurrentBlock();
2400 }
2401
2402 protected function populateFeedbackBlockMessage(string $a_message)
2403 {
2404 $this->tpl->setCurrentBlock('instant_response_message');
2405 $this->tpl->setVariable('INSTANT_RESPONSE_MESSAGE', $a_message);
2406 $this->tpl->parseCurrentBlock();
2407 }
2408
2409
2410 protected function getCurrentSequenceElement()
2411 {
2412 if ($this->getSequenceElementParameter()) {
2413 return $this->getSequenceElementParameter();
2414 }
2415
2416 return $this->testSession->getLastSequence();
2417 }
2418
2420 {
2421 unset($_GET['sequence']);
2422 $this->ctrl->setParameter($this, 'sequence', null);
2423 }
2424
2425 protected function getSequenceElementParameter()
2426 {
2427 if (isset($_GET['sequence'])) {
2428 return $_GET['sequence'];
2429 }
2430
2431 return null;
2432 }
2433
2434 protected function getPresentationModeParameter()
2435 {
2436 if (isset($_GET['pmode'])) {
2437 return $_GET['pmode'];
2438 }
2439
2440 return null;
2441 }
2442
2443 protected function getInstantResponseParameter()
2444 {
2445 if (isset($_GET['instresp'])) {
2446 return $_GET['instresp'];
2447 }
2448
2449 return null;
2450 }
2451
2452 protected function getNextCommandParameter()
2453 {
2454 if (isset($_POST['nextcmd']) && strlen($_POST['nextcmd'])) {
2455 return $_POST['nextcmd'];
2456 }
2457
2458 return null;
2459 }
2460
2461 protected function getNextSequenceParameter()
2462 {
2463 if (isset($_POST['nextseq']) && is_numeric($_POST['nextseq'])) {
2464 return (int) $_POST['nextseq'];
2465 }
2466
2467 return null;
2468 }
2469
2470 // fau: testNav - get the navigation url set by a submit from ilTestPlayerNavigationControl.js
2471 protected function getNavigationUrlParameter()
2472 {
2473 if (isset($_POST['test_player_navigation_url'])) {
2474 $navigation_url = $_POST['test_player_navigation_url'];
2475
2476 $navigation_url_parts = parse_url($navigation_url);
2477 $ilias_url_parts = parse_url(ilUtil::_getHttpPath());
2478
2479 if (!isset($navigation_url_parts['host']) || ($ilias_url_parts['host'] === $navigation_url_parts['host'])) {
2480 return $navigation_url;
2481 }
2482 }
2483
2484 return null;
2485 }
2486 // fau.
2487
2488 // fau: testNav - get set and check the 'answer_changed' url parameter
2494 protected function getAnswerChangedParameter()
2495 {
2496 return !empty($_GET['test_answer_changed']);
2497 }
2498
2503 protected function setAnswerChangedParameter($changed = true)
2504 {
2505 $this->ctrl->setParameter($this, 'test_answer_changed', $changed ? '1' : '0');
2506 }
2507
2508
2514 protected function handleIntermediateSubmit()
2515 {
2516 if ($this->getAnswerChangedParameter()) {
2517 $this->saveQuestionSolution(false);
2518 } else {
2520 }
2522 }
2523 // fau.
2524
2525 // fau: testNav - save the switch to prevent the navigation confirmation
2530 {
2531 if (!empty($_POST['save_on_navigation_prevent_confirmation'])) {
2532 $_SESSION['save_on_navigation_prevent_confirmation'] = true;
2533 }
2534
2535 if (!empty($_POST[self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM])) {
2537 }
2538 }
2539 // fau.
2540
2544 private $cachedQuestionGuis = array();
2545
2551 protected function getQuestionGuiInstance($question_id, $fromCache = true)
2552 {
2553 global $DIC;
2554 $tpl = $DIC['tpl'];
2555
2556 if (!$fromCache || !isset($this->cachedQuestionGuis[$question_id])) {
2557 $questionGui = $this->object->createQuestionGUI("", $question_id);
2558 $questionGui->setTargetGui($this);
2559 $questionGui->setPresentationContext(assQuestionGUI::PRESENTATION_CONTEXT_TEST);
2560 $questionGui->object->setObligationsToBeConsidered($this->object->areObligationsEnabled());
2561 $questionGui->populateJavascriptFilesRequiredForWorkForm($tpl);
2562 $questionGui->object->setOutputType(OUTPUT_JAVASCRIPT);
2563 $questionGui->object->setShuffler($this->buildQuestionAnswerShuffler((string) $question_id, (string) $this->testSession->getActiveId(), (string) $this->testSession->getPass()));
2564
2565 // hey: prevPassSolutions - determine solution pass index and configure gui accordingly
2566 $this->initTestQuestionConfig($questionGui->object);
2567 // hey.
2568
2569 $this->cachedQuestionGuis[$question_id] = $questionGui;
2570 }
2571
2572 return $this->cachedQuestionGuis[$question_id];
2573 }
2574
2578 private $cachedQuestionObjects = array();
2579
2584 protected function getQuestionInstance($questionId, $fromCache = true)
2585 {
2586 global $DIC;
2587 $ilDB = $DIC['ilDB'];
2588 $ilUser = $DIC['ilUser'];
2589
2590 if (!$fromCache || !isset($this->cachedQuestionObjects[$questionId])) {
2591 $questionOBJ = assQuestion::_instantiateQuestion($questionId);
2592
2593 $assSettings = new ilSetting('assessment');
2594 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
2595 $processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $ilDB);
2596 $processLockerFactory->setQuestionId($questionOBJ->getId());
2597 $processLockerFactory->setUserId($ilUser->getId());
2598 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
2599 $processLockerFactory->setAssessmentLogEnabled(ilObjAssessmentFolder::_enabledAssessmentLogging());
2600 $questionOBJ->setProcessLocker($processLockerFactory->getLocker());
2601
2602 $questionOBJ->setObligationsToBeConsidered($this->object->areObligationsEnabled());
2603 $questionOBJ->setOutputType(OUTPUT_JAVASCRIPT);
2604
2605 // hey: prevPassSolutions - determine solution pass index and configure gui accordingly
2606 $this->initTestQuestionConfig($questionOBJ);
2607 // hey.
2608
2609 $this->cachedQuestionObjects[$questionId] = $questionOBJ;
2610 }
2611
2612 return $this->cachedQuestionObjects[$questionId];
2613 }
2614
2615 // hey: prevPassSolutions - determine solution pass index and configure gui accordingly
2616 protected function initTestQuestionConfig(assQuestion $questionOBJ)
2617 {
2618 $questionOBJ->getTestPresentationConfig()->setPreviousPassSolutionReuseAllowed(
2619 $this->object->isPreviousSolutionReuseEnabled($this->testSession->getActiveId())
2620 );
2621 }
2622
2628 protected function handleTearsAndAngerQuestionIsNull($questionId, $sequenceElement)
2629 {
2630 global $DIC;
2631 $ilLog = $DIC['ilLog'];
2632
2633 $ilLog->write(
2634 "INV SEQ:"
2635 . "active={$this->testSession->getActiveId()} "
2636 . "qId=$questionId seq=$sequenceElement "
2637 . serialize($this->testSequence)
2638 );
2639
2640 $ilLog->logStack('INV SEQ');
2641
2642 $this->ctrl->setParameter($this, 'sequence', $this->testSequence->getFirstSequence());
2643 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
2644 }
2645
2649 protected function populateMessageContent($contentHTML)
2650 {
2651 if ($this->object->getKioskMode()) {
2652 $this->tpl->addBlockfile($this->getContentBlockName(), 'content', "tpl.il_as_tst_kiosk_mode_content.html", "Modules/Test");
2653 $this->tpl->setContent($contentHTML);
2654 } else {
2655 $this->tpl->setVariable($this->getContentBlockName(), $contentHTML);
2656 }
2657 }
2658
2659 protected function populateModals()
2660 {
2661 require_once 'Services/UIComponent/Button/classes/class.ilSubmitButton.php';
2662 require_once 'Services/UIComponent/Button/classes/class.ilLinkButton.php';
2663 require_once 'Services/UIComponent/Modal/classes/class.ilModalGUI.php';
2664
2666 // fau: testNav - populateNavWhenChangedModal instead of populateNavWhileEditModal
2668 // fau.
2669
2670 if ($this->object->isFollowupQuestionAnswerFixationEnabled()) {
2672
2674 }
2675 }
2676
2677 protected function populateDiscardSolutionModal()
2678 {
2679 $tpl = new ilTemplate('tpl.tst_player_confirmation_modal.html', true, true, 'Modules/Test');
2680
2681 $tpl->setVariable('CONFIRMATION_TEXT', $this->lng->txt('discard_answer_confirmation'));
2682
2683 $button = ilSubmitButton::getInstance();
2684 $button->setCommand(ilTestPlayerCommands::DISCARD_SOLUTION);
2685 $button->setCaption('discard_answer');
2686 $tpl->setCurrentBlock('buttons');
2687 $tpl->setVariable('BUTTON', $button->render());
2688 $tpl->parseCurrentBlock();
2689
2690 $button = ilLinkButton::getInstance();
2691 $button->setId('tst_cancel_discard_button');
2692 $button->setCaption('cancel');
2693 $button->setPrimary(true);
2694 $tpl->setCurrentBlock('buttons');
2695 $tpl->setVariable('BUTTON', $button->render());
2696 $tpl->parseCurrentBlock();
2697
2698 $modal = ilModalGUI::getInstance();
2699 $modal->setId('tst_discard_solution_modal');
2700 $modal->setHeading($this->lng->txt('discard_answer'));
2701 $modal->setBody($tpl->get());
2702
2703 $this->tpl->setCurrentBlock('discard_solution_modal');
2704 $this->tpl->setVariable('DISCARD_SOLUTION_MODAL', $modal->getHTML());
2705 $this->tpl->parseCurrentBlock();
2706
2707 // fau: testNav - the discard solution modal is now handled by ilTestPlayerNavigationControl.js
2708// $this->tpl->addJavaScript('Modules/Test/js/ilTestPlayerDiscardSolutionModal.js', true);
2709// fau.
2710 }
2711
2712 // fau: testNav - populateNavWhileEditModal is obsolete and can be deleted.
2713 // protected function populateNavWhileEditModal()
2714 // {
2715 // require_once 'Services/Form/classes/class.ilFormPropertyGUI.php';
2716 // require_once 'Services/Form/classes/class.ilHiddenInputGUI.php';
2717//
2718 // $tpl = new ilTemplate('tpl.tst_player_confirmation_modal.html', true, true, 'Modules/Test');
2719//
2720 // $tpl->setVariable('CONFIRMATION_TEXT', $this->lng->txt('tst_nav_while_edit_modal_text'));
2721//
2722 // $button = ilSubmitButton::getInstance();
2723 // $button->setCommand(ilTestPlayerCommands::SUBMIT_SOLUTION);
2724 // $button->setCaption('tst_nav_while_edit_modal_save_btn');
2725 // $button->setPrimary(true);
2726 // $tpl->setCurrentBlock('buttons');
2727 // $tpl->setVariable('BUTTON', $button->render());
2728 // $tpl->parseCurrentBlock();
2729//
2730 // foreach(array('nextcmd', 'nextseq') as $hiddenPostVar)
2731 // {
2732 // $nextCmdInp = new ilHiddenInputGUI($hiddenPostVar);
2733 // $nextCmdInp->setValue('');
2734 // $tpl->setCurrentBlock('hidden_inputs');
2735 // $tpl->setVariable('HIDDEN_INPUT', $nextCmdInp->getToolbarHTML());
2736 // $tpl->parseCurrentBlock();
2737 // }
2738//
2739 // $button = ilLinkButton::getInstance();
2740 // $this->ctrl->setParameter($this, 'pmode', self::PRESENTATION_MODE_VIEW);
2741 // $button->setId('nextCmdLink');
2742 // $button->setUrl('#');
2743 // $this->ctrl->setParameter($this, 'pmode', $this->getPresentationModeParameter());
2744 // $button->setCaption('tst_nav_while_edit_modal_nosave_btn');
2745 // $tpl->setCurrentBlock('buttons');
2746 // $tpl->setVariable('BUTTON', $button->render());
2747 // $tpl->parseCurrentBlock();
2748//
2749 // $button = ilLinkButton::getInstance();
2750 // $button->setId('tst_cancel_nav_while_edit_button');
2751 // $button->setCaption('tst_nav_while_edit_modal_cancel_btn');
2752 // $tpl->setCurrentBlock('buttons');
2753 // $tpl->setVariable('BUTTON', $button->render());
2754 // $tpl->parseCurrentBlock();
2755//
2756 // $modal = ilModalGUI::getInstance();
2757 // $modal->setId('tst_nav_while_edit_modal');
2758 // $modal->setHeading($this->lng->txt('tst_nav_while_edit_modal_header'));
2759 // $modal->setBody($tpl->get());
2760//
2761 // $this->tpl->setCurrentBlock('nav_while_edit_modal');
2762 // $this->tpl->setVariable('NAV_WHILE_EDIT_MODAL', $modal->getHTML());
2763 // $this->tpl->parseCurrentBlock();
2764//
2765 // $this->tpl->addJavaScript('Modules/Test/js/ilTestPlayerNavWhileEditModal.js', true);
2766 // }
2767 // fau.
2768
2769 // fau: testNav - new function populateNavWhenChangedModal
2770 protected function populateNavWhenChangedModal()
2771 {
2772 return; // usibility fix: get rid of popup
2773
2774 if (!empty($_SESSION['save_on_navigation_prevent_confirmation'])) {
2775 return;
2776 }
2777
2778 $tpl = new ilTemplate('tpl.tst_player_confirmation_modal.html', true, true, 'Modules/Test');
2779
2780 if ($this->object->isInstantFeedbackAnswerFixationEnabled() && $this->object->isForceInstantFeedbackEnabled()) {
2781 $text = $this->lng->txt('save_on_navigation_locked_confirmation');
2782 } else {
2783 $text = $this->lng->txt('save_on_navigation_confirmation');
2784 }
2785 if ($this->object->isForceInstantFeedbackEnabled()) {
2786 $text .= " " . $this->lng->txt('save_on_navigation_forced_feedback_hint');
2787 }
2788 $tpl->setVariable('CONFIRMATION_TEXT', $text);
2789
2790
2791 $button = ilLinkButton::getInstance();
2792 $button->setId('tst_save_on_navigation_button');
2793 $button->setUrl('#');
2794 $button->setCaption('tst_save_and_proceed');
2795 $button->setPrimary(true);
2796 $tpl->setCurrentBlock('buttons');
2797 $tpl->setVariable('BUTTON', $button->render());
2798 $tpl->parseCurrentBlock();
2799
2800 $button = ilLinkButton::getInstance();
2801 $button->setId('tst_cancel_on_navigation_button');
2802 $button->setUrl('#');
2803 $button->setCaption('cancel');
2804 $button->setPrimary(false);
2805 $tpl->setCurrentBlock('buttons');
2806 $tpl->setVariable('BUTTON', $button->render());
2807 $tpl->parseCurrentBlock();
2808
2809 $tpl->setCurrentBlock('checkbox');
2810 $tpl->setVariable('CONFIRMATION_CHECKBOX_NAME', 'save_on_navigation_prevent_confirmation');
2811 $tpl->setVariable('CONFIRMATION_CHECKBOX_LABEL', $this->lng->txt('tst_dont_show_msg_again_in_current_session'));
2812 $tpl->parseCurrentBlock();
2813
2814 $modal = ilModalGUI::getInstance();
2815 $modal->setId('tst_save_on_navigation_modal');
2816 $modal->setHeading($this->lng->txt('save_on_navigation'));
2817 $modal->setBody($tpl->get());
2818
2819 $this->tpl->setCurrentBlock('nav_while_edit_modal');
2820 $this->tpl->setVariable('NAV_WHILE_EDIT_MODAL', $modal->getHTML());
2821 $this->tpl->parseCurrentBlock();
2822 }
2823 // fau.
2824
2826 {
2827 require_once 'Modules/Test/classes/class.ilTestPlayerConfirmationModal.php';
2828 $modal = new ilTestPlayerConfirmationModal();
2829 $modal->setModalId('tst_next_locks_unchanged_modal');
2830
2831 $modal->setHeaderText($this->lng->txt('tst_nav_next_locks_empty_answer_header'));
2832 $modal->setConfirmationText($this->lng->txt('tst_nav_next_locks_empty_answer_confirm'));
2833
2834 $button = $modal->buildModalButtonInstance('tst_nav_next_empty_answer_button');
2835 $button->setCaption('tst_proceed');
2836 $button->setPrimary(false);
2837 $modal->addButton($button);
2838
2839 $button = $modal->buildModalButtonInstance('tst_cancel_next_empty_answer_button');
2840 $button->setCaption('cancel');
2841 $button->setPrimary(true);
2842 $modal->addButton($button);
2843
2844 $this->tpl->setCurrentBlock('next_locks_unchanged_modal');
2845 $this->tpl->setVariable('NEXT_LOCKS_UNCHANGED_MODAL', $modal->getHTML());
2846 $this->tpl->parseCurrentBlock();
2847 }
2848
2850 {
2852 return;
2853 }
2854
2855 require_once 'Modules/Test/classes/class.ilTestPlayerConfirmationModal.php';
2856 $modal = new ilTestPlayerConfirmationModal();
2857 $modal->setModalId('tst_next_locks_changed_modal');
2858
2859 $modal->setHeaderText($this->lng->txt('tst_nav_next_locks_current_answer_header'));
2860 $modal->setConfirmationText($this->lng->txt('tst_nav_next_locks_current_answer_confirm'));
2861
2862 $modal->setConfirmationCheckboxName(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM);
2863 $modal->setConfirmationCheckboxLabel($this->lng->txt('tst_dont_show_msg_again_in_current_session'));
2864
2865 $button = $modal->buildModalButtonInstance('tst_nav_next_changed_answer_button');
2866 $button->setCaption('tst_save_and_proceed');
2867 $button->setPrimary(true);
2868 $modal->addButton($button);
2869
2870 $button = $modal->buildModalButtonInstance('tst_cancel_next_changed_answer_button');
2871 $button->setCaption('cancel');
2872 $button->setPrimary(false);
2873 $modal->addButton($button);
2874
2875 $this->tpl->setCurrentBlock('next_locks_changed_modal');
2876 $this->tpl->setVariable('NEXT_LOCKS_CHANGED_MODAL', $modal->getHTML());
2877 $this->tpl->parseCurrentBlock();
2878 }
2879
2880 const FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM = 'followup_qst_locks_prevent_confirmation';
2881
2883 {
2885 }
2886
2888 {
2889 if (!isset($_SESSION[self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM])) {
2890 return false;
2891 }
2892
2894 }
2895
2896 // fau: testNav - new function populateQuestionEditControl
2902 protected function populateQuestionEditControl($questionGUI)
2903 {
2904 // configuration for ilTestPlayerQuestionEditControl.js
2905 $config = array();
2906
2907 // set the initial state of the question
2908 $state = $questionGUI->object->lookupForExistingSolutions($this->testSession->getActiveId(), $this->testSession->getPass());
2909 $config['isAnswered'] = $state['authorized'];
2910 $config['isAnswerChanged'] = $state['intermediate'] || $this->getAnswerChangedParameter();
2911
2912 // set url to which the for should be submitted when the working time is over
2913 // don't use asynch url because the form is submitted directly
2914 // but use simple '&' because url is copied by javascript into the form action
2915 $config['saveOnTimeReachedUrl'] = str_replace('&amp;', '&', $this->ctrl->getFormAction($this, ilTestPlayerCommands::AUTO_SAVE_ON_TIME_LIMIT));
2916
2917 // enable the auto saving function
2918 // the autosave url is asynch because it will be used by an ajax request
2919 if ($questionGUI->isAutosaveable() && $this->object->getAutosave()) {
2920 $config['autosaveUrl'] = $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::AUTO_SAVE, '', true);
2921 $config['autosaveInterval'] = $this->object->getAutosaveIval();
2922 } else {
2923 $config['autosaveUrl'] = '';
2924 $config['autosaveInterval'] = 0;
2925 }
2926
2928 // hey: prevPassSolutions - refactored method identifiers
2929 $questionConfig = $questionGUI->object->getTestPresentationConfig();
2930 // hey.
2931
2932 // Normal questions: changes are done in form fields an can be detected there
2933 $config['withFormChangeDetection'] = $questionConfig->isFormChangeDetectionEnabled();
2934
2935 // Flash and Java questions: changes are directly sent to ilias and have to be polled from there
2936 $config['withBackgroundChangeDetection'] = $questionConfig->isBackgroundChangeDetectionEnabled();
2937 $config['backgroundDetectorUrl'] = $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::DETECT_CHANGES, '', true);
2938
2939 // Forced feedback will change the navigation saving command
2940 $config['forcedInstantFeedback'] = $this->object->isForceInstantFeedbackEnabled();
2941 $config['nextQuestionLocks'] = $this->object->isFollowupQuestionAnswerFixationEnabled();
2942
2943 $this->tpl->addJavascript('./Modules/Test/js/ilTestPlayerQuestionEditControl.js');
2944 $this->tpl->addOnLoadCode('il.TestPlayerQuestionEditControl.init(' . json_encode($config) . ')');
2945 }
2946 // fau.
2947
2948 protected function getQuestionsDefaultPresentationMode($isQuestionWorkedThrough)
2949 {
2950 // fau: testNav - always set default presentation mode to "edit"
2952 // fau.
2953 }
2954
2955 protected function registerForcedFeedbackNavUrl($forcedFeedbackNavUrl)
2956 {
2957 if (!isset($_SESSION['forced_feedback_navigation_url'])) {
2958 $_SESSION['forced_feedback_navigation_url'] = array();
2959 }
2960
2961 $_SESSION['forced_feedback_navigation_url'][$this->testSession->getActiveId()] = $forcedFeedbackNavUrl;
2962 }
2963
2965 {
2966 if (!isset($_SESSION['forced_feedback_navigation_url'])) {
2967 return null;
2968 }
2969
2970 if (!isset($_SESSION['forced_feedback_navigation_url'][$this->testSession->getActiveId()])) {
2971 return null;
2972 }
2973
2974 return $_SESSION['forced_feedback_navigation_url'][$this->testSession->getActiveId()];
2975 }
2976
2978 {
2979 return !empty($this->getRegisteredForcedFeedbackNavUrl());
2980 }
2981
2983 {
2984 if (isset($_SESSION['forced_feedback_navigation_url'][$this->testSession->getActiveId()])) {
2985 unset($_SESSION['forced_feedback_navigation_url'][$this->testSession->getActiveId()]);
2986 }
2987 }
2988
2989 protected function handleFileUploadCmd()
2990 {
2991 $this->updateWorkingTime();
2992 $this->saveQuestionSolution(false);
2993 $this->ctrl->redirect($this, ilTestPlayerCommands::SUBMIT_SOLUTION);
2994 }
2995}
$result
$filename
Definition: buildRTE.php:89
$_GET["client_id"]
$_POST["username"]
$_SESSION["AccountId"]
An exception for terminatinating execution or to throw for unit testing.
const IL_COMP_MODULE
const IL_CAL_FKT_GETDATE
const IL_CAL_TIMESTAMP
const IL_CAL_UNIX
Multiple choice question GUI representation.
Basic GUI class for assessment questions.
getSolutionOutput( $active_id, $pass=null, $graphicalOutput=false, $result_output=false, $show_question_only=true, $show_feedback=false, $show_correct_solution=false, $show_manual_scoring=false, $show_question_text=true)
setNavigationGUI($navigationGUI)
outQuestionForTest( $formaction, $active_id, $pass, $is_question_postponed=false, $user_post_solutions=false, $show_specific_inline_feedback=false)
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
output question page
getSpecificFeedbackOutput($userSolution)
Returns the answer specific feedback for the question.
hasInlineFeedback()
this method can be overwritten per question type
getGenericFeedbackOutput($active_id, $pass)
Returns the answer specific feedback for the question.
Abstract basic class which is to be extended by the concrete assessment question type classes.
static _instantiateQuestion($question_id)
getTestPresentationConfig()
Get the test question configuration (initialised once)
static _getCurrentGUI(ilObjTest $a_test_obj=null)
Get the GUI that is used for the currently available selector (other GUI instances may exist for conf...
Confirmation screen class.
static formatDate(ilDateTime $date, $a_skip_day=false, $a_include_wd=false, $include_seconds=false)
Format a date @access public.
@classDescription Date and time handling
static getInstance(ilTestSession $a_test_session)
static getInstance()
Factory.
static getInstance()
Get instance.
static _enabledAssessmentLogging()
check wether assessment logging is enabled or not
static getSyntaxStylePath()
get syntax style path
static getContentStylePath($a_style_id, $add_random=true, $add_token=true)
get content style path
static lookupExamId($active_id, $pass)
static _getUsePreviousAnswers($active_id, $user_active_user_setting=false)
Returns if the previous results should be hidden for a learner.
static allObligationsAnswered($test_id, $active_id, $pass)
checks wether all questions marked as obligatory were answered within the test pass with given testId...
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
static buildExamId($active_id, $pass, $test_obj_id=null)
static _getSolvedQuestions($active_id, $question_fi=null)
get solved questions
static get($a_var)
Get a value.
ILIAS Setting Class.
static getInstance()
Factory.
Class ilTaggingGUI.
special template class to simplify handling of ITX/PEAR
Class ilTestArchiver.
Output class for assessment test evaluation.
Base Exception for all Exceptions relating to Modules/Test.
static generatePDF($pdf_output, $output_mode, $filename=null, $purpose=null)
Class ilTestPassFinishTasks.
Output class for assessment test execution.
handleSkillTriggering(ilTestSession $testSession)
checkTestSessionUser(ilTestSession $testSession)
populateNextButtons($disabled, $primaryNext)
redirectAfterAutosaveCmd()
Redirect the user after an automatic save when the time limit is reached.
isShowingPostponeStatusReguired($questionId)
saveTagsCmd()
Save tags for tagging gui.
initTestQuestionConfig(assQuestion $questionOBJ)
checkWorkingTimeCmd()
This is asynchronously called by tpl.workingtime.js to check for changes in the user's processing tim...
confirmHintRequestCmd()
Go to hint request confirmation.
__construct($a_object)
ilTestOutputGUI constructor
removeIntermediateSolution()
remove an auto-saved solution of the current question
autosaveOnTimeLimitCmd()
Automatically save a user answer when the limited duration of a test run is reached (called by synchr...
setAnswerChangedParameter($changed=true)
Set the 'answer changed' url parameter for generated links.
confirmFinishCmd()
The final submission of a test was confirmed.
buildEditableStateQuestionNavigationGUI($questionId, $charSelectorAvailable)
startPlayerCmd()
Start a test for the first time.
prepareTestPage($presentationMode, $sequenceElement, $questionId)
isOptionalQuestionAnsweringConfirmationRequired($sequenceElement)
handleTearsAndAngerQuestionIsNull($questionId, $sequenceElement)
getQuestionInstance($questionId, $fromCache=true)
saveQuestionSolution($authorized=true, $force=false)
saves the user input of a question
isFirstQuestionInSequence($sequenceElement)
populateGenericFeedbackBlock(assQuestionGUI $question_gui, $solutionCorrect)
getQuestionGuiInstance($question_id, $fromCache=true)
unmarkQuestionCmd()
Set a question unsolved.
showSideList($presentationMode, $currentSequenceElement)
populateUpperNextButtonBlock($disabled, $primaryNext)
initTestCmd()
Start a test for the first time after a redirect.
populateInstantResponseModal(assQuestionGUI $questionGui, $navUrl)
endingTimeReached()
handle endingTimeReached
outQuestionSummaryCmd($fullpage=true, $contextFinishTest=false, $obligationsInfo=false, $obligationsFilter=false)
Output of a summary of all test questions for test participants.
maxProcessingTimeReached()
Outputs a message when the maximum processing time is reached.
showQuestionEditable(assQuestionGUI $questionGui, $formAction, $isQuestionWorkedThrough, $instantResponse)
resumePlayerCmd()
Resume a test at the last position.
handleIntermediateSubmit()
Check the 'answer changed' parameter when a question form is intermediately submitted.
confirmSubmitAnswers()
confirm submit results if confirm then results are submitted and the screen will be redirected to the...
autosaveCmd()
Automatically save a user answer while working on the test (called repeatedly by asynchronous posts i...
ensureExistingTestSession(ilTestSession $testSession)
populateScoreBlock($reachedPoints, $maxPoints)
updateWorkingTime()
updates working time and stores state saveresult to see if question has to be stored or not
handleUserSettings()
Handles some form parameters on starting and resuming a test.
populateInstantResponseBlocks(assQuestionGUI $questionGui, $authorizedSolution)
getQuestionsDefaultPresentationMode($isQuestionWorkedThrough)
outCorrectSolution()
Creates an output of the solution of an answer compared to the correct solution.
detectChangesCmd()
Detect changes sent in the background to the server This is called by ajax from ilTestPlayerQuestionE...
populateLowerNextButtonBlock($disabled, $primaryNext)
finishTestCmd($requires_confirmation=true)
markQuestionCmd()
Set a question solved.
populateTestNavigationToolbar(ilTestNavigationToolbarGUI $toolbarGUI)
isTestSignRedirectRequired($activeId, $lastFinishedPass)
getAnswerChangedParameter()
Get the 'answer changed' status from the current request It may be set by ilTestPlayerNavigationContr...
determineSolutionPassIndex(assQuestionGUI $questionGui)
populateSpecificFeedbackBlock(assQuestionGUI $question_gui)
showRequestedHintListCmd()
Go to requested hint list.
isMaxProcessingTimeReached()
Checks wheather the maximum processing time is reached or not.
setAnonymousIdCmd()
Sets a session variable with the test access code for an anonymous test user.
saveNavigationPreventConfirmation()
Save the save the switch to prevent the navigation confirmation.
registerForcedFeedbackNavUrl($forcedFeedbackNavUrl)
isLastQuestionInSequence($sequenceElement)
checkOnlineTestAccess()
check access restrictions like client ip, partipating user etc.
populateQuestionNavigation($sequenceElement, $disabled, $primaryNext)
buildNextButtonInstance($disabled, $primaryNext)
isTestAccessible()
test accessible returns true if the user can perform the test
showQuestionViewable(assQuestionGUI $questionGui, $formAction, $isQuestionWorkedThrough, $instantResponse)
getContentBlockName()
Returns the name of the current content block (depends on the kiosk mode setting)
showListOfAnswers($active_id, $pass=null, $top_data="", $bottom_data="")
Creates an output of the list of answers for a test participant during the test (only the actual pass...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getCorrectSolutionOutput($question_id, $active_id, $pass, ilTestQuestionRelatedObjectivesList $objectivesList=null)
Returns an output of the solution to an answer compared to the correct solution.
getResultsSignature()
Returns HTML code for a signature field.
buildQuestionRelatedObjectivesList(ilLOTestQuestionAdapter $objectivesAdapter, ilTestQuestionSequence $testSequence)
getAdditionalUsrDataHtmlAndPopulateWindowTitle($testSession, $active_id, $overwrite_anonymity=false)
Returns the user data for a test results output.
buildQuestionAnswerShuffler(string $question_id, string $active_id, string $active_pass)
Test session handler.
static getWebspaceDir($mode="filesystem")
get webspace directory
static getStyleSheetLocation($mode="output", $a_css_name="", $a_css_location="")
get full style sheet file name (path inclusive) of current user
static redirect($a_script)
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
static _getHttpPath()
static makeDirParents($a_dir)
Create a new directory and all parent directories.
static sendInfo($a_info="", $a_keep=false)
Send Info Message to Screen.
static initjQuery(ilGlobalTemplateInterface $a_tpl=null)
inits and adds the jQuery JS-File to the global or a passed template
global $DIC
Definition: goto.php:24
$ilUser
Definition: imgupload.php:18
const OUTPUT_JAVASCRIPT
const REDIRECT_KIOSK
exit
Definition: login.php:29
if(!array_key_exists('PATH_INFO', $_SERVER)) $config
Definition: metadata.php:68
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
redirection script todo: (a better solution should control the processing via a xml file)
global $ilSetting
Definition: privfeed.php:17
$url
$_SERVER['HTTP_HOST']
Definition: raiseError.php:10
$results
foreach($_POST as $key=> $value) $res
global $ilDB