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