ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
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
31
38
43
47 protected $processLocker;
48
52 protected $testSession;
53
57 protected $assSettings;
58
62 protected $testSequence = null;
63
69 public function __construct($a_object)
70 {
71 parent::__construct($a_object);
72 $this->ref_id = $_GET["ref_id"];
73
74 global $rbacsystem, $ilUser, $lng;
75 require_once 'Modules/Test/classes/class.ilTestPasswordChecker.php';
76 $this->passwordChecker = new ilTestPasswordChecker($rbacsystem, $ilUser, $this->object, $lng);
77
78 $this->processLocker = null;
79 $this->testSession = null;
80 $this->assSettings = null;
81 }
82
83 protected function checkReadAccess()
84 {
85 global $rbacsystem;
86
87 if(!$rbacsystem->checkAccess("read", $this->object->getRefId()))
88 {
89 // only with read access it is possible to run the test
90 $this->ilias->raiseError($this->lng->txt("cannot_execute_test"), $this->ilias->error_obj->MESSAGE);
91 }
92 }
93
94 protected function checkTestExecutable()
95 {
96 $executable = $this->object->isExecutable($this->testSession, $this->testSession->getUserId());
97
98 if( !$executable['executable'] )
99 {
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 {
111 throw new ilTestException('active id given does not relate to current user!');
112 }
113 }
114
116 {
117 if( $testSession->getActiveId() )
118 {
119 return;
120 }
121
122 global $ilUser;
123
124 $testSession->setUserId($ilUser->getId());
125
126 if( $testSession->isAnonymousUser() )
127 {
128 if( !$testSession->doesAccessCodeInSessionExists() )
129 {
130 return;
131 }
132
133 $testSession->setAnonymousId($testSession->getAccessCodeFromSession());
134 }
135
136 $testSession->saveToDb();
137 }
138
139 protected function initProcessLocker($activeId)
140 {
141 global $ilDB;
142
143 require_once 'Modules/Test/classes/class.ilTestProcessLockerFactory.php';
144 $processLockerFactory = new ilTestProcessLockerFactory($this->assSettings, $ilDB);
145
146 $processLockerFactory->setActiveId($activeId);
147
148 $this->processLocker = $processLockerFactory->getLocker();
149 }
150
157 function saveTagsCmd()
158 {
159 include_once("./Services/Tagging/classes/class.ilTaggingGUI.php");
160 $tagging_gui = new ilTaggingGUI();
161 $tagging_gui->setObject($this->object->getId(), $this->object->getType());
162 $tagging_gui->saveInput();
163 $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
164 }
165
170 {
171 if ($_SESSION["active_time_id"])
172 {
173 $this->object->updateWorkingTime($_SESSION["active_time_id"]);
174 }
175
176 $_SESSION["active_time_id"] = $this->object->startWorkingTime(
177 $this->testSession->getActiveId(), $this->testSession->getPass()
178 );
179 }
180
181// fau: testNav - new function removeIntermediateSolution()
187 {
188 $questionId = $this->getCurrentQuestionId();
189
190 $this->getQuestionInstance($questionId)->removeIntermediateSolution(
191 $this->testSession->getActiveId(), $this->testSession->getPass()
192 );
193 }
194// fau.
195
199 abstract public function saveQuestionSolution($authorized = true, $force = false);
200
201 abstract protected function canSaveResult();
202
203 public function suspendTestCmd()
204 {
205 $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
206 }
207
215 public function isMaxProcessingTimeReached()
216 {
217 global $ilUser;
218 $active_id = $this->testSession->getActiveId();
219 $starting_time = $this->object->getStartingTimeOfUser($active_id);
220 if ($starting_time === FALSE)
221 {
222 return FALSE;
223 }
224 else
225 {
226 return $this->object->isMaxProcessingTimeReached($starting_time, $active_id);
227 }
228 }
229
230 protected function determineInlineScoreDisplay()
231 {
232 $show_question_inline_score = FALSE;
233 if ($this->object->getAnswerFeedbackPoints())
234 {
235 $show_question_inline_score = TRUE;
236 return $show_question_inline_score;
237 }
238 return $show_question_inline_score;
239 }
240
242 {
243 $this->tpl->setCurrentBlock('test_nav_toolbar');
244 $this->tpl->setVariable('TEST_NAV_TOOLBAR', $toolbarGUI->getHTML());
245 $this->tpl->parseCurrentBlock();
246 }
247
248 protected function populateQuestionNavigation($sequenceElement, $disabled, $primaryNext)
249 {
250 if( !$this->isFirstQuestionInSequence($sequenceElement) )
251 {
252 $this->populatePreviousButtons($disabled);
253 }
254
255 if( !$this->isLastQuestionInSequence($sequenceElement) )
256 {
257 $this->populateNextButtons($disabled, $primaryNext);
258 }
259 }
260
261 protected function populatePreviousButtons($disabled)
262 {
263 $this->populateUpperPreviousButtonBlock($disabled);
264 $this->populateLowerPreviousButtonBlock($disabled);
265 }
266
267 protected function populateNextButtons($disabled, $primaryNext)
268 {
269 $this->populateUpperNextButtonBlock($disabled, $primaryNext);
270 $this->populateLowerNextButtonBlock($disabled, $primaryNext);
271 }
272
273 protected function populateLowerNextButtonBlock($disabled, $primaryNext)
274 {
275 $button = $this->buildNextButtonInstance($disabled, $primaryNext);
276 $button->setId('bottomnextbutton');
277
278 $this->tpl->setCurrentBlock( "next_bottom" );
279 $this->tpl->setVariable( "BTN_NEXT", $button->render());
280 $this->tpl->parseCurrentBlock();
281 }
282
283 protected function populateUpperNextButtonBlock($disabled, $primaryNext)
284 {
285 $button = $this->buildNextButtonInstance($disabled, $primaryNext);
286 $button->setId('nextbutton');
287
288 $this->tpl->setCurrentBlock( "next" );
289 $this->tpl->setVariable( "BTN_NEXT", $button->render());
290 $this->tpl->parseCurrentBlock();
291 }
292
293 protected function populateLowerPreviousButtonBlock($disabled)
294 {
295 $button = $this->buildPreviousButtonInstance($disabled);
296 $button->setId('bottomprevbutton');
297
298 $this->tpl->setCurrentBlock( "prev_bottom" );
299 $this->tpl->setVariable("BTN_PREV", $button->render());
300 $this->tpl->parseCurrentBlock();
301 }
302
303 protected function populateUpperPreviousButtonBlock($disabled)
304 {
305 $button = $this->buildPreviousButtonInstance($disabled);
306 $button->setId('prevbutton');
307
308 $this->tpl->setCurrentBlock( "prev" );
309 $this->tpl->setVariable("BTN_PREV", $button->render());
310 $this->tpl->parseCurrentBlock();
311 }
312
318 private function buildNextButtonInstance($disabled, $primaryNext)
319 {
321// fau: testNav - set glyphicon and primary
322 $button->setPrimary($primaryNext);
323 $button->setRightGlyph('glyphicon glyphicon-arrow-right');
324// fau.
325 $button->setNextCommand(ilTestPlayerCommands::NEXT_QUESTION);
326 $button->setUrl($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::NEXT_QUESTION));
327 $button->setCaption('next_question');
328 $button->addCSSClass('ilTstNavElem');
329 //$button->setDisabled($disabled);
330 return $button;
331 }
332
337 private function buildPreviousButtonInstance($disabled)
338 {
340// fau: testNav - set glyphicon and primary
341 $button->setLeftGlyph('glyphicon glyphicon-arrow-left');
342// fau.
343 $button->setNextCommand(ilTestPlayerCommands::PREVIOUS_QUESTION);
344 $button->setUrl($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::PREVIOUS_QUESTION));
345 $button->setCaption('previous_question');
346 $button->addCSSClass('ilTstNavElem');
347 //$button->setDisabled($disabled);
348 return $button;
349 }
350
351 protected function populateSpecificFeedbackBlock($question_gui)
352 {
353 $this->tpl->setCurrentBlock( "specific_feedback" );
354 $this->tpl->setVariable( "SPECIFIC_FEEDBACK",
355 $question_gui->getSpecificFeedbackOutput(
356 $this->testSession->getActiveId(),
357 NULL
358 )
359 );
360 $this->tpl->parseCurrentBlock();
361 }
362
363 protected function populateGenericFeedbackBlock(assQuestionGUI $question_gui, $solutionCorrect)
364 {
365 $feedback = $question_gui->getGenericFeedbackOutput( $this->testSession->getActiveId(),NULL);
366
367 if( strlen($feedback) )
368 {
369 $cssClass = ( $solutionCorrect ?
371 );
372
373 $this->tpl->setCurrentBlock( "answer_feedback" );
374 $this->tpl->setVariable( "ANSWER_FEEDBACK", $feedback);
375 $this->tpl->setVariable( "ILC_FB_CSS_CLASS", $cssClass);
376 $this->tpl->parseCurrentBlock();
377 }
378 }
379
380 protected function populateScoreBlock($reachedPoints, $maxPoints)
381 {
382 $scoreInformation = sprintf(
383 $this->lng->txt( "you_received_a_of_b_points" ), $reachedPoints, $maxPoints
384 );
385
386 $this->tpl->setCurrentBlock( "received_points_information" );
387 $this->tpl->setVariable("RECEIVED_POINTS_INFORMATION", $scoreInformation);
388 $this->tpl->parseCurrentBlock();
389 }
390
391 protected function populateSolutionBlock($solutionoutput)
392 {
393 if( strlen($solutionoutput) )
394 {
395 $this->tpl->setCurrentBlock( "solution_output" );
396 $this->tpl->setVariable( "CORRECT_SOLUTION", $this->lng->txt( "tst_best_solution_is" ) );
397 $this->tpl->setVariable( "QUESTION_FEEDBACK", $solutionoutput );
398 $this->tpl->parseCurrentBlock();
399 }
400 }
401
402 protected function populateSyntaxStyleBlock()
403 {
404 $this->tpl->setCurrentBlock( "SyntaxStyle" );
405 $this->tpl->setVariable( "LOCATION_SYNTAX_STYLESHEET",
407 );
408 $this->tpl->parseCurrentBlock();
409 }
410
411 protected function populateContentStyleBlock()
412 {
413 include_once("./Services/Style/Content/classes/class.ilObjStyleSheet.php");
414 $this->tpl->setCurrentBlock( "ContentStyle" );
415 $this->tpl->setVariable( "LOCATION_CONTENT_STYLESHEET",
417 );
418 $this->tpl->parseCurrentBlock();
419 }
420
426 public function setAnonymousIdCmd()
427 {
428 if( $this->testSession->isAnonymousUser() )
429 {
430 $this->testSession->setAccessCodeToSession($_POST['anonymous_id']);
431 }
432
433 $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
434 }
435
442 protected function startPlayerCmd()
443 {
444 $testStartLock = $this->getLockParameter();
445 $isFirstTestStartRequest = false;
446
447 $this->processLocker->executeTestStartLockOperation(function() use ($testStartLock, &$isFirstTestStartRequest) {
448
449 if($this->testSession->lookupTestStartLock() != $testStartLock)
450 {
451 $this->testSession->persistTestStartLock($testStartLock);
452 $isFirstTestStartRequest = true;
453 }
454
455 });
456
457 if( $isFirstTestStartRequest )
458 {
459 $this->handleUserSettings();
460 $this->ctrl->redirect($this, ilTestPlayerCommands::INIT_TEST);
461 }
462
463 $this->ctrl->setParameterByClass('ilObjTestGUI', 'lock', $testStartLock);
464 $this->ctrl->redirectByClass("ilobjtestgui", "redirectToInfoScreen");
465 }
466
467 public function getLockParameter()
468 {
469 if( isset($_POST['lock']) && strlen($_POST['lock']) )
470 {
471 return $_POST['lock'];
472 }
473 elseif( isset($_GET['lock']) && strlen($_GET['lock']) )
474 {
475 return $_GET['lock'];
476 }
477
478 return null;
479 }
480
484 abstract protected function resumePlayerCmd();
485
489 protected function initTestCmd()
490 {
491 if ($this->object->checkMaximumAllowedUsers() == FALSE)
492 {
494 }
495
496 if( $this->testSession->isAnonymousUser() && !$this->testSession->getActiveId() )
497 {
498 $accessCode = $this->testSession->createNewAccessCode();
499
500 $this->testSession->setAccessCodeToSession($accessCode);
501 $this->testSession->setAnonymousId($accessCode);
502 $this->testSession->saveToDb();
503
504 $this->ctrl->redirect($this, ilTestPlayerCommands::DISPLAY_ACCESS_CODE);
505 }
506
507 $this->testSession->unsetAccessCodeInSession();
508 $this->ctrl->redirect($this, ilTestPlayerCommands::START_TEST);
509 }
510
512 {
513 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_anonymous_code_presentation.html", "Modules/Test");
514 $this->tpl->setCurrentBlock("adm_content");
515 $this->tpl->setVariable("TEXT_ANONYMOUS_CODE_CREATED", $this->lng->txt("tst_access_code_created"));
516 $this->tpl->setVariable("TEXT_ANONYMOUS_CODE", $this->testSession->getAccessCodeFromSession());
517 $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
518 $this->tpl->setVariable("CMD_CONFIRM", ilTestPlayerCommands::ACCESS_CODE_CONFIRMED);
519 $this->tpl->setVariable("TXT_CONFIRM", $this->lng->txt("continue_work"));
520 $this->tpl->parseCurrentBlock();
521 }
522
524 {
525 $this->ctrl->redirect($this, ilTestPlayerCommands::START_TEST);
526 }
527
531 public function handleUserSettings()
532 {
533 global $ilUser;
534
535 if ($_POST["chb_javascript"])
536 {
537 $ilUser->writePref("tst_javascript", 1);
538 }
539 else
540 {
541 $ilUser->writePref("tst_javascript", 0);
542 }
543
544 // hide previous results
545 if ($this->object->getNrOfTries() != 1)
546 {
547 if ($this->object->getUsePreviousAnswers() == 1)
548 {
549 if ($_POST["chb_use_previous_answers"])
550 {
551 $ilUser->writePref("tst_use_previous_answers", 1);
552 }
553 else
554 {
555 $ilUser->writePref("tst_use_previous_answers", 0);
556 }
557 }
558 }
559 }
560
562 {
563 $active_id = $this->testSession->getActiveId();
564 $actualpass = ilObjTest::_getPass($active_id);
565
566 $this->performTestPassFinishedTasks($actualpass);
567
568 $this->testSession->setLastFinishedPass($this->testSession->getPass());
569 $this->testSession->increaseTestPass();
570
571 $url = $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::AFTER_TEST_PASS_FINISHED);
572
573 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_redirect_autosave.html", "Modules/Test");
574 $this->tpl->setVariable("TEXT_REDIRECT", $this->lng->txt("redirectAfterSave"));
575 $this->tpl->setCurrentBlock("HeadContent");
576 $this->tpl->setVariable("CONTENT_BLOCK", "<meta http-equiv=\"refresh\" content=\"5; url=" . $url . "\">");
577 $this->tpl->parseCurrentBlock();
578 }
579
580 abstract protected function getCurrentQuestionId();
581
582 function autosaveCmd()
583 {
584 $canSaveResult = $this->canSaveResult();
585 $authorizedSolution = !$canSaveResult;
586
587 $result = "";
588 if (is_array($_POST) && count($_POST) > 0)
589 {
591 {
592 $result = '-IGNORE-';
593 }
594 else
595 {
596// fau: testNav - delete intermediate solution if answer is unchanged
597 // answer is changed, so save the change as intermediate solution
598 if ($this->getAnswerChangedParameter())
599 {
600 $res = $this->saveQuestionSolution($authorizedSolution, true);
601 }
602 // answer is not changed, so delete an intermediate solution
603 else
604 {
605 $db_res = $this->removeIntermediateSolution();
606 $res = is_int($db_res);
607 }
608// fau.
609 if ($res)
610 {
611 $result = $this->lng->txt("autosave_success");
612 }
613 else
614 {
615 $result = $this->lng->txt("autosave_failed");
616 }
617 }
618 }
619// fau: testNav - simplify the redirection if time is reached
620 if (!$canSaveResult && !$this->ctrl->isAsynch())
621 {
622 // this was the last action in the test, saving is no longer allowed
623 // form was directly submitted in saveOnTimeReached()
624 // instead of ajax with autoSave()
625 $this->ctrl->redirect($this, ilTestPlayerCommands::REDIRECT_ON_TIME_LIMIT);
626 }
627// fau.
628 echo $result;
629 exit;
630 }
631
632// fau: testNav - new function detectChangesCmd()
638 protected function detectChangesCmd()
639 {
640 $questionId = $this->getCurrentQuestionId();
641 $state = $this->getQuestionInstance($questionId)->lookupForExistingSolutions(
642 $this->testSession->getActiveId(),
643 $this->testSession->getPass()
644 );
645 $result = array();
646 $result['isAnswered'] = $state['authorized'];
647 $result['isAnswerChanged'] = $state['intermediate'];
648
649 echo json_encode($result);
650 exit;
651 }
652// fau.
653
654 protected function submitIntermediateSolutionCmd()
655 {
656 $this->saveQuestionSolution(false, true);
657// fau: testNav - set the 'answer changed' parameter when an intermediate solution is submitted
658 $this->setAnswerChangedParameter(true);
659// fau.
660 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
661 }
662
666 public function toggleSideListCmd()
667 {
668 global $ilUser;
669
670 $show_side_list = $ilUser->getPref('side_list_of_questions');
671 $ilUser->writePref('side_list_of_questions', !$show_side_list);
672 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
673 }
674
676 {
677// fau: testNav - handle intermediate submit when marking the question
679// fau.
680 $this->markQuestionCmd();
681 }
682
686 protected function markQuestionCmd()
687 {
688 $questionId = $this->testSequence->getQuestionForSequence(
690 );
691
692 $this->object->setQuestionSetSolved(1, $questionId, $this->testSession->getUserId());
693
694 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
695 }
696
698 {
699// fau: testNav - handle intermediate submit when unmarking the question
701// fau.
702 $this->unmarkQuestionCmd();
703 }
704
708 protected function unmarkQuestionCmd()
709 {
710 $questionId = $this->testSequence->getQuestionForSequence(
712 );
713
714 $this->object->setQuestionSetSolved(0, $questionId, $this->testSession->getUserId());
715
716 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
717 }
718
722 protected function confirmFinishCmd()
723 {
724 $this->finishTestCmd(false);
725 }
726
730 protected function confirmFinishTestCmd()
731 {
735 global $ilUser;
736
737 require_once 'Services/Utilities/classes/class.ilConfirmationGUI.php';
738 $confirmation = new ilConfirmationGUI();
739 $confirmation->setFormAction($this->ctrl->getFormAction($this, 'confirmFinish'));
740 $confirmation->setHeaderText($this->lng->txt("tst_finish_confirmation_question"));
741 $confirmation->setConfirm($this->lng->txt("tst_finish_confirm_button"), 'confirmFinish');
742 $confirmation->setCancel($this->lng->txt("tst_finish_confirm_cancel_button"), ilTestPlayerCommands::BACK_FROM_FINISHING);
743
744 $this->populateHelperGuiContent($confirmation);
745 }
746
747 function finishTestCmd($requires_confirmation = true)
748 {
749 global $ilAuth;
750
751 unset($_SESSION["tst_next"]);
752
753 $active_id = $this->testSession->getActiveId();
754 $actualpass = ilObjTest::_getPass($active_id);
755
756 $allObligationsAnswered = ilObjTest::allObligationsAnswered($this->testSession->getTestId(), $active_id, $actualpass);
757
758 /*
759 * The following "endgames" are possible prior to actually finishing the test:
760 * - Obligations (Ability to finish the test.)
761 * If not all obligatory questions are answered, the user is presented a list
762 * showing the deficits.
763 * - Examview (Will to finish the test.)
764 * With the examview, the participant can review all answers given in ILIAS or a PDF prior to
765 * commencing to the finished test.
766 * - Last pass allowed (Reassuring the will to finish the test.)
767 * If passes are limited, on the last pass, an additional confirmation is to be displayed.
768 */
769
770
771 if( $this->object->areObligationsEnabled() && !$allObligationsAnswered )
772 {
773 if( $this->object->getListOfQuestions() )
774 {
775 $this->ctrl->redirect($this, ilTestPlayerCommands::QUESTION_SUMMARY_INC_OBLIGATIONS);
776 }
777 else
778 {
780 }
781
782 return;
783 }
784
785 // Examview enabled & !reviewed & requires_confirmation? test_submission_overview (review gui)
786 if ($this->object->getEnableExamview() && !isset($_GET['reviewed']) && $requires_confirmation)
787 {
788 $this->ctrl->redirectByClass('ilTestSubmissionReviewGUI', "show");
789 return;
790 }
791
792 // Last try in limited tries & !confirmed
793 if (($requires_confirmation) && ($actualpass == $this->object->getNrOfTries() - 1))
794 {
795 // show confirmation page
796 return $this->confirmFinishTestCmd();
797 }
798
799 // Last try in limited tries & confirmed?
800 if(($actualpass == $this->object->getNrOfTries() - 1) && (!$requires_confirmation))
801 {
802 // @todo: php7 ask mister test
803 #$ilAuth->setIdle(ilSession::getIdleValue(), false);
804 #$ilAuth->setExpire(0);
805 switch($this->object->getMailNotification())
806 {
807 case 1:
808 $this->object->sendSimpleNotification($active_id);
809 break;
810 case 2:
811 $this->object->sendAdvancedNotification($active_id);
812 break;
813 }
814 }
815
816 // Non-last try finish
817 if(!$_SESSION['tst_pass_finish'])
818 {
819 if(!$_SESSION['tst_pass_finish']) $_SESSION['tst_pass_finish'] = 1;
820 if($this->object->getMailNotificationType() == 1)
821 {
822 switch($this->object->getMailNotification())
823 {
824 case 1:
825 $this->object->sendSimpleNotification($active_id);
826 break;
827 case 2:
828 $this->object->sendAdvancedNotification($active_id);
829 break;
830 }
831 }
832 }
833
834 // no redirect request loops after test pass finished tasks has been performed
835
836 $this->performTestPassFinishedTasks($actualpass);
837
838 $this->ctrl->redirect($this, ilTestPlayerCommands::AFTER_TEST_PASS_FINISHED);
839 }
840
841 protected function performTestPassFinishedTasks($finishedPass)
842 {
843 require_once 'Modules/Test/classes/class.ilTestPassFinishTasks.php';
844
845 $finishTasks = new ilTestPassFinishTasks($this->testSession->getActiveId(), $this->object->getId());
846 $finishTasks->performFinishTasks($this->processLocker);
847 }
848
849 protected function afterTestPassFinishedCmd()
850 {
851 $activeId = $this->testSession->getActiveId();
852 $lastFinishedPass = $this->testSession->getLastFinishedPass();
853
854 // handle test signature
855 if ( $this->isTestSignRedirectRequired($activeId, $lastFinishedPass) )
856 {
857 $this->ctrl->redirectByClass('ilTestSignatureGUI', 'invokeSignaturePlugin');
858 }
859
860 // show final statement
861 if(!$_GET['skipfinalstatement'])
862 {
863 if ($this->object->getShowFinalStatement())
864 {
865 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_FINAL_STATMENT);
866 }
867 }
868
869 // redirect after test
870 $redirection_mode = $this->object->getRedirectionMode();
871 $redirection_url = $this->object->getRedirectionUrl();
872 if( $redirection_url && $redirection_mode && !$this->object->canViewResults() )
873 {
874 if( $redirection_mode == REDIRECT_KIOSK )
875 {
876 if( $this->object->getKioskMode() )
877 {
878 ilUtil::redirect($redirection_url);
879 }
880 }
881 else
882 {
883 ilUtil::redirect($redirection_url);
884 }
885 }
886
887 // default redirect (pass overview when enabled, otherwise infoscreen)
888 $this->redirectBackCmd();
889 }
890
891 protected function isTestSignRedirectRequired($activeId, $lastFinishedPass)
892 {
893 if( !$this->object->getSignSubmission() )
894 {
895 return false;
896 }
897
898 if( !is_null(ilSession::get("signed_{$activeId}_{$lastFinishedPass}")) )
899 {
900 return false;
901 }
902
903 global $ilPluginAdmin;
904
905 $activePlugins = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, 'Test', 'tsig');
906
907 if( !count($activePlugins) )
908 {
909 return false;
910 }
911
912 return true;
913 }
914
920 protected function archiveParticipantSubmission( $active, $pass )
921 {
922 global $ilObjDataCache;
923
924 require_once 'Modules/Test/classes/class.ilTestResultHeaderLabelBuilder.php';
925 $testResultHeaderLabelBuilder = new ilTestResultHeaderLabelBuilder($this->lng, $ilObjDataCache);
926
927 $objectivesList = null;
928
929 if( $this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired() )
930 {
931 $testSequence = $this->testSequenceFactory->getSequenceByActiveIdAndPass($this->testSession->getActiveId(), $this->testSession->getPass());
932 $testSequence->loadFromDb();
933 $testSequence->loadQuestions();
934
935 require_once 'Modules/Course/classes/Objectives/class.ilLOTestQuestionAdapter.php';
936 $objectivesAdapter = ilLOTestQuestionAdapter::getInstance($this->testSession);
937
938 $objectivesList = $this->buildQuestionRelatedObjectivesList($objectivesAdapter, $testSequence);
939 $objectivesList->loadObjectivesTitles();
940
941 $testResultHeaderLabelBuilder->setObjectiveOrientedContainerId($this->testSession->getObjectiveOrientedContainerId());
942 $testResultHeaderLabelBuilder->setUserId($this->testSession->getUserId());
943 $testResultHeaderLabelBuilder->setTestObjId($this->object->getId());
944 $testResultHeaderLabelBuilder->setTestRefId($this->object->getRefId());
945 $testResultHeaderLabelBuilder->initObjectiveOrientedMode();
946 }
947
948 $results = $this->object->getTestResult(
949 $active, $pass, false, !$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()
950 );
951
952 require_once 'class.ilTestEvaluationGUI.php';
953 $testevaluationgui = new ilTestEvaluationGUI($this->object);
954 $results_output = $testevaluationgui->getPassListOfAnswers(
955 $results, $active, $pass, false, false, false, false, false, $objectivesList, $testResultHeaderLabelBuilder
956 );
957
958 require_once './Modules/Test/classes/class.ilTestArchiver.php';
959 global $ilSetting;
960 $inst_id = $ilSetting->get('inst_id', null);
961 $archiver = new ilTestArchiver($this->object->getId());
962
963 $path = ilUtil::getWebspaceDir() . '/assessment/'. $this->object->getId() . '/exam_pdf';
964 if (!is_dir($path))
965 {
967 }
968 $filename = realpath($path) . '/exam_N' . $inst_id . '-' . $this->object->getId()
969 . '-' . $active . '-' . $pass . '.pdf';
970
971 require_once 'class.ilTestPDFGenerator.php';
973 //$template->setVariable("PDF_FILE_LOCATION", $filename);
974 // Participant submission
975 $archiver->handInParticipantSubmission( $active, $pass, $filename, $results_output );
976 //$archiver->handInParticipantMisc( $active, $pass, 'signature_gedoens.sig', $filename );
977 //$archiver->handInParticipantQuestionMaterial( $active, $pass, 123, 'file_upload.pdf', $filename );
978
979 global $ilias;
980 $questions = $this->object->getQuestions();
981 foreach ($questions as $question_id)
982 {
983 $question_object = $this->object->getQuestionDataset( $question_id );
984 if ($question_object->type_tag == 'assFileUpload')
985 {
986 // Pfad: /data/default/assessment/tst_2/14/21/files/file_14_4_1370417414.png
987 // /data/ - klar
988 // /assessment/ - Konvention
989 // /tst_2/ = /tst_<test_id> (ilObjTest)
990 // /14/ = /<active_fi>/
991 // /21/ = /<question_id>/ (question_object)
992 // /files/ - Konvention
993 // file_14_4_1370417414.png = file_<active_fi>_<pass>_<some timestamp>.<ext>
994
995 $candidate_path =
996 $ilias->ini_ilias->readVariable( 'server', 'absolute_path' ) . ilTestArchiver::DIR_SEP
997 . $ilias->ini_ilias->readVariable( 'clients', 'path' ) . ilTestArchiver::DIR_SEP
998 . $ilias->client_id . ilTestArchiver::DIR_SEP
999 . 'assessment' . ilTestArchiver::DIR_SEP
1000 . 'tst_' . $this->object->test_id . ilTestArchiver::DIR_SEP
1001 . $active . ilTestArchiver::DIR_SEP
1002 . $question_id . ilTestArchiver::DIR_SEP
1003 . 'files' . ilTestArchiver::DIR_SEP;
1004 $handle = opendir( $candidate_path );
1005 while ($handle !== false && ($file = readdir( $handle )) !== false)
1006 {
1007 if ($file != null)
1008 {
1009 $filename_start = 'file_' . $active . '_' . $pass . '_';
1010
1011 if (strpos( $file, $filename_start ) === 0)
1012 {
1013 $archiver->handInParticipantQuestionMaterial( $active, $pass, $question_id, $file, $file );
1014 }
1015 }
1016 }
1017 }
1018 }
1019 $passdata = $this->object->getTestResult(
1020 $active, $pass, false, !$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()
1021 );
1022 $overview = $testevaluationgui->getPassListOfAnswers(
1023 $passdata, $active, $pass, true, false, false, true, false, $objectivesList, $testResultHeaderLabelBuilder
1024 );
1025 $filename = realpath(ilUtil::getWebspaceDir()) . '/assessment/scores-'.$this->object->getId() . '-' . $active . '-' . $pass . '.pdf';
1027 $archiver->handInTestResult($active, $pass, $filename);
1028 unlink($filename);
1029
1030 return;
1031 }
1032
1033 public function redirectBackCmd()
1034 {
1035 require_once 'Modules/Test/classes/class.ilTestPassesSelector.php';
1036 $testPassesSelector = new ilTestPassesSelector($GLOBALS['ilDB'], $this->object);
1037 $testPassesSelector->setActiveId($this->testSession->getActiveId());
1038 $testPassesSelector->setLastFinishedPass($this->testSession->getLastFinishedPass());
1039
1040 if( count($testPassesSelector->getReportablePasses()) )
1041 {
1042 $this->ctrl->redirectByClass("ilTestEvaluationGUI", "outUserResultsOverview");
1043 }
1044
1045 $this->backToInfoScreenCmd();
1046 }
1047
1048 protected function backToInfoScreenCmd()
1049 {
1050 $this->ctrl->redirectByClass('ilObjTestGUI', 'redirectToInfoScreen');
1051 }
1052
1053 /*
1054 * Presents the final statement of a test
1055 */
1056 public function showFinalStatementCmd()
1057 {
1058 $template = new ilTemplate("tpl.il_as_tst_final_statement.html", TRUE, TRUE, "Modules/Test");
1059 $this->ctrl->setParameter($this, "skipfinalstatement", 1);
1060 $template->setVariable("FORMACTION", $this->ctrl->getFormAction($this, ilTestPlayerCommands::AFTER_TEST_PASS_FINISHED));
1061 $template->setVariable("FINALSTATEMENT", $this->object->prepareTextareaOutput($this->object->getFinalStatement(), true));
1062 $template->setVariable("BUTTON_CONTINUE", $this->lng->txt("btn_next"));
1063 $this->tpl->setVariable($this->getContentBlockName(), $template->get());
1064 }
1065
1066 public function getKioskHead()
1067 {
1068 global $ilUser;
1069
1070 $template = new ilTemplate('tpl.il_as_tst_kiosk_head.html', true, true, 'Modules/Test');
1071 if ($this->object->getShowKioskModeTitle())
1072 {
1073 $template->setCurrentBlock("kiosk_show_title");
1074 $template->setVariable("TEST_TITLE", $this->object->getTitle());
1075 $template->parseCurrentBlock();
1076 }
1077 if ($this->object->getShowKioskModeParticipant())
1078 {
1079 $template->setCurrentBlock("kiosk_show_participant");
1080 $template->setVariable("PARTICIPANT_NAME_TXT", $this->lng->txt("login_as"));
1081 $template->setVariable("PARTICIPANT_NAME", $ilUser->getFullname());
1082 $template->setVariable("PARTICIPANT_LOGIN", $ilUser->getLogin());
1083 $template->setVariable("PARTICIPANT_MATRICULATION", $ilUser->getMatriculation());
1084 $template->setVariable("PARTICIPANT_EMAIL", $ilUser->getEmail());
1085 $template->parseCurrentBlock();
1086 }
1087 if ($this->object->isShowExamIdInTestPassEnabled())
1088 {
1089 $exam_id = ilObjTest::buildExamId(
1090 $this->testSession->getActiveId() , $this->testSession->getPass(), $this->object->getId()
1091 );
1092
1093 $template->setCurrentBlock("kiosk_show_exam_id");
1094 $template->setVariable("EXAM_ID_TXT", $this->lng->txt("exam_id"));
1095 $template->setVariable( "EXAM_ID", $exam_id);
1096 $template->parseCurrentBlock();
1097 }
1098 return $template->get();
1099 }
1100
1104 protected function prepareTestPage($presentationMode, $sequenceElement, $questionId)
1105 {
1106 global $ilUser, $ilNavigationHistory;
1107
1108 $ilNavigationHistory->addItem($this->testSession->getRefId(),
1109 $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::RESUME_PLAYER), 'tst'
1110 );
1111
1112 $this->initTestPageTemplate();
1114 $this->populateSyntaxStyleBlock();
1115
1116 if ($this->isMaxProcessingTimeReached())
1117 {
1118 $this->maxProcessingTimeReached();
1119 return;
1120 }
1121
1122 if ($this->object->endingTimeReached())
1123 {
1124 $this->endingTimeReached();
1125 return;
1126 }
1127
1128 if( $this->isOptionalQuestionAnsweringConfirmationRequired($sequenceElement) )
1129 {
1130 $this->ctrl->setParameter($this, "sequence", $sequenceElement);
1132 return;
1133 }
1134
1135 if ($this->object->getKioskMode())
1136 {
1137 $this->populateKioskHead();
1138 }
1139
1140 $this->tpl->setVariable("TEST_ID", $this->object->getTestId());
1141 $this->tpl->setVariable("LOGIN", $ilUser->getLogin());
1142 $this->tpl->setVariable("SEQ_ID", $sequenceElement);
1143 $this->tpl->setVariable("QUEST_ID", $questionId);
1144
1145 if ($this->object->getEnableProcessingTime())
1146 {
1147 $this->outProcessingTime($this->testSession->getActiveId());
1148 }
1149
1150 $this->tpl->setVariable("PAGETITLE", "- " . $this->object->getTitle());
1151
1152 if ($this->object->isShowExamIdInTestPassEnabled() && !$this->object->getKioskMode())
1153 {
1154 $this->tpl->setCurrentBlock('exam_id_footer');
1155 $this->tpl->setVariable('EXAM_ID_VAL', ilObjTest::lookupExamId(
1156 $this->testSession->getActiveId(), $this->testSession->getPass(), $this->object->getId()
1157 ));
1158 $this->tpl->setVariable('EXAM_ID_TXT', $this->lng->txt('exam_id'));
1159 $this->tpl->parseCurrentBlock();
1160 }
1161
1162 if ($this->object->getListOfQuestions())
1163 {
1164 $this->showSideList($presentationMode, $sequenceElement);
1165 }
1166 }
1167
1168 abstract protected function isOptionalQuestionAnsweringConfirmationRequired($sequenceElement);
1169
1170 abstract protected function isShowingPostponeStatusReguired($questionId);
1171
1172 protected function showQuestionViewable(assQuestionGUI $questionGui, $formAction, $isQuestionWorkedThrough, $instantResponse)
1173 {
1174 $questionNavigationGUI = $this->buildReadOnlyStateQuestionNavigationGUI($questionGui->object->getId());
1175 $questionNavigationGUI->setQuestionWorkedThrough($isQuestionWorkedThrough);
1176 $questionGui->setNavigationGUI($questionNavigationGUI);
1177
1178// fau: testNav - set answere status in question header
1179 $questionGui->getQuestionHeaderBlockBuilder()->setQuestionAnswered($isQuestionWorkedThrough);
1180// fau.
1181
1182 $answerFeedbackEnabled = (
1183 $instantResponse && $this->object->getSpecificAnswerFeedback()
1184 );
1185
1186 $solutionoutput = $questionGui->getSolutionOutput(
1187 $this->testSession->getActiveId(), #active_id
1188 $this->testSession->getPass(), #pass
1189 false, #graphical_output
1190 false, #result_output
1191 true, #show_question_only
1192 $answerFeedbackEnabled, #show_feedback
1193 false, #show_correct_solution
1194 false, #show_manual_scoring
1195 true #show_question_text
1196 );
1197
1198 $pageoutput = $questionGui->outQuestionPage(
1199 "",
1200 $this->isShowingPostponeStatusReguired($questionGui->object->getId()),
1201 $this->testSession->getActiveId(),
1202 $solutionoutput
1203 );
1204
1205 $this->tpl->setCurrentBlock('readonly_css_class');
1206 $this->tpl->touchBlock('readonly_css_class');
1207 $this->tpl->parseCurrentBlock();
1208
1209 $this->tpl->setVariable('QUESTION_OUTPUT', $pageoutput);
1210
1211 $this->tpl->setVariable("FORMACTION", $formAction);
1212 $this->tpl->setVariable("ENCTYPE", 'enctype="'.$questionGui->getFormEncodingType().'"');
1213 $this->tpl->setVariable("FORM_TIMESTAMP", time());
1214 }
1215
1216 protected function showQuestionEditable(assQuestionGUI $questionGui, $formAction, $isQuestionWorkedThrough, $instantResponse)
1217 {
1218 $questionNavigationGUI = $this->buildEditableStateQuestionNavigationGUI(
1219 $questionGui->object->getId(), $this->populateCharSelectorIfRequired()
1220 );
1221 if( $isQuestionWorkedThrough )
1222 {
1223 $questionNavigationGUI->setDiscardSolutionButtonEnabled(true);
1224// fau: testNav - set answere status in question header
1225 $questionGui->getQuestionHeaderBlockBuilder()->setQuestionAnswered(true);
1226// fau.
1227 }
1228 elseif( $this->object->isPostponingEnabled() )
1229 {
1230 $questionNavigationGUI->setSkipQuestionLinkTarget(
1231 $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::SKIP_QUESTION)
1232 );
1233 }
1234 $questionGui->setNavigationGUI($questionNavigationGUI);
1235
1236 $isPostponed = $this->isShowingPostponeStatusReguired($questionGui->object->getId());
1237
1238 $answerFeedbackEnabled = (
1239 $instantResponse && $this->object->getSpecificAnswerFeedback()
1240 );
1241
1242 if( isset($_GET['save_error']) && $_GET['save_error'] == 1 && isset($_SESSION['previouspost']) )
1243 {
1244 $userPostSolution = $_SESSION['previouspost'];
1245 unset($_SESSION['previouspost']);
1246 }
1247 else
1248 {
1249 $userPostSolution = false;
1250 }
1251
1252// fau: testNav - add special checkbox for mc question
1253 if ($questionGui instanceof assMultipleChoiceGUI)
1254 {
1255 $questionGui->setWithNoneAbove($this->object->getMCScoring());
1256 $questionGui->setIsAnswered($isQuestionWorkedThrough);
1257 }
1258// fau.
1259
1260 // hey: prevPassSolutions - determine solution pass index and configure gui accordingly
1261 $qstConfig = $questionGui->object->getTestPresentationConfig();
1262 if( $qstConfig->isPreviousPassSolutionReuseAllowed() )
1263 {
1264 $passIndex = $this->determineSolutionPassIndex($questionGui); // last pass having solution stored
1265 if( $passIndex < $this->testSession->getPass() ) // it's the previous pass if current pass is higher
1266 {
1267 $qstConfig->setSolutionInitiallyPrefilled(true);
1268 }
1269 }
1270 else
1271 {
1272 $passIndex = $this->testSession->getPass();
1273 }
1274 // hey.
1275
1276 // Answer specific feedback is rendered into the display of the test question with in the concrete question types outQuestionForTest-method.
1277 // Notation of the params prior to getting rid of this crap in favor of a class
1278 $questionGui->outQuestionForTest(
1279 $formAction, #form_action
1280 $this->testSession->getActiveId(), #active_id
1281 // hey: prevPassSolutions - prepared pass index having no, current or previous solution
1282 $passIndex, #pass
1283 // hey.
1284 $isPostponed, #is_postponed
1285 $userPostSolution, #user_post_solution
1286 $answerFeedbackEnabled #answer_feedback == inline_specific_feedback
1287 );
1288 // The display of specific inline feedback and specific feedback in an own block is to honor questions, which
1289 // have the possibility to embed the specific feedback into their output while maintaining compatibility to
1290 // questions, which do not have such facilities. E.g. there can be no "specific inline feedback" for essay
1291 // questions, while the multiple-choice questions do well.
1292
1293
1294 $this->populateModals();
1295
1296// fau: testNav - pouplate the new question edit control instead of the deprecated intermediate solution saver
1297 $this->populateQuestionEditControl($questionGui);
1298// fau.
1299 }
1300
1301 // hey: prevPassSolutions - determine solution pass index
1302 protected function determineSolutionPassIndex(assQuestionGUI $questionGui)
1303 {
1304 require_once './Modules/Test/classes/class.ilObjTest.php';
1305
1306 if( ilObjTest::_getUsePreviousAnswers($this->testSession->getActiveId(), true) )
1307 {
1308 $currentSolutionAvailable = $questionGui->object->authorizedOrIntermediateSolutionExists(
1309 $this->testSession->getActiveId(), $this->testSession->getPass()
1310 );
1311
1312 if( !$currentSolutionAvailable )
1313 {
1314 $previousPass = $questionGui->object->getSolutionMaxPass(
1315 $this->testSession->getActiveId()
1316 );
1317
1318 $previousSolutionAvailable = $questionGui->object->authorizedSolutionExists(
1319 $this->testSession->getActiveId(), $previousPass
1320 );
1321
1322 if( $previousSolutionAvailable )
1323 {
1324 return $previousPass;
1325 }
1326 }
1327 }
1328
1329 return $this->testSession->getPass();
1330 }
1331 // hey.
1332
1333 abstract protected function showQuestionCmd();
1334
1335 abstract protected function editSolutionCmd();
1336
1337 abstract protected function submitSolutionCmd();
1338
1339// fau: testNav - new function to revert probably auto-saved changes and show the last submitted question state
1340 protected function revertChangesCmd()
1341 {
1343 $this->setAnswerChangedParameter(false);
1344 $this->ctrl->saveParameter($this, 'sequence');
1345 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
1346 }
1347// fau.
1348
1349 abstract protected function discardSolutionCmd();
1350
1351 abstract protected function skipQuestionCmd();
1352
1353 abstract protected function startTestCmd();
1362 {
1363 global $ilUser;
1364
1365 // check if user is invited to participate
1366 $user = $this->object->getInvitedUsers($ilUser->getId());
1367 if (!is_array ($user) || count($user)!=1)
1368 {
1369 ilUtil::sendInfo($this->lng->txt("user_not_invited"), true);
1370 $this->ctrl->redirectByClass("ilobjtestgui", "backToRepository");
1371 }
1372
1373 $user = array_pop($user);
1374 // check if client ip is set and if current remote addr is equal to stored client-ip
1375 if (strcmp($user["clientip"],"")!=0 && strcmp($user["clientip"],$_SERVER["REMOTE_ADDR"])!=0)
1376 {
1377 ilUtil::sendInfo($this->lng->txt("user_wrong_clientip"), true);
1378 $this->ctrl->redirectByClass("ilobjtestgui", "backToRepository");
1379 }
1380 }
1381
1382
1387 {
1388 return !$this->isNrOfTriesReached()
1389 and !$this->isMaxProcessingTimeReached()
1390 and $this->object->startingTimeReached()
1391 and !$this->object->endingTimeReached();
1392 }
1393
1398 {
1399 return $this->object->hasNrOfTriesRestriction() && $this->object->isNrOfTriesReached($this->testSession->getPass());
1400 }
1401
1408 {
1409 ilUtil::sendInfo(sprintf($this->lng->txt("detail_ending_time_reached"), ilDatePresentation::formatDate(new ilDateTime($this->object->getEndingTime(), IL_CAL_UNIX))));
1410 $this->testSession->increasePass();
1411 $this->testSession->setLastSequence(0);
1412 $this->testSession->saveToDb();
1413
1414 $this->redirectBackCmd();
1415 }
1416
1425 {
1426 $this->suspendTestCmd();
1427 }
1428
1435 {
1436 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_submit_answers_confirm.html", "Modules/Test");
1437 $this->tpl->setCurrentBlock("adm_content");
1438 if ($this->object->isTestFinished($this->testSession->getActiveId()))
1439 {
1440 $this->tpl->setCurrentBlock("not_submit_allowed");
1441 $this->tpl->setVariable("TEXT_ALREADY_SUBMITTED", $this->lng->txt("tst_already_submitted"));
1442 $this->tpl->setVariable("BTN_OK", $this->lng->txt("tst_show_answer_sheet"));
1443 } else
1444 {
1445 $this->tpl->setCurrentBlock("submit_allowed");
1446 $this->tpl->setVariable("TEXT_CONFIRM_SUBMIT_RESULTS", $this->lng->txt("tst_confirm_submit_answers"));
1447 $this->tpl->setVariable("BTN_OK", $this->lng->txt("tst_submit_results"));
1448 }
1449 $this->tpl->setVariable("BTN_BACK", $this->lng->txt("back"));
1450 $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this, "finalSubmission"));
1451 $this->tpl->parseCurrentBlock();
1452 }
1453
1454 function outProcessingTime($active_id)
1455 {
1456 global $ilUser;
1457
1458 $starting_time = $this->object->getStartingTimeOfUser($active_id);
1459 $processing_time = $this->object->getProcessingTimeInSeconds($active_id);
1460 $processing_time_minutes = floor($processing_time / 60);
1461 $processing_time_seconds = $processing_time - $processing_time_minutes * 60;
1462 $str_processing_time = "";
1463 if ($processing_time_minutes > 0)
1464 {
1465 $str_processing_time = $processing_time_minutes . " " . ($processing_time_minutes == 1 ? $this->lng->txt("minute") : $this->lng->txt("minutes"));
1466 }
1467 if ($processing_time_seconds > 0)
1468 {
1469 if (strlen($str_processing_time) > 0) $str_processing_time .= " " . $this->lng->txt("and") . " ";
1470 $str_processing_time .= $processing_time_seconds . " " . ($processing_time_seconds == 1 ? $this->lng->txt("second") : $this->lng->txt("seconds"));
1471 }
1472 $time_left = $starting_time + $processing_time - time();
1473 $time_left_minutes = floor($time_left / 60);
1474 $time_left_seconds = $time_left - $time_left_minutes * 60;
1475 $str_time_left = "";
1476 if ($time_left_minutes > 0)
1477 {
1478 $str_time_left = $time_left_minutes . " " . ($time_left_minutes == 1 ? $this->lng->txt("minute") : $this->lng->txt("minutes"));
1479 }
1480 if ($time_left < 300)
1481 {
1482 if ($time_left_seconds > 0)
1483 {
1484 if (strlen($str_time_left) > 0) $str_time_left .= " " . $this->lng->txt("and") . " ";
1485 $str_time_left .= $time_left_seconds . " " . ($time_left_seconds == 1 ? $this->lng->txt("second") : $this->lng->txt("seconds"));
1486 }
1487 }
1488 $date = getdate($starting_time);
1489 $formattedStartingTime = ilDatePresentation::formatDate(new ilDateTime($date,IL_CAL_FKT_GETDATE));
1490 $datenow = getdate();
1491 $this->tpl->setCurrentBlock("enableprocessingtime");
1492 $this->tpl->setVariable("USER_WORKING_TIME",
1493 sprintf(
1494 $this->lng->txt("tst_time_already_spent"),
1495 $formattedStartingTime,
1496 $str_processing_time
1497 )
1498 );
1499 $this->tpl->setVariable("USER_REMAINING_TIME", sprintf($this->lng->txt("tst_time_already_spent_left"), $str_time_left));
1500 $this->tpl->parseCurrentBlock();
1501 $template = new ilTemplate("tpl.workingtime.js.html", TRUE, TRUE, 'Modules/Test');
1502 $template->setVariable("STRING_MINUTE", $this->lng->txt("minute"));
1503 $template->setVariable("STRING_MINUTES", $this->lng->txt("minutes"));
1504 $template->setVariable("STRING_SECOND", $this->lng->txt("second"));
1505 $template->setVariable("STRING_SECONDS", $this->lng->txt("seconds"));
1506 $template->setVariable("STRING_TIMELEFT", $this->lng->txt("tst_time_already_spent_left"));
1507 $template->setVariable("AND", strtolower($this->lng->txt("and")));
1508 $template->setVariable("YEAR", $date["year"]);
1509 $template->setVariable("MONTH", $date["mon"]-1);
1510 $template->setVariable("DAY", $date["mday"]);
1511 $template->setVariable("HOUR", $date["hours"]);
1512 $template->setVariable("MINUTE", $date["minutes"]);
1513 $template->setVariable("SECOND", $date["seconds"]);
1514 if ($this->object->isEndingTimeEnabled() )
1515 {
1516 $date_time = new ilDateTime($this->object->getEndingTime(), IL_CAL_UNIX);
1517 preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $date_time->get(IL_CAL_TIMESTAMP), $matches);
1518 $template->setVariable("ENDYEAR", $matches[1]);
1519 $template->setVariable("ENDMONTH", $matches[2]-1);
1520 $template->setVariable("ENDDAY", $matches[3]);
1521 $template->setVariable("ENDHOUR", $matches[4]);
1522 $template->setVariable("ENDMINUTE", $matches[5]);
1523 $template->setVariable("ENDSECOND", $matches[6]);
1524 }
1525 $template->setVariable("YEARNOW", $datenow["year"]);
1526 $template->setVariable("MONTHNOW", $datenow["mon"]-1);
1527 $template->setVariable("DAYNOW", $datenow["mday"]);
1528 $template->setVariable("HOURNOW", $datenow["hours"]);
1529 $template->setVariable("MINUTENOW", $datenow["minutes"]);
1530 $template->setVariable("SECONDNOW", $datenow["seconds"]);
1531 $template->setVariable("PTIME_M", $processing_time_minutes);
1532 $template->setVariable("PTIME_S", $processing_time_seconds);
1533
1534 $this->tpl->setCurrentBlock("HeadContent");
1535 $this->tpl->setVariable("CONTENT_BLOCK", $template->get());
1536 $this->tpl->parseCurrentBlock();
1537 }
1538
1539 protected function showSideList($presentationMode, $currentSequenceElement)
1540 {
1541 global $ilUser;
1542
1543 $sideListActive = $ilUser->getPref('side_list_of_questions');
1544
1545 if($sideListActive)
1546 {
1547 $this->tpl->addCss(
1548 ilUtil::getStyleSheetLocation("output", "ta_split.css", "Modules/Test"), "screen"
1549 );
1550
1551 $questionSummaryData = $this->service->getQuestionSummaryData($this->testSequence, false);
1552
1553 require_once 'Modules/Test/classes/class.ilTestQuestionSideListGUI.php';
1554 $questionSideListGUI = new ilTestQuestionSideListGUI($this->ctrl, $this->lng);
1555 $questionSideListGUI->setTargetGUI($this);
1556 $questionSideListGUI->setQuestionSummaryData($questionSummaryData);
1557 $questionSideListGUI->setCurrentSequenceElement($currentSequenceElement);
1558// fau: testNav - set side list presentation mode to "view" to allow navigation when question is in edit mode
1559 $questionSideListGUI->setCurrentPresentationMode(ilTestPlayerAbstractGUI::PRESENTATION_MODE_VIEW);
1560 $questionSideListGUI->setDisabled(false);
1561// $questionSideListGUI->setCurrentPresentationMode($presentationMode);
1562// $questionSideListGUI->setDisabled($presentationMode == self::PRESENTATION_MODE_EDIT);
1563// fau.
1564 $this->tpl->setVariable('LIST_OF_QUESTIONS', $questionSideListGUI->getHTML());
1565 }
1566 }
1567
1568 abstract protected function isQuestionSummaryFinishTestButtonRequired();
1569
1573 public function outQuestionSummaryCmd($fullpage = true, $contextFinishTest = false, $obligationsNotAnswered = false, $obligationsFilter = false)
1574 {
1575 if( $fullpage )
1576 {
1577 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_question_summary.html", "Modules/Test");
1578 }
1579
1580 if( $obligationsNotAnswered )
1581 {
1582 ilUtil::sendFailure($this->lng->txt('not_all_obligations_answered'));
1583 }
1584
1585 if( $this->object->getKioskMode() && $fullpage )
1586 {
1587 $head = $this->getKioskHead();
1588 if( strlen($head) )
1589 {
1590 $this->tpl->setCurrentBlock("kiosk_options");
1591 $this->tpl->setVariable("KIOSK_HEAD", $head);
1592 $this->tpl->parseCurrentBlock();
1593 }
1594 }
1595
1596
1597 $active_id = $this->testSession->getActiveId();
1598 $questionSummaryData = $this->service->getQuestionSummaryData($this->testSequence, $obligationsFilter);
1599
1600 $this->ctrl->setParameter($this, "sequence", $_GET["sequence"]);
1601
1602 if( $fullpage )
1603 {
1604 include_once "./Modules/Test/classes/tables/class.ilListOfQuestionsTableGUI.php";
1605 $table_gui = new ilListOfQuestionsTableGUI($this, 'showQuestion');
1606
1607 $table_gui->setShowPointsEnabled( !$this->object->getTitleOutput() );
1608 $table_gui->setShowMarkerEnabled( $this->object->getShowMarker() );
1609 $table_gui->setObligationsNotAnswered( $obligationsNotAnswered );
1610 $table_gui->setShowObligationsEnabled( $this->object->areObligationsEnabled() );
1611 $table_gui->setObligationsFilterEnabled( $obligationsFilter );
1612 $table_gui->setFinishTestButtonEnabled($this->isQuestionSummaryFinishTestButtonRequired());
1613
1614 $table_gui->init();
1615
1616 $table_gui->setData($questionSummaryData);
1617
1618 $this->tpl->setVariable('TABLE_LIST_OF_QUESTIONS', $table_gui->getHTML());
1619
1620 if( $this->object->getEnableProcessingTime() )
1621 {
1622 $this->outProcessingTime($active_id);
1623 }
1624 }
1625 }
1626
1628 {
1629 return $this->outQuestionSummaryCmd(true, true, true, false);
1630 }
1631
1633 {
1634 return $this->outQuestionSummaryCmd(true, true, true, true);
1635 }
1636
1638 {
1639 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_max_allowed_users_reached.html", "Modules/Test");
1640 $this->tpl->setCurrentBlock("adm_content");
1641 $this->tpl->setVariable("MAX_ALLOWED_USERS_MESSAGE", sprintf($this->lng->txt("tst_max_allowed_users_message"), $this->object->getAllowedUsersTimeGap()));
1642 $this->tpl->setVariable("MAX_ALLOWED_USERS_HEADING", sprintf($this->lng->txt("tst_max_allowed_users_heading"), $this->object->getAllowedUsersTimeGap()));
1643 $this->tpl->setVariable("CMD_BACK_TO_INFOSCREEN", ilTestPlayerCommands::BACK_TO_INFO_SCREEN);
1644 $this->tpl->setVariable("TXT_BACK_TO_INFOSCREEN", $this->lng->txt("tst_results_back_introduction"));
1645 $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
1646 $this->tpl->parseCurrentBlock();
1647 }
1648
1650 {
1651 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
1652 }
1653
1660 {
1661 $this->tpl->addBlockFile("ADM_CONTENT", "adm_content", "tpl.il_as_tst_correct_solution.html", "Modules/Test");
1662
1663 include_once("./Services/Style/Content/classes/class.ilObjStyleSheet.php");
1664 $this->tpl->setCurrentBlock("ContentStyle");
1665 $this->tpl->setVariable("LOCATION_CONTENT_STYLESHEET", ilObjStyleSheet::getContentStylePath(0));
1666 $this->tpl->parseCurrentBlock();
1667
1668 $this->tpl->setCurrentBlock("SyntaxStyle");
1669 $this->tpl->setVariable("LOCATION_SYNTAX_STYLESHEET", ilObjStyleSheet::getSyntaxStylePath());
1670 $this->tpl->parseCurrentBlock();
1671
1672 $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
1673 if ($this->object->getShowSolutionAnswersOnly())
1674 {
1675 $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print_hide_content.css", "Modules/Test"), "print");
1676 }
1677
1678 $this->tpl->setCurrentBlock("adm_content");
1679 $solution = $this->getCorrectSolutionOutput($_GET["evaluation"], $_GET["active_id"], $_GET["pass"]);
1680 $this->tpl->setVariable("OUTPUT_SOLUTION", $solution);
1681 $this->tpl->setVariable("TEXT_BACK", $this->lng->txt("back"));
1682 $this->ctrl->saveParameter($this, "pass");
1683 $this->ctrl->saveParameter($this, "active_id");
1684 $this->tpl->setVariable("URL_BACK", $this->ctrl->getLinkTarget($this, "outUserResultsOverview"));
1685 $this->tpl->parseCurrentBlock();
1686 }
1687
1697 function showListOfAnswers($active_id, $pass = NULL, $top_data = "", $bottom_data = "")
1698 {
1699 global $ilUser;
1700
1701 $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_finish_list_of_answers.html", "Modules/Test");
1702
1703 $result_array =& $this->object->getTestResult(
1704 $active_id, $pass, false, !$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()
1705 );
1706
1707 $counter = 1;
1708 // output of questions with solutions
1709 foreach ($result_array as $question_data)
1710 {
1711 $question = $question_data["qid"];
1712 if (is_numeric($question))
1713 {
1714 $this->tpl->setCurrentBlock("printview_question");
1715 $question_gui = $this->object->createQuestionGUI("", $question);
1716 $template = new ilTemplate("tpl.il_as_qpl_question_printview.html", TRUE, TRUE, "Modules/TestQuestionPool");
1717 $template->setVariable("COUNTER_QUESTION", $counter.". ");
1718 $template->setVariable("QUESTION_TITLE", $question_gui->object->getTitle());
1719
1720 $show_question_only = ($this->object->getShowSolutionAnswersOnly()) ? TRUE : FALSE;
1721 $result_output = $question_gui->getSolutionOutput($active_id, $pass, FALSE, FALSE, $show_question_only, $this->object->getShowSolutionFeedback());
1722 $template->setVariable("SOLUTION_OUTPUT", $result_output);
1723 $this->tpl->setVariable("QUESTION_OUTPUT", $template->get());
1724 $this->tpl->parseCurrentBlock();
1725 $counter ++;
1726 }
1727 }
1728
1729 $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
1730 if ($this->object->getShowSolutionAnswersOnly())
1731 {
1732 $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print_hide_content.css", "Modules/Test"), "print");
1733 }
1734 if (strlen($top_data))
1735 {
1736 $this->tpl->setCurrentBlock("top_data");
1737 $this->tpl->setVariable("TOP_DATA", $top_data);
1738 $this->tpl->parseCurrentBlock();
1739 }
1740
1741 if (strlen($bottom_data))
1742 {
1743 $this->tpl->setCurrentBlock("bottom_data");
1744 $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
1745 $this->tpl->setVariable("BOTTOM_DATA", $bottom_data);
1746 $this->tpl->parseCurrentBlock();
1747 }
1748
1749 $this->tpl->setCurrentBlock("adm_content");
1750 $this->tpl->setVariable("TXT_ANSWER_SHEET", $this->lng->txt("tst_list_of_answers"));
1751 $user_data = $this->getAdditionalUsrDataHtmlAndPopulateWindowTitle($this->testSession, $active_id, TRUE);
1752 $signature = $this->getResultsSignature();
1753 $this->tpl->setVariable("USER_DETAILS", $user_data);
1754 $this->tpl->setVariable("SIGNATURE", $signature);
1755 $this->tpl->setVariable("TITLE", $this->object->getTitle());
1756 $this->tpl->setVariable("TXT_TEST_PROLOG", $this->lng->txt("tst_your_answers"));
1757 $invited_user =& $this->object->getInvitedUsers($ilUser->getId());
1758 $pagetitle = $this->object->getTitle() . " - " . $this->lng->txt("clientip") .
1759 ": " . $invited_user[$ilUser->getId()]["clientip"] . " - " .
1760 $this->lng->txt("matriculation") . ": " .
1761 $invited_user[$ilUser->getId()]["matriculation"];
1762 $this->tpl->setVariable("PAGETITLE", $pagetitle);
1763 $this->tpl->parseCurrentBlock();
1764 }
1765
1771 public function getContentBlockName()
1772 {
1773 if ($this->object->getKioskMode())
1774 {
1775 $this->tpl->setBodyClass("kiosk");
1776 $this->tpl->setAddFooter(FALSE);
1777 return "CONTENT";
1778 }
1779 else
1780 {
1781 return "ADM_CONTENT";
1782 }
1783 }
1784
1786 {
1787 $this->ctrl->redirectByClass(
1788 array('ilRepositoryGUI', 'ilObjTestGUI', 'ilTestEvaluationGUI'), "outUserResultsOverview"
1789 );
1790 }
1791
1795 protected function showRequestedHintListCmd()
1796 {
1797// fau: testNav - handle intermediate submit for viewing requested hints
1798 $this->handleIntermediateSubmit();
1799// fau.
1800
1801 $this->ctrl->setParameter($this, 'pmode', self::PRESENTATION_MODE_EDIT);
1802
1803 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintRequestGUI.php';
1804 $this->ctrl->redirectByClass('ilAssQuestionHintRequestGUI', ilAssQuestionHintRequestGUI::CMD_SHOW_LIST);
1805 }
1806
1810 protected function confirmHintRequestCmd()
1811 {
1812// fau: testNav - handle intermediate submit for confirming hint requests
1813 $this->handleIntermediateSubmit();
1814// fau.
1815
1816 $this->ctrl->setParameter($this, 'pmode', self::PRESENTATION_MODE_EDIT);
1817
1818 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintRequestGUI.php';
1819 $this->ctrl->redirectByClass('ilAssQuestionHintRequestGUI', ilAssQuestionHintRequestGUI::CMD_CONFIRM_REQUEST);
1820 }
1821
1822 abstract protected function isFirstQuestionInSequence($sequenceElement);
1823
1824 abstract protected function isLastQuestionInSequence($sequenceElement);
1825
1826
1827 abstract protected function handleQuestionActionCmd();
1828
1829 abstract protected function showInstantResponseCmd();
1830
1831 abstract protected function nextQuestionCmd();
1832
1833 abstract protected function previousQuestionCmd();
1834
1835 protected function prepareSummaryPage()
1836 {
1837 $this->tpl->addBlockFile(
1838 $this->getContentBlockName(), 'adm_content', 'tpl.il_as_tst_question_summary.html', 'Modules/Test'
1839 );
1840
1841 if ($this->object->getKioskMode())
1842 {
1843 $this->populateKioskHead();
1844 }
1845 }
1846
1847 protected function initTestPageTemplate()
1848 {
1849 $this->tpl->addBlockFile(
1850 $this->getContentBlockName(), 'adm_content', 'tpl.il_as_tst_output.html', 'Modules/Test'
1851 );
1852 }
1853
1854 protected function populateKioskHead()
1855 {
1856 ilUtil::sendInfo(); // ???
1857
1858 $head = $this->getKioskHead();
1859
1860 if (strlen($head))
1861 {
1862 $this->tpl->setCurrentBlock("kiosk_options");
1863 $this->tpl->setVariable("KIOSK_HEAD", $head);
1864 $this->tpl->parseCurrentBlock();
1865 }
1866 }
1867
1869 {
1870 if( $this->ctrl->getNextClass() == 'iltestpasswordprotectiongui' )
1871 {
1872 return;
1873 }
1874
1875 if( !$this->passwordChecker->isPasswordProtectionPageRedirectRequired() )
1876 {
1877 return;
1878 }
1879
1880 $this->ctrl->setParameter($this, 'lock', $this->getLockParameter());
1881
1882 $nextCommand = $this->ctrl->getCmdClass().'::'.$this->ctrl->getCmd();
1883 $this->ctrl->setParameterByClass('ilTestPasswordProtectionGUI', 'nextCommand', $nextCommand);
1884 $this->ctrl->redirectByClass('ilTestPasswordProtectionGUI', 'showPasswordForm');
1885 }
1886
1887 protected function isParticipantsAnswerFixed($questionId)
1888 {
1889 if( !$this->object->isInstantFeedbackAnswerFixationEnabled() )
1890 {
1891 return false;
1892 }
1893
1894 if( !$this->testSequence->isQuestionChecked($questionId) )
1895 {
1896 return false;
1897 }
1898
1899 return true;
1900 }
1901
1906 {
1907 return $this->lng->txt("save_introduction");
1908 }
1909
1910 protected function initAssessmentSettings()
1911 {
1912 $this->assSettings = new ilSetting('assessment');
1913 }
1914
1919 {
1920 $questionList = $this->buildTestPassQuestionList();
1921 $questionList->load();
1922
1923 $testResults = $this->object->getTestResult($testSession->getActiveId(), $testSession->getPass(), true);
1924
1925 require_once 'Modules/Test/classes/class.ilTestSkillEvaluation.php';
1926 $skillEvaluation = new ilTestSkillEvaluation($this->db, $this->object->getTestId(), $this->object->getRefId());
1927
1928 $skillEvaluation->setUserId($testSession->getUserId());
1929 $skillEvaluation->setActiveId($testSession->getActiveId());
1930 $skillEvaluation->setPass($testSession->getPass());
1931
1932 $skillEvaluation->setNumRequiredBookingsForSkillTriggering($this->assSettings->get(
1934 ));
1935
1936
1937 $skillEvaluation->init($questionList);
1938 $skillEvaluation->evaluate($testResults);
1939
1940 $skillEvaluation->handleSkillTriggering();
1941 }
1942
1943 abstract protected function buildTestPassQuestionList();
1944
1946 {
1947 require_once 'Modules/Test/classes/confirmations/class.ilTestAnswerOptionalQuestionsConfirmationGUI.php';
1948 $confirmation = new ilTestAnswerOptionalQuestionsConfirmationGUI($this->lng);
1949
1950 $confirmation->setFormAction($this->ctrl->getFormAction($this));
1951 $confirmation->setCancelCmd('cancelAnswerOptionalQuestions');
1952 $confirmation->setConfirmCmd('confirmAnswerOptionalQuestions');
1953
1954 $confirmation->build($this->object->isFixedTest());
1955
1956 $this->populateHelperGuiContent($confirmation);
1957 }
1958
1960 {
1961 $this->testSequence->setAnsweringOptionalQuestionsConfirmed(true);
1962 $this->testSequence->saveToDb();
1963
1964 $this->ctrl->setParameter($this, 'activecommand', 'gotoquestion');
1965 $this->ctrl->redirect($this, 'redirectQuestion');
1966 }
1967
1969 {
1970 if( $this->object->getListOfQuestions() )
1971 {
1972 $this->ctrl->setParameter($this, 'activecommand', 'summary');
1973 }
1974 else
1975 {
1976 $this->ctrl->setParameter($this, 'activecommand', 'previous');
1977 }
1978
1979 $this->ctrl->redirect($this, 'redirectQuestion');
1980 }
1981
1985 protected function populateHelperGuiContent($helperGui)
1986 {
1987 if($this->object->getKioskMode())
1988 {
1989 $this->tpl->addBlockfile($this->getContentBlockName(), 'content', "tpl.il_as_tst_kiosk_mode_content.html", "Modules/Test");
1990 $this->tpl->setContent($this->ctrl->getHTML($helperGui));
1991 }
1992 else
1993 {
1994 $this->tpl->setVariable($this->getContentBlockName(), $this->ctrl->getHTML($helperGui));
1995 }
1996 }
1997
2002 {
2003 global $ilSetting;
2004
2005 if ($ilSetting->get('char_selector_availability') > 0)
2006 {
2007 require_once 'Services/UIComponent/CharSelector/classes/class.ilCharSelectorGUI.php';
2008 $char_selector = ilCharSelectorGUI::_getCurrentGUI($this->object);
2009 if ($char_selector->getConfig()->getAvailability() == ilCharSelectorConfig::ENABLED)
2010 {
2011 $char_selector->addToPage();
2012 $this->tpl->setCurrentBlock('char_selector');
2013 $this->tpl->setVariable("CHAR_SELECTOR_TEMPLATE", $char_selector->getSelectorHtml());
2014 $this->tpl->parseCurrentBlock();
2015
2016 return true;
2017 }
2018 }
2019
2020 return false;
2021 }
2022
2023 protected function getTestNavigationToolbarGUI()
2024 {
2025 global $ilUser;
2026
2027 require_once 'Modules/Test/classes/class.ilTestNavigationToolbarGUI.php';
2028 $navigationToolbarGUI = new ilTestNavigationToolbarGUI($this->ctrl, $this->lng, $this);
2029
2030 $navigationToolbarGUI->setSuspendTestButtonEnabled($this->object->getShowCancel());
2031 $navigationToolbarGUI->setQuestionTreeButtonEnabled($this->object->getListOfQuestions());
2032 $navigationToolbarGUI->setQuestionTreeVisible($ilUser->getPref('side_list_of_questions'));
2033 $navigationToolbarGUI->setQuestionListButtonEnabled($this->object->getListOfQuestions());
2034 $navigationToolbarGUI->setFinishTestCommand($this->getFinishTestCommand());
2035
2036 return $navigationToolbarGUI;
2037 }
2038
2039 protected function buildReadOnlyStateQuestionNavigationGUI($questionId)
2040 {
2041 require_once 'Modules/Test/classes/class.ilTestQuestionNavigationGUI.php';
2042 $navigationGUI = new ilTestQuestionNavigationGUI($this->lng);
2043
2044 if( !$this->isParticipantsAnswerFixed($questionId) )
2045 {
2046 $navigationGUI->setEditSolutionCommand(ilTestPlayerCommands::EDIT_SOLUTION);
2047 }
2048
2049 if($this->object->getShowMarker())
2050 {
2051 include_once "./Modules/Test/classes/class.ilObjTest.php";
2052 $solved_array = ilObjTest::_getSolvedQuestions($this->testSession->getActiveId(), $questionId);
2053 $solved = 0;
2054
2055 if(count($solved_array) > 0)
2056 {
2057 $solved = array_pop($solved_array);
2058 $solved = $solved["solved"];
2059 }
2060// fau: testNav - change question mark command to link target
2061 if($solved == 1)
2062 {
2063 $navigationGUI->setQuestionMarkLinkTarget($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::UNMARK_QUESTION));
2064 $navigationGUI->setQuestionMarked(true);
2065 }
2066 else
2067 {
2068 $navigationGUI->setQuestionMarkLinkTarget($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::MARK_QUESTION));
2069 $navigationGUI->setQuestionMarked(false);
2070 }
2071 }
2072// fau.
2073
2074 return $navigationGUI;
2075 }
2076
2077 protected function buildEditableStateQuestionNavigationGUI($questionId, $charSelectorAvailable)
2078 {
2079 require_once 'Modules/Test/classes/class.ilTestQuestionNavigationGUI.php';
2080 $navigationGUI = new ilTestQuestionNavigationGUI($this->lng);
2081
2082 if( $this->object->isForceInstantFeedbackEnabled() )
2083 {
2084 $navigationGUI->setSubmitSolutionCommand(ilTestPlayerCommands::SUBMIT_SOLUTION);
2085 }
2086 else
2087 {
2088// fau: testNav - use simple "submitSolution" button instead of "submitSolutionAndNext"
2089 $navigationGUI->setSubmitSolutionCommand(ilTestPlayerCommands::SUBMIT_SOLUTION);
2090// fau.
2091 }
2092
2093// fau: testNav - add a 'revert changes' link for editable question
2094 $navigationGUI->setRevertChangesLinkTarget($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::REVERT_CHANGES));
2095// fau.
2096
2097
2098 // feedback
2099 switch( 1 )
2100 {
2101 case $this->object->getSpecificAnswerFeedback():
2102 case $this->object->getGenericAnswerFeedback():
2103 case $this->object->getAnswerFeedbackPoints():
2104 case $this->object->getInstantFeedbackSolution():
2105
2106 $navigationGUI->setAnswerFreezingEnabled($this->object->isInstantFeedbackAnswerFixationEnabled());
2107
2108 if( $this->object->isForceInstantFeedbackEnabled() )
2109 {
2110 $navigationGUI->setForceInstantResponseEnabled(true);
2111 $navigationGUI->setInstantFeedbackCommand(ilTestPlayerCommands::SUBMIT_SOLUTION);
2112 }
2113 else
2114 {
2115 $navigationGUI->setInstantFeedbackCommand(ilTestPlayerCommands::SHOW_INSTANT_RESPONSE);
2116 }
2117 }
2118
2119 // hints
2120 if( $this->object->isOfferingQuestionHintsEnabled() )
2121 {
2122 $activeId = $this->testSession->getActiveId();
2123 $pass = $this->testSession->getPass();
2124
2125 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
2126 $questionHintTracking = new ilAssQuestionHintTracking($questionId, $activeId, $pass);
2127
2128 if( $questionHintTracking->requestsPossible() )
2129 {
2130 $navigationGUI->setRequestHintCommand(ilTestPlayerCommands::CONFIRM_HINT_REQUEST);
2131 }
2132
2133 if( $questionHintTracking->requestsExist() )
2134 {
2135 $navigationGUI->setShowHintsCommand(ilTestPlayerCommands::SHOW_REQUESTED_HINTS_LIST);
2136 }
2137 }
2138
2139 $navigationGUI->setCharSelectorEnabled($charSelectorAvailable);
2140
2141 if($this->object->getShowMarker())
2142 {
2143 include_once "./Modules/Test/classes/class.ilObjTest.php";
2144 $solved_array = ilObjTest::_getSolvedQuestions($this->testSession->getActiveId(), $questionId);
2145 $solved = 0;
2146
2147 if(count($solved_array) > 0)
2148 {
2149 $solved = array_pop($solved_array);
2150 $solved = $solved["solved"];
2151 }
2152
2153// fau: testNav - change question mark command to link target
2154 if($solved == 1)
2155 {
2156 $navigationGUI->setQuestionMarkLinkTarget($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::UNMARK_QUESTION_SAVE));
2157 $navigationGUI->setQuestionMarked(true);
2158 }
2159 else
2160 {
2161 $navigationGUI->setQuestionMarkLinkTarget($this->ctrl->getLinkTarget($this, ilTestPlayerCommands::MARK_QUESTION_SAVE));
2162 $navigationGUI->setQuestionMarked(false);
2163 }
2164 }
2165// fau.
2166 return $navigationGUI;
2167 }
2168
2172 protected function getFinishTestCommand()
2173 {
2174 if( !$this->object->getListOfQuestionsEnd() )
2175 {
2176 return 'finishTest';
2177 }
2178
2179 if( $this->object->areObligationsEnabled() )
2180 {
2181 $allObligationsAnswered = ilObjTest::allObligationsAnswered(
2182 $this->testSession->getTestId(), $this->testSession->getActiveId(), $this->testSession->getPass()
2183 );
2184
2185 if( !$allObligationsAnswered )
2186 {
2187 return 'outQuestionSummaryWithObligationsInfo';
2188 }
2189 }
2190
2191 return 'outQuestionSummary';
2192 }
2193
2194// fau: testNav - populateIntermediateSolutionSaver is obsolete and can be deletd.
2195// /**
2196// * @param assQuestionGUI $questionGui
2197// */
2198// protected function populateIntermediateSolutionSaver(assQuestionGUI $questionGui)
2199// {
2200// $this->tpl->addJavaScript(ilUtil::getJSLocation("autosave.js", "Modules/Test"));
2201//
2202// $this->tpl->setVariable("AUTOSAVE_URL", $this->ctrl->getFormAction(
2203// $this, ilTestPlayerCommands::AUTO_SAVE, "", true
2204// ));
2205//
2206// if( $questionGui->isAutosaveable() && $this->object->getAutosave() )
2207// {
2208// $formAction = $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::AUTO_SAVE, '', false, false);
2209//
2210// $this->tpl->touchBlock('autosave');
2211// $this->tpl->setVariable("AUTOSAVEFORMACTION", $formAction);
2212// $this->tpl->setVariable("AUTOSAVEINTERVAL", $this->object->getAutosaveIval());
2213// }
2214// }
2215// fau.
2216
2217// fau: testNav - new function populateInstantResponseModal()
2218 protected function populateInstantResponseModal(assQuestionGUI $questionGui, $navUrl)
2219 {
2220 $questionGui->setNavigationGUI(null);
2221 $questionGui->getQuestionHeaderBlockBuilder()->setQuestionAnswered(true);
2222
2223 $answerFeedbackEnabled = $this->object->getSpecificAnswerFeedback();
2224
2225 $solutionoutput = $questionGui->getSolutionOutput(
2226 $this->testSession->getActiveId(), #active_id
2227 $this->testSession->getPass(), #pass
2228 false, #graphical_output
2229 false, #result_output
2230 true, #show_question_only
2231 $answerFeedbackEnabled, #show_feedback
2232 false, #show_correct_solution
2233 false, #show_manual_scoring
2234 true #show_question_text
2235 );
2236
2237 $pageoutput = $questionGui->outQuestionPage(
2238 "",
2239 $this->isShowingPostponeStatusReguired($questionGui->object->getId()),
2240 $this->testSession->getActiveId(),
2241 $solutionoutput
2242 );
2243
2244 $tpl = new ilTemplate('tpl.tst_player_response_modal.html', true, true, 'Modules/Test');
2245
2246 // populate the instant response blocks in the
2247 $saved_tpl = $this->tpl;
2248 $this->tpl = $tpl;
2249 $this->populateInstantResponseBlocks($questionGui, true);
2250 $this->tpl = $saved_tpl;
2251
2252 $tpl->setVariable('QUESTION_OUTPUT', $pageoutput);
2253
2254 $button = ilLinkButton::getInstance();
2255 $button->setId('tst_confirm_feedback');
2256 $button->setUrl($navUrl);
2257 $button->setCaption('proceed');
2258 $button->setPrimary(true);
2259 $tpl->setVariable('BUTTON', $button->render());
2260
2261
2262 require_once('Services/UIComponent/Modal/classes/class.ilModalGUI.php');
2263 $modal = ilModalGUI::getInstance();
2264 $modal->setType(ilModalGUI::TYPE_LARGE);
2265 $modal->setId('tst_question_feedback_modal');
2266 $modal->setHeading($this->lng->txt('tst_instant_feedback'));
2267 $modal->setBody($tpl->get());
2268
2269 $this->tpl->addOnLoadCode("$('#tst_question_feedback_modal').modal('show');");
2270 $this->tpl->setVariable('INSTANT_RESPONSE_MODAL', $modal->getHTML());
2271 }
2272// fau;
2273
2274
2278 protected function populateInstantResponseBlocks(assQuestionGUI $questionGui, $authorizedSolution)
2279 {
2280 // This controls if the solution should be shown.
2281 // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Solutions"
2282 if($this->object->getInstantFeedbackSolution())
2283 {
2284 $show_question_inline_score = $this->determineInlineScoreDisplay();
2285
2286 // Notation of the params prior to getting rid of this crap in favor of a class
2287 $solutionoutput = $questionGui->getSolutionOutput($this->testSession->getActiveId(), #active_id
2288 NULL, #pass
2289 FALSE, #graphical_output
2290 $show_question_inline_score, #result_output
2291 FALSE, #show_question_only
2292 FALSE, #show_feedback
2293 TRUE, #show_correct_solution
2294 FALSE, #show_manual_scoring
2295 FALSE #show_question_text
2296 );
2297 $this->populateSolutionBlock($solutionoutput);
2298 }
2299
2300 $reachedPoints = $questionGui->object->getAdjustedReachedPoints(
2301 $this->testSession->getActiveId(), NULL, $authorizedSolution
2302 );
2303
2304 $maxPoints = $questionGui->object->getMaximumPoints();
2305
2306 $solutionCorrect = ($reachedPoints == $maxPoints);
2307
2308 // This controls if the score should be shown.
2309 // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Results (Only Points)"
2310 if($this->object->getAnswerFeedbackPoints())
2311 {
2312 $this->populateScoreBlock($reachedPoints, $maxPoints);
2313 }
2314
2315 // This controls if the generic feedback should be shown.
2316 // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Solutions"
2317 if($this->object->getGenericAnswerFeedback())
2318 {
2319 $this->populateGenericFeedbackBlock($questionGui, $solutionCorrect);
2320 }
2321
2322 // This controls if the specific feedback should be shown.
2323 // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Answer-Specific Feedback"
2324 if($this->object->getSpecificAnswerFeedback())
2325 {
2326 $this->populateSpecificFeedbackBlock($questionGui);
2327 }
2328 }
2329
2330 protected function getCurrentSequenceElement()
2331 {
2332 if( $this->getSequenceElementParameter() )
2333 {
2334 return $this->getSequenceElementParameter();
2335 }
2336
2337 return $this->testSession->getLastSequence();
2338 }
2339
2341 {
2342 unset($_GET['sequence']);
2343 $this->ctrl->setParameter($this, 'sequence', null);
2344 }
2345
2346 protected function getSequenceElementParameter()
2347 {
2348 if( isset($_GET['sequence']) )
2349 {
2350 return $_GET['sequence'];
2351 }
2352
2353 return null;
2354 }
2355
2356 protected function getPresentationModeParameter()
2357 {
2358 if( isset($_GET['pmode']) )
2359 {
2360 return $_GET['pmode'];
2361 }
2362
2363 return null;
2364 }
2365
2366 protected function getInstantResponseParameter()
2367 {
2368 if( isset($_GET['instresp']) )
2369 {
2370 return $_GET['instresp'];
2371 }
2372
2373 return null;
2374 }
2375
2376 protected function getNextCommandParameter()
2377 {
2378 if( isset($_POST['nextcmd']) && strlen($_POST['nextcmd']) )
2379 {
2380 return $_POST['nextcmd'];
2381 }
2382
2383 return null;
2384 }
2385
2386 protected function getNextSequenceParameter()
2387 {
2388 if( isset($_POST['nextseq']) && is_numeric($_POST['nextseq']) )
2389 {
2390 return (int)$_POST['nextseq'];
2391 }
2392
2393 return null;
2394 }
2395
2396// fau: testNav - get the navigation url set by a submit from ilTestPlayerNavigationControl.js
2397 protected function getNavigationUrlParameter()
2398 {
2399 if (isset($_POST['test_player_navigation_url'])) {
2400 return $_POST['test_player_navigation_url'];
2401 }
2402 return null;
2403 }
2404// fau.
2405
2406// fau: testNav - get set and check the 'answer_changed' url parameter
2412 protected function getAnswerChangedParameter()
2413 {
2414 return !empty($_GET['test_answer_changed']);
2415 }
2416
2421 protected function setAnswerChangedParameter($changed = true)
2422 {
2423 $this->ctrl->setParameter($this, 'test_answer_changed', $changed ? '1' : '0');
2424 }
2425
2426
2432 protected function handleIntermediateSubmit()
2433 {
2434 if ($this->getAnswerChangedParameter())
2435 {
2436 $this->saveQuestionSolution(false);
2437 }
2438 else
2439 {
2441 }
2443 }
2444// fau.
2445
2446// fau: testNav - save the switch to prevent the navigation confirmation
2451 {
2452 if (!empty($_POST['save_on_navigation_prevent_confirmation']))
2453 {
2454 $_SESSION['save_on_navigation_prevent_confirmation'] = true;
2455 }
2456 }
2457// fau.
2458
2462 private $cachedQuestionGuis = array();
2463
2469 protected function getQuestionGuiInstance($questionId, $fromCache = true)
2470 {
2471 global $tpl;
2472
2473 if( !$fromCache || !isset($this->cachedQuestionGuis[$questionId]) )
2474 {
2475 $questionGui = $this->object->createQuestionGUI("", $questionId);
2476 $questionGui->setTargetGui($this);
2477 $questionGui->setPresentationContext(assQuestionGUI::PRESENTATION_CONTEXT_TEST);
2478 $questionGui->object->setObligationsToBeConsidered($this->object->areObligationsEnabled());
2479 $questionGui->populateJavascriptFilesRequiredForWorkForm($tpl);
2480 $questionGui->object->setOutputType(OUTPUT_JAVASCRIPT);
2481 $questionGui->object->setShuffler($this->buildQuestionAnswerShuffler($questionId));
2482
2483 // hey: prevPassSolutions - determine solution pass index and configure gui accordingly
2484 $this->initTestQuestionConfig($questionGui->object);
2485 // hey.
2486
2487 $this->cachedQuestionGuis[$questionId] = $questionGui;
2488 }
2489
2490 return $this->cachedQuestionGuis[$questionId];
2491 }
2492
2496 private $cachedQuestionObjects = array();
2497
2502 protected function getQuestionInstance($questionId, $fromCache = true)
2503 {
2504 global $ilDB, $ilUser;
2505
2506 if( !$fromCache || !isset($this->cachedQuestionObjects[$questionId]) )
2507 {
2508 $questionOBJ = assQuestion::_instantiateQuestion($questionId);
2509
2510 $assSettings = new ilSetting('assessment');
2511 require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionProcessLockerFactory.php';
2512 $processLockerFactory = new ilAssQuestionProcessLockerFactory($assSettings, $ilDB);
2513 $processLockerFactory->setQuestionId($questionOBJ->getId());
2514 $processLockerFactory->setUserId($ilUser->getId());
2515 include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
2516 $processLockerFactory->setAssessmentLogEnabled(ilObjAssessmentFolder::_enabledAssessmentLogging());
2517 $questionOBJ->setProcessLocker($processLockerFactory->getLocker());
2518
2519 $questionOBJ->setObligationsToBeConsidered($this->object->areObligationsEnabled());
2520 $questionOBJ->setOutputType(OUTPUT_JAVASCRIPT);
2521
2522 // hey: prevPassSolutions - determine solution pass index and configure gui accordingly
2523 $this->initTestQuestionConfig($questionOBJ);
2524 // hey.
2525
2526 $this->cachedQuestionObjects[$questionId] = $questionOBJ;
2527 }
2528
2529 return $this->cachedQuestionObjects[$questionId];
2530 }
2531
2532 // hey: prevPassSolutions - determine solution pass index and configure gui accordingly
2533 protected function initTestQuestionConfig(assQuestion $questionOBJ)
2534 {
2535 $questionOBJ->getTestPresentationConfig()->setPreviousPassSolutionReuseAllowed(
2536 $this->object->isPreviousSolutionReuseEnabled( $this->testSession->getActiveId() )
2537 );
2538 }
2539 // hey.
2540
2545 protected function buildQuestionAnswerShuffler($questionId)
2546 {
2547 require_once 'Services/Randomization/classes/class.ilArrayElementShuffler.php';
2548 $shuffler = new ilArrayElementShuffler();
2549
2550 $fixedSeed = $this->buildFixedShufflerSeed($questionId);
2551 $shuffler->setSeed($fixedSeed);
2552
2553 return $shuffler;
2554 }
2555
2561 protected function handleTearsAndAngerQuestionIsNull($questionId, $sequenceElement)
2562 {
2563 global $ilLog;
2564
2565 $ilLog->write("INV SEQ:"
2566 ."active={$this->testSession->getActiveId()} "
2567 ."qId=$questionId seq=$sequenceElement "
2568 . serialize($this->testSequence)
2569 );
2570
2571 $ilLog->logStack('INV SEQ');
2572
2573 $this->ctrl->setParameter($this, 'sequence', $this->testSequence->getFirstSequence());
2574 $this->ctrl->redirect($this, ilTestPlayerCommands::SHOW_QUESTION);
2575 }
2576
2580 protected function populateMessageContent($contentHTML)
2581 {
2582 if($this->object->getKioskMode())
2583 {
2584 $this->tpl->addBlockfile($this->getContentBlockName(), 'content', "tpl.il_as_tst_kiosk_mode_content.html", "Modules/Test");
2585 $this->tpl->setContent($contentHTML);
2586 }
2587 else
2588 {
2589 $this->tpl->setVariable($this->getContentBlockName(), $contentHTML);
2590 }
2591 }
2592
2593 protected function populateModals()
2594 {
2595 require_once 'Services/UIComponent/Button/classes/class.ilSubmitButton.php';
2596 require_once 'Services/UIComponent/Button/classes/class.ilLinkButton.php';
2597 require_once 'Services/UIComponent/Modal/classes/class.ilModalGUI.php';
2598
2600// fau: testNav - populateNavWhenChangedModal instead of populateNavWhileEditModal
2602// fau.
2603
2604 if( $this->object->getKioskMode() )
2605 {
2606 $this->tpl->addJavaScript('Services/UICore/lib/bootstrap-3.2.0/dist/js/bootstrap.min.js', true);
2607 }
2608 }
2609
2610 protected function populateDiscardSolutionModal()
2611 {
2612 $tpl = new ilTemplate('tpl.tst_player_confirmation_modal.html', true, true, 'Modules/Test');
2613
2614 $tpl->setVariable('CONFIRMATION_TEXT', $this->lng->txt('discard_answer_confirmation'));
2615
2616 $button = ilSubmitButton::getInstance();
2617 $button->setCommand(ilTestPlayerCommands::DISCARD_SOLUTION);
2618 $button->setCaption('discard_answer');
2619 $tpl->setCurrentBlock('buttons');
2620 $tpl->setVariable('BUTTON', $button->render());
2621 $tpl->parseCurrentBlock();
2622
2623 $button = ilLinkButton::getInstance();
2624 $button->setId('tst_cancel_discard_button');
2625 $button->setCaption('cancel');
2626 $button->setPrimary(true);
2627 $tpl->setCurrentBlock('buttons');
2628 $tpl->setVariable('BUTTON', $button->render());
2629 $tpl->parseCurrentBlock();
2630
2631 $modal = ilModalGUI::getInstance();
2632 $modal->setId('tst_discard_solution_modal');
2633 $modal->setHeading($this->lng->txt('discard_answer'));
2634 $modal->setBody($tpl->get());
2635
2636 $this->tpl->setCurrentBlock('discard_solution_modal');
2637 $this->tpl->setVariable('DISCARD_SOLUTION_MODAL', $modal->getHTML());
2638 $this->tpl->parseCurrentBlock();
2639
2640// fau: testNav - the discard solution modal is now handled by ilTestPlayerNavigationControl.js
2641// $this->tpl->addJavaScript('Modules/Test/js/ilTestPlayerDiscardSolutionModal.js', true);
2642// fau.
2643 }
2644
2645// fau: testNav - populateNavWhileEditModal is obsolete and can be deleted.
2646// protected function populateNavWhileEditModal()
2647// {
2648// require_once 'Services/Form/classes/class.ilFormPropertyGUI.php';
2649// require_once 'Services/Form/classes/class.ilHiddenInputGUI.php';
2650//
2651// $tpl = new ilTemplate('tpl.tst_player_confirmation_modal.html', true, true, 'Modules/Test');
2652//
2653// $tpl->setVariable('CONFIRMATION_TEXT', $this->lng->txt('tst_nav_while_edit_modal_text'));
2654//
2655// $button = ilSubmitButton::getInstance();
2656// $button->setCommand(ilTestPlayerCommands::SUBMIT_SOLUTION);
2657// $button->setCaption('tst_nav_while_edit_modal_save_btn');
2658// $button->setPrimary(true);
2659// $tpl->setCurrentBlock('buttons');
2660// $tpl->setVariable('BUTTON', $button->render());
2661// $tpl->parseCurrentBlock();
2662//
2663// foreach(array('nextcmd', 'nextseq') as $hiddenPostVar)
2664// {
2665// $nextCmdInp = new ilHiddenInputGUI($hiddenPostVar);
2666// $nextCmdInp->setValue('');
2667// $tpl->setCurrentBlock('hidden_inputs');
2668// $tpl->setVariable('HIDDEN_INPUT', $nextCmdInp->getToolbarHTML());
2669// $tpl->parseCurrentBlock();
2670// }
2671//
2672// $button = ilLinkButton::getInstance();
2673// $this->ctrl->setParameter($this, 'pmode', self::PRESENTATION_MODE_VIEW);
2674// $button->setId('nextCmdLink');
2675// $button->setUrl('#');
2676// $this->ctrl->setParameter($this, 'pmode', $this->getPresentationModeParameter());
2677// $button->setCaption('tst_nav_while_edit_modal_nosave_btn');
2678// $tpl->setCurrentBlock('buttons');
2679// $tpl->setVariable('BUTTON', $button->render());
2680// $tpl->parseCurrentBlock();
2681//
2682// $button = ilLinkButton::getInstance();
2683// $button->setId('tst_cancel_nav_while_edit_button');
2684// $button->setCaption('tst_nav_while_edit_modal_cancel_btn');
2685// $tpl->setCurrentBlock('buttons');
2686// $tpl->setVariable('BUTTON', $button->render());
2687// $tpl->parseCurrentBlock();
2688//
2689// $modal = ilModalGUI::getInstance();
2690// $modal->setId('tst_nav_while_edit_modal');
2691// $modal->setHeading($this->lng->txt('tst_nav_while_edit_modal_header'));
2692// $modal->setBody($tpl->get());
2693//
2694// $this->tpl->setCurrentBlock('nav_while_edit_modal');
2695// $this->tpl->setVariable('NAV_WHILE_EDIT_MODAL', $modal->getHTML());
2696// $this->tpl->parseCurrentBlock();
2697//
2698// $this->tpl->addJavaScript('Modules/Test/js/ilTestPlayerNavWhileEditModal.js', true);
2699// }
2700// fau.
2701
2702// fau: testNav - new function populateNavWhenChangedModal
2703 protected function populateNavWhenChangedModal()
2704 {
2705 if (!empty($_SESSION['save_on_navigation_prevent_confirmation']))
2706 {
2707 return;
2708 }
2709
2710 $tpl = new ilTemplate('tpl.tst_player_confirmation_modal.html', true, true, 'Modules/Test');
2711
2712 if ($this->object->isInstantFeedbackAnswerFixationEnabled() && $this->object->isForceInstantFeedbackEnabled())
2713 {
2714 $text = $this->lng->txt('save_on_navigation_locked_confirmation');
2715 }
2716 else
2717 {
2718 $text = $this->lng->txt('save_on_navigation_confirmation');
2719 }
2720 if ($this->object->isForceInstantFeedbackEnabled())
2721 {
2722 $text .= " ". $this->lng->txt('save_on_navigation_forced_feedback_hint');
2723 }
2724 $tpl->setVariable('CONFIRMATION_TEXT', $text);
2725
2726
2727 $button = ilLinkButton::getInstance();
2728 $button->setId('tst_save_on_navigation_button');
2729 $button->setUrl('#');
2730 $button->setCaption('tst_save_and_proceed');
2731 $button->setPrimary(true);
2732 $tpl->setCurrentBlock('buttons');
2733 $tpl->setVariable('BUTTON', $button->render());
2734 $tpl->parseCurrentBlock();
2735
2736 $button = ilLinkButton::getInstance();
2737 $button->setId('tst_cancel_on_navigation_button');
2738 $button->setUrl('#');
2739 $button->setCaption('cancel');
2740 $button->setPrimary(false);
2741 $tpl->setCurrentBlock('buttons');
2742 $tpl->setVariable('BUTTON', $button->render());
2743 $tpl->parseCurrentBlock();
2744
2745 $tpl->setCurrentBlock('checkbox');
2746 $tpl->setVariable('CONFIRMATION_CHECKBOX_NAME','save_on_navigation_prevent_confirmation');
2747 $tpl->setVariable('CONFIRMATION_CHECKBOX_LABEL',$this->lng->txt('save_on_navigation_prevent_confirmation'));
2748 $tpl->parseCurrentBlock();
2749
2750 $modal = ilModalGUI::getInstance();
2751 $modal->setId('tst_save_on_navigation_modal');
2752 $modal->setHeading($this->lng->txt('save_on_navigation'));
2753 $modal->setBody($tpl->get());
2754
2755 $this->tpl->setCurrentBlock('nav_while_edit_modal');
2756 $this->tpl->setVariable('NAV_WHILE_EDIT_MODAL', $modal->getHTML());
2757 $this->tpl->parseCurrentBlock();
2758 }
2759// fau.
2760
2761// fau: testNav - new function populateQuestionEditControl
2767 protected function populateQuestionEditControl($questionGUI)
2768 {
2769 // configuration for ilTestPlayerQuestionEditControl.js
2770 $config = array();
2771
2772 // set the initial state of the question
2773 $state = $questionGUI->object->lookupForExistingSolutions($this->testSession->getActiveId(), $this->testSession->getPass());
2774 $config['isAnswered'] = $state['authorized'];
2775 $config['isAnswerChanged'] = $state['intermediate'] || $this->getAnswerChangedParameter();
2776
2777 // set url to which the for should be submitted when the working time is over
2778 // don't use asynch url because the form is submitted directly
2779 // but use simple '&' because url is copied by javascript into the form action
2780 $config['saveOnTimeReachedUrl'] = str_replace('&amp;','&', $this->ctrl->getFormAction($this, ilTestPlayerCommands::AUTO_SAVE));
2781
2782 // enable the auto saving function
2783 // the autosave url is asynch because it will be used by an ajax request
2784 if( $questionGUI->isAutosaveable() && $this->object->getAutosave() )
2785 {
2786 $config['autosaveUrl'] = $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::AUTO_SAVE, '', true);
2787 $config['autosaveInterval'] = $this->object->getAutosaveIval();
2788 }
2789 else
2790 {
2791 $config['autosaveUrl'] = '';
2792 $config['autosaveInterval'] = 0;
2793 }
2794
2796 // hey: prevPassSolutions - refactored method identifiers
2797 $questionConfig = $questionGUI->object->getTestPresentationConfig();
2798 // hey.
2799
2800 // Normal questions: changes are done in form fields an can be detected there
2801 $config['withFormChangeDetection'] = $questionConfig->isFormChangeDetectionEnabled();
2802
2803 // Flash and Java questions: changes are directly sent to ilias and have to be polled from there
2804 $config['withBackgroundChangeDetection'] = $questionConfig->isBackgroundChangeDetectionEnabled();
2805 $config['backgroundDetectorUrl'] = $this->ctrl->getLinkTarget($this, ilTestPlayerCommands::DETECT_CHANGES, '', true);
2806
2807 // Forced feedback will change the navigation saving command
2808 $config['forcedInstantFeedback'] = $this->object->isForceInstantFeedbackEnabled();
2809
2810 $this->tpl->addJavascript('./Modules/Test/js/ilTestPlayerQuestionEditControl.js');
2811 $this->tpl->addOnLoadCode('il.TestPlayerQuestionEditControl.init('.json_encode($config).')');
2812 }
2813// fau.
2814
2815 protected function getQuestionsDefaultPresentationMode($isQuestionWorkedThrough)
2816 {
2817// fau: testNav - always set default presentation mode to "edit"
2819// fau.
2820 }
2821
2826 protected function buildFixedShufflerSeed($questionId)
2827 {
2828 $fixedSeed = $questionId . $this->testSession->getActiveId() . $this->testSession->getPass();
2829
2831 {
2832 $fixedSeed *= (
2834 );
2835 }
2836
2837 return $fixedSeed;
2838 }
2839
2840 protected function registerForcedFeedbackNavUrl($forcedFeedbackNavUrl)
2841 {
2842 if( !isset($_SESSION['forced_feedback_navigation_url']) )
2843 {
2844 $_SESSION['forced_feedback_navigation_url'] = array();
2845 }
2846
2847 $_SESSION['forced_feedback_navigation_url'][$this->testSession->getActiveId()] = $forcedFeedbackNavUrl;
2848 }
2849
2851 {
2852 if( !isset($_SESSION['forced_feedback_navigation_url']) )
2853 {
2854 return null;
2855 }
2856
2857 if( !isset($_SESSION['forced_feedback_navigation_url'][$this->testSession->getActiveId()]) )
2858 {
2859 return null;
2860 }
2861
2862 return $_SESSION['forced_feedback_navigation_url'][$this->testSession->getActiveId()];
2863 }
2864
2866 {
2867 return !empty($this->getRegisteredForcedFeedbackNavUrl());
2868 }
2869
2871 {
2872 if( isset($_SESSION['forced_feedback_navigation_url'][$this->testSession->getActiveId()]) )
2873 {
2874 unset($_SESSION['forced_feedback_navigation_url'][$this->testSession->getActiveId()]);
2875 }
2876 }
2877}
sprintf('%.4f', $callTime)
$result
$path
Definition: aliased.php:25
$_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.
setNavigationGUI($navigationGUI)
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)
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="")
output question page
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)
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)
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)
Class ilTestPassFinishTasks.
Output class for assessment test execution.
handleSkillTriggering(ilTestSession $testSession)
checkTestSessionUser(ilTestSession $testSession)
populateNextButtons($disabled, $primaryNext)
isShowingPostponeStatusReguired($questionId)
saveTagsCmd()
Save tags for tagging gui.
initTestQuestionConfig(assQuestion $questionOBJ)
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...
confirmHintRequestCmd()
Go to hint request confirmation.
__construct($a_object)
ilTestOutputGUI constructor
removeIntermediateSolution()
remove an auto-saved solution of the current question
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)
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
maxProcessingTimeReached()
Outputs a message when the maximum processing time is reached.
showQuestionEditable(assQuestionGUI $questionGui, $formAction, $isQuestionWorkedThrough, $instantResponse)
getQuestionGuiInstance($questionId, $fromCache=true)
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...
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)
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)
outQuestionSummaryCmd($fullpage=true, $contextFinishTest=false, $obligationsNotAnswered=false, $obligationsFilter=false)
Output of a summary of all test questions for test participants.
Service GUI class for tests.
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.
getAdditionalUsrDataHtmlAndPopulateWindowTitle($testSession, $active_id, $overwrite_anonymity=FALSE)
Returns the user data for a test results output.
buildQuestionRelatedObjectivesList(ilLOTestQuestionAdapter $objectivesAdapter, ilTestQuestionSequence $testSequence)
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)
http redirect to other script
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
static makeDirParents($a_dir)
Create a new directory and all parent directories.
static sendInfo($a_info="", $a_keep=false)
Send Info Message to Screen.
$counter
$text
$GLOBALS['loaded']
Global hash that tracks already loaded includes.
const OUTPUT_JAVASCRIPT
const REDIRECT_KIOSK
redirection script todo: (a better solution should control the processing via a xml file)
global $ilSetting
Definition: privfeed.php:17
if(!file_exists("$old.txt")) if( $old===$new) if(file_exists("$new.txt")) $file
$results
$url
Definition: shib_logout.php:72
global $ilDB
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
global $DIC
$ilUser
Definition: imgupload.php:18