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