19declare(strict_types=1);
83 $this->ref_id = $this->testrequest->getRefId();
89 $this->
tabs->clearTargets();
91 $cmd = $this->
ctrl->getCmd();
92 $next_class = $this->
ctrl->getNextClass($this);
95 if ($cmd ===
'autosave') {
96 echo $this->
lng->txt(
'autosave_failed') .
': ' . $read_access;
99 $this->tpl->setOnScreenMessage(
'failure', $read_access,
true);
100 $this->
ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, TestScreenGUI::class]);
103 $this->
ctrl->saveParameter($this,
"sequence");
104 $this->
ctrl->saveParameter($this,
"pmode");
105 $this->
ctrl->saveParameter($this,
"active_id");
110 $this->test_session = $testSessionFactory->getSession($this->testrequest->int(
'active_id'));
119 $this->test_sequence->loadFromDb();
120 $this->test_sequence->loadQuestions();
128 $instance_name = $this->
settings->get(
'short_inst_name') ??
'';
129 if (trim($instance_name) ===
'') {
130 $instance_name =
'ILIAS';
132 $this->global_screen->tool()->context()->current()->addAdditionalData(
136 $this->global_screen->tool()->context()->current()->addAdditionalData(
138 $this->
object->getKioskMode()
140 $this->global_screen->tool()->context()->current()->addAdditionalData(
144 $this->global_screen->tool()->context()->current()->addAdditionalData(
149 switch ($next_class) {
150 case 'ilassquestionpagegui':
156 $page_gui->setFileDownloadLink(
157 $this->
ctrl->getLinkTargetByClass(ilObjTestGUI::class,
'downloadFile')
159 $ret = $this->
ctrl->forwardCommand($page_gui);
162 case 'iltestsubmissionreviewgui':
168 $ret = $this->
ctrl->forwardCommand($gui);
171 case 'ilassspecfeedbackpagegui':
172 case 'ilassgenfeedbackpagegui':
173 $id = $this->testrequest->int(
'pg_id');
174 if ($this->
ctrl->getCmd() !==
'displayMediaFullscreen'
180 $next_class ===
'ilassgenfeedbackpagegui' ?
'qfbg' :
'qfbs',
182 ))->displayMediaFullscreen();
185 case 'iltestpasswordprotectiongui':
193 $this->password_checker,
197 $ret = $this->
ctrl->forwardCommand($gui);
205 if ($cmd ===
'outQuestionSummary'
206 || $cmd ===
'submitSolution') {
210 if ($cmd ===
'showQuestion') {
212 $testPassesSelector->setActiveId($this->test_session->getActiveId());
213 $testPassesSelector->setLastFinishedPass($this->test_session->getLastFinishedPass());
215 if (!$testPassesSelector->openPassExists()) {
216 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'tst_pass_finished'),
true);
217 $this->
ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, TestScreenGUI::class]);
222 $ret = $this->$cmd();
233 if (!$this->rbac_system->checkAccess(
'read', $this->object->getRefId())) {
234 return $this->
lng->txt(
'cannot_execute_test');
237 $participant_access = (
new ilTestAccess($this->
object->getRefId()))->isParticipantAllowed(
241 if ($participant_access !== ParticipantAccess::ALLOWED) {
242 return $participant_access->getAccessForbiddenMessage($this->
lng);
250 $executable = $this->
object->isExecutable($this->test_session, $this->test_session->getUserId());
252 if (!$executable[
'executable']) {
253 $this->tpl->setOnScreenMessage(
'info', $executable[
'errormessage'],
true);
254 $this->
ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, TestScreenGUI::class]);
261 throw new ilTestException(
'active id given does not relate to current user!');
288 $this->process_locker = $process_lockerFactory->withContextId((
int) $activeId)->getLocker();
300 $tagging_gui->setObject($this->
object->getId(), $this->object->getType());
301 $tagging_gui->saveInput();
302 $this->
ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, ilInfoScreenGUI::class]);
311 $this->
object->updateWorkingTime(
ilSession::get(
"active_time_id"));
316 $this->
object->startWorkingTime(
317 $this->test_session->getActiveId(),
318 $this->test_session->getPass()
328 $this->test_session->getActiveId(),
329 $this->test_session->getPass()
334 bool $authorized =
true,
354 if ($question_obj ===
null) {
358 $saved = ($force || $this->
canSaveResult()) && $this->
save($question_obj, $authorized);
361 $this->
ctrl->setParameter($this,
'save_error',
'1');
362 ilSession::set(
'previouspost', $this->testrequest->getParsedBody());
374 $formtimestamp = $this->testrequest->int(
'formtimestamp');
386 $q_id = $this->test_sequence->getQuestionForSequence($this->testrequest->int(
'sequence'));
388 if ($this->isParticipantsAnswerFixed($q_id)) {
394 if ($q_id ===
null) {
398 return $this->getQuestionInstance($q_id);
403 $active_id = $this->test_session->getActiveId();
413 if ($authorized && $this->test_session->isObjectiveOriented()) {
415 $objectivesAdapter->updateQuestionResult($this->test_session, $question_obj);
418 if ($authorized && $this->
object->isSkillServiceToBeConsidered()) {
419 $this->handleSkillTriggering($this->test_session);
422 if ($authorized && $this->
logger->isLoggingEnabled()
423 && !$this->getObject()->getAnonymity()
425 $this->logger->getAdditionalInformationGenerator(),
426 $this->getObject()->getRefId(),
429 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
430 TestParticipantInteractionTypes::ANSWER_SUBMITTED
432 $this->
logger->logParticipantInteraction($interaction);
439 return !$this->
object->endingTimeReached() && !$this->isMaxProcessingTimeReached() && !$this->isNrOfTriesReached();
444 $this->
ctrl->redirectByClass(TestScreenGUI::class, TestScreenGUI::DEFAULT_CMD);
449 $active_id = $this->test_session->getActiveId();
450 $starting_time = $this->
object->getStartingTimeOfUser($active_id);
451 if ($starting_time ===
false) {
454 return $this->
object->isMaxProcessingTimeReached($starting_time, $active_id);
460 $show_question_inline_score =
false;
461 if ($this->
object->getAnswerFeedbackPoints()) {
462 $show_question_inline_score =
true;
463 return $show_question_inline_score;
465 return $show_question_inline_score;
470 $this->tpl->setCurrentBlock(
'test_nav_toolbar');
471 $this->tpl->setVariable(
'TEST_NAV_TOOLBAR', $toolbar_gui->getHTML());
472 $this->tpl->parseCurrentBlock();
474 if ($this->finish_test_modal ===
null) {
478 $this->tpl->setCurrentBlock(
'finish_test_modal');
479 $this->tpl->setVariable(
481 $this->ui_renderer->render(
482 $this->finish_test_modal->withOnLoad($this->finish_test_modal->getShowSignal())
485 $this->tpl->parseCurrentBlock();
490 if (!$this->isFirstQuestionInSequence($sequence_element)) {
491 $this->populatePreviousButtons();
494 if (!$this->isLastQuestionInSequence($sequence_element)) {
495 $this->populateNextButtons($primary_next);
501 $this->populateUpperPreviousButtonBlock();
502 $this->populateLowerPreviousButtonBlock();
507 $this->populateUpperNextButtonBlock($primary_next);
508 $this->populateLowerNextButtonBlock($primary_next);
513 $button = $this->buildNextButtonInstance($primary_next);
515 $this->tpl->setCurrentBlock(
"next_bottom");
516 $this->tpl->setVariable(
"BTN_NEXT_BOTTOM", $this->ui_renderer->render($button));
517 $this->tpl->parseCurrentBlock();
522 $button = $this->buildNextButtonInstance($primaryNext);
524 $this->tpl->setCurrentBlock(
"next");
525 $this->tpl->setVariable(
"BTN_NEXT", $this->ui_renderer->render($button));
526 $this->tpl->parseCurrentBlock();
531 $button = $this->buildPreviousButtonInstance();
533 $this->tpl->setCurrentBlock(
"prev_bottom");
534 $this->tpl->setVariable(
"BTN_PREV_BOTTOM", $this->ui_renderer->render($button));
535 $this->tpl->parseCurrentBlock();
540 $button = $this->buildPreviousButtonInstance();
542 $this->tpl->setCurrentBlock(
"prev");
543 $this->tpl->setVariable(
"BTN_PREV", $this->ui_renderer->render($button));
544 $this->tpl->parseCurrentBlock();
555 $button = $this->ui_factory->button()->primary(
556 $this->
lng->txt(
'next_question') . $this->ui_renderer->render($this->ui_factory->symbol()->glyph()->next()),
558 )->withUnavailableAction(
true)
561 $button = $this->ui_factory->button()->standard(
562 $this->
lng->txt(
'next_question') . $this->ui_renderer->render($this->ui_factory->symbol()->glyph()->next()),
564 )->withUnavailableAction(
true)
577 $button = $this->ui_factory->button()->standard(
578 $this->ui_renderer->render($this->ui_factory->symbol()->glyph()->back()) . $this->lng->txt(
'previous_question'),
580 )->withUnavailableAction(
true)
587 return static function (
string $id) use ($target, $cmd):
string {
588 return "document.getElementById('{$id}').addEventListener('click', "
589 .
"(e) => {il.TestPlayerQuestionEditControl.checkNavigation('{$target}', '{$cmd}', e);}"
591 .
"document.getElementById('{$id}').removeAttribute('disabled');";
600 $solutionValues = $question_gui->
getObject()->getSolutionValues(
601 $this->test_session->getActiveId(),
606 $question_gui->
getObject()->fetchIndexedValuesFromValuePairs($solutionValues)
609 if (!empty($feedback)) {
610 $this->tpl->setCurrentBlock(
"specific_feedback");
611 $this->tpl->setVariable(
"SPECIFIC_FEEDBACK", $feedback);
612 $this->tpl->parseCurrentBlock();
624 $feedback = $question_gui->
getGenericFeedbackOutput($this->test_session->getActiveId(), $this->test_session->getPass());
626 if (strlen($feedback)) {
632 $this->tpl->setCurrentBlock(
"answer_feedback");
633 $this->tpl->setVariable(
"ANSWER_FEEDBACK", $feedback);
634 $this->tpl->setVariable(
"ILC_FB_CSS_CLASS", $cssClass);
635 $this->tpl->parseCurrentBlock();
643 $scoreInformation = sprintf(
644 $this->
lng->txt(
"you_received_a_of_b_points"),
649 $this->tpl->setCurrentBlock(
"received_points_information");
650 $this->tpl->setVariable(
"RECEIVED_POINTS_INFORMATION", $scoreInformation);
651 $this->tpl->parseCurrentBlock();
656 if (strlen($solutionoutput)) {
657 $this->tpl->setCurrentBlock(
"solution_output");
658 $this->tpl->setVariable(
"CORRECT_SOLUTION", $this->
lng->txt(
"tst_best_solution_is"));
659 $this->tpl->setVariable(
"QUESTION_FEEDBACK", $solutionoutput);
660 $this->tpl->parseCurrentBlock();
666 $this->tpl->setCurrentBlock(
"SyntaxStyle");
667 $this->tpl->setVariable(
668 "LOCATION_SYNTAX_STYLESHEET",
671 $this->tpl->parseCurrentBlock();
676 $this->tpl->setCurrentBlock(
"ContentStyle");
677 $this->tpl->setVariable(
678 "LOCATION_CONTENT_STYLESHEET",
681 $this->tpl->parseCurrentBlock();
691 if ($this->test_session->isAnonymousUser()) {
692 $this->test_session->setAccessCodeToSession($this->testrequest->strVal(
'anonymous_id'));
695 $this->
ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, ilInfoScreenGUI::class]);
706 $testStartLock = $this->getLockParameter();
707 $isFirstTestStartRequest =
false;
709 $this->process_locker->executeTestStartLockOperation(
function () use ($testStartLock, &$isFirstTestStartRequest) {
710 if ($this->test_session->lookupTestStartLock() !== $testStartLock) {
711 $this->test_session->persistTestStartLock($testStartLock);
712 $isFirstTestStartRequest = true;
716 if ($isFirstTestStartRequest) {
717 $this->handleUserSettings();
721 $this->
ctrl->setParameterByClass(
'ilObjTestGUI',
'lock', $testStartLock);
722 $this->
ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, ilInfoScreenGUI::class]);
727 if ($this->testrequest->isset(
'lock') && strlen($this->testrequest->raw(
'lock'))) {
728 return $this->testrequest->raw(
'lock');
736 $this->handleUserSettings();
738 $active_id = $this->test_session->getActiveId();
739 $this->
ctrl->setParameter($this,
"active_id", $active_id);
741 $active_time_id = $this->
object->startWorkingTime($active_id, $this->test_session->getPass());
745 if ($this->
object->isRandomTest()) {
746 if (!$this->test_sequence->hasRandomQuestionsForPass($active_id, $this->test_session->getPass())) {
748 $this->generateRandomTestPassForActiveUser();
752 $shuffle = $this->
object->getShuffleQuestions();
753 if ($this->
object->isRandomTest()) {
757 $this->test_result_repository->updateTestAttemptResult(
759 $this->test_session->getPass(),
761 $this->object->getId()
765 if (!$this->test_sequence->hasSequence()) {
766 $this->test_sequence->createNewSequence($this->
object->getQuestionCount(), $shuffle);
767 $this->test_sequence->saveToDb();
770 if ($this->
object->getListOfQuestionsStart()) {
774 $this->
ctrl->setParameter($this,
'sequence', $this->test_session->getLastSequence());
775 $this->
ctrl->setParameter($this,
'pmode',
'');
784 if ($this->test_session->isAnonymousUser()
785 && !$this->test_session->doesAccessCodeInSessionExists()) {
786 $access_code = $this->test_session->createNewAccessCode();
788 $this->test_session->setAccessCodeToSession($access_code);
789 $this->test_session->setAnonymousId($access_code);
790 $this->test_session->saveToDb();
795 if (!$this->test_session->isAnonymousUser()) {
796 $this->test_session->unsetAccessCodeInSession();
803 $this->tpl->addBlockFile($this->getContentBlockName(),
"adm_content",
"tpl.il_as_tst_anonymous_code_presentation.html",
"components/ILIAS/Test");
804 $this->tpl->setCurrentBlock(
"adm_content");
805 $this->tpl->setVariable(
"TEXT_ANONYMOUS_CODE_CREATED", $this->
lng->txt(
"tst_access_code_created"));
806 $this->tpl->setVariable(
"TEXT_ANONYMOUS_CODE", $this->test_session->getAccessCodeFromSession());
807 $this->tpl->setVariable(
"FORMACTION", $this->
ctrl->getFormAction($this));
809 $this->tpl->setVariable(
"TXT_CONFIRM", $this->
lng->txt(
"continue_work"));
810 $this->tpl->parseCurrentBlock();
823 if ($this->
object->getNrOfTries() != 1
824 && $this->object->getUsePreviousAnswers() == 1
826 $chb_use_previous_answers = 0;
827 if ($this->post_wrapper->has(
'chb_use_previous_answers')) {
828 $chb_use_previous_answers = $this->post_wrapper->retrieve(
829 'chb_use_previous_answers',
833 $this->
user->writePref(
"tst_use_previous_answers", (
string) $chb_use_previous_answers);
843 $this->performTestPassFinishedTasks(StatusOfAttempt::FINISHED_BY_DURATION);
845 $this->redirectAfterFinish();
850 $this->performTestPassFinishedTasks(StatusOfAttempt::FINISHED_BY_DURATION);
852 $this->redirectAfterFinish();
859 $this->tpl->addBlockFile($this->getContentBlockName(),
"adm_content",
"tpl.il_as_tst_redirect_autosave.html",
"components/ILIAS/Test");
860 $this->tpl->setVariable(
"TEXT_REDIRECT", $this->
lng->txt(
"redirectAfterSave"));
861 $this->tpl->setVariable(
"URL",
$url);
866 return $this->test_sequence->getQuestionForSequence($this->testrequest->int(
'sequence'));
875 if (!$this->
access->checkAccess(
'read',
'', $this->ref_id)) {
876 echo $this->
lng->txt(
'autosave_failed') .
': ' . $this->
lng->txt(
'msg_no_perm_read_item');
879 $test_can_run = $this->
object->isExecutable($this->test_session, $this->test_session->getUserId());
880 if (!$test_can_run[
'executable']) {
881 echo $test_can_run[
'errormessage'];
884 if ($this->testrequest->getPostKeys() === []) {
889 if (!$this->canSaveResult() || $this->isParticipantsAnswerFixed($this->getCurrentQuestionId())) {
894 if ($this->saveQuestionSolution(!$this->getAnswerChangedParameter(),
true)) {
895 echo $this->
lng->txt(
'autosave_success');
899 echo $this->
lng->txt(
'autosave_failed');
909 if (!$this->isParticipantsAnswerFixed($this->getCurrentQuestionId())) {
910 $this->saveQuestionSolution(
false,
true);
924 $question_id = $this->getCurrentQuestionId();
925 $state = $this->getQuestionInstance($question_id)->lookupForExistingSolutions(
926 $this->test_session->getActiveId(),
927 $this->test_session->getPass()
930 $result[
'isAnswered'] = $state[
'authorized'];
931 $result[
'isAnswerChanged'] = $state[
'intermediate'];
933 echo json_encode($result);
940 $this->saveQuestionSolution(
false,
true);
942 $this->setAnswerChangedParameter(
true);
949 $this->handleIntermediateSubmit();
950 $this->markQuestionCmd();
958 $question_id = $this->test_sequence->getQuestionForSequence(
959 $this->getCurrentSequenceElement()
962 $this->
object->setQuestionSetSolved(1, $question_id, $this->test_session->getUserId());
970 $this->handleIntermediateSubmit();
972 $this->unmarkQuestionCmd();
980 $question_id = $this->test_sequence->getQuestionForSequence(
981 $this->getCurrentSequenceElement()
984 $this->
object->setQuestionSetSolved(0, $question_id, $this->test_session->getUserId());
991 $this->handleCheckTestPassValid();
994 if ($this->testrequest->strVal(
'finalization_confirmed') !==
'confirmed') {
995 $this->finish_test_modal = $this->buildFinishTestModal();
996 $this->showQuestionCmd();
1005 $this->performTestPassFinishedTasks(StatusOfAttempt::FINISHED_BY_PARTICIPANT);
1007 if ($this->
logger->isLoggingEnabled()
1008 && !$this->getObject()->getAnonymity()
1009 && ($interaction = $this->logger->getInteractionFactory()->buildParticipantInteraction(
1012 $this->user->getId(),
1013 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
1017 $this->
logger->logParticipantInteraction($interaction);
1026 $this->test_session,
1028 $this->test_result_repository
1029 ))->performFinishTasks($this->process_locker, $status_of_attempt);
1030 $this->test_result_repository->updateTestResultCache($this->test_session->getActiveId());
1036 if (!$this->testrequest->isset(
'skipfinalstatement')) {
1037 if ($this->
object->getMainSettings()->getFinishingSettings()->getConcludingRemarksEnabled()) {
1043 $redirection_mode = $this->
object->getMainSettings()->getFinishingSettings()->getRedirectionMode();
1044 $redirection_url = $this->
object->getMainSettings()->getFinishingSettings()->getRedirectionUrl();
1045 if (empty($redirection_url)
1046 || $this->
object->canShowTestResults($this->test_session)
1047 || $redirection_mode === RedirectionModes::NONE
1048 || $redirection_mode === RedirectionModes::IF_KIOSK_ACTIVATED && !$this->object->getKioskMode()) {
1049 $this->redirectBackCmd();
1061 $class = get_class($this);
1062 $this->
ctrl->setParameterByClass($class,
'finalization_confirmed',
'confirmed');
1064 $this->
ctrl->clearParameterByClass($class,
'finalization_confirmed');
1066 $message = $this->
lng->txt(
'tst_finish_confirmation_question');
1067 if (($this->
object->getNrOfTries() - 1) === $this->test_session->getPass()) {
1068 $message = $this->
lng->txt(
'tst_finish_confirmation_question_no_attempts_left');
1071 return $this->ui_factory->modal()->interruptive(
1072 $this->
lng->txt(
'finish_test'),
1075 )->withActionButtonLabel($this->
lng->txt(
'tst_finish_confirm_button'));
1081 $testPassesSelector->setActiveId($this->test_session->getActiveId());
1082 $testPassesSelector->setLastFinishedPass($this->test_session->getLastFinishedPass());
1084 if (count($testPassesSelector->getReportablePasses())) {
1085 if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
1086 $this->
ctrl->redirectByClass([
'ilTestResultsGUI',
'ilTestEvalObjectiveOrientedGUI']);
1089 $this->
ctrl->redirectByClass([ilTestResultsGUI::class, ilMyTestResultsGUI::class, ilTestEvaluationGUI::class]);
1092 $this->
ctrl->redirectByClass(TestScreenGUI::class, TestScreenGUI::DEFAULT_CMD);
1100 $this->global_screen->tool()->context()->current()->getAdditionalData()->replace(
1102 $this->
object->getTitle() .
' - ' . $this->lng->txt(
'final_statement')
1105 $this->content_style->gui()->addCss($this->tpl, $this->ref_id);
1106 $this->
ctrl->setParameterByClass(ilTestPageGUI::class,
'page_type',
'concludingremarkspage');
1107 $this->
ctrl->setParameterByClass(static::class,
'skipfinalstatement', 1);
1108 $this->tpl->setVariable(
1109 $this->getContentBlockName(),
1110 $this->ui_renderer->render([
1111 $this->ui_factory->legacy()->content(
1112 $this->object->prepareTextareaOutput($this->object->getFinalStatement(),
true)
1114 $this->ui_factory->button()->standard(
1115 $this->lng->txt(
'btn_next'),
1124 $this->navigation_history->addItem(
1125 $this->test_session->getRefId(),
1130 $this->initTestPageTemplate();
1131 $this->populateContentStyleBlock();
1132 $this->populateSyntaxStyleBlock();
1134 if ($this->isMaxProcessingTimeReached()) {
1135 $this->max_processing_time_reached();
1139 if ($this->
object->endingTimeReached()) {
1140 $this->endingTimeReached();
1144 if ($this->isOptionalQuestionAnsweringConfirmationRequired($sequenceElement)) {
1145 $this->
ctrl->setParameter($this,
"sequence", $sequenceElement);
1146 $this->showAnswerOptionalQuestionsConfirmation();
1150 $this->tpl->setVariable(
"TEST_ID", (
string) $this->
object->getTestId());
1151 $this->tpl->setVariable(
"LOGIN", $this->
user->getLogin());
1153 $this->tpl->setVariable(
"SEQ_ID", $sequenceElement);
1154 $this->tpl->setVariable(
"QUEST_ID", $question_id);
1156 if ($this->
object->getEnableProcessingTime()) {
1157 $this->outProcessingTime($this->test_session->getActiveId(),
false);
1160 $this->tpl->setVariable(
"PAGETITLE",
"- " . $this->
object->getTitle());
1162 if ($this->
object->isShowExamIdInTestPassEnabled() && !$this->object->getKioskMode()) {
1163 $this->tpl->setCurrentBlock(
'exam_id_footer');
1165 $this->test_session->getActiveId(),
1166 $this->test_session->getPass(),
1167 $this->object->getId()
1169 $this->tpl->setVariable(
'EXAM_ID_TXT', $this->
lng->txt(
'exam_id'));
1170 $this->tpl->parseCurrentBlock();
1173 if ($this->
object->getListOfQuestions()) {
1174 $this->showSideList($sequenceElement);
1180 if ($this->test_sequence->isAnsweringOptionalQuestionsConfirmed()) {
1184 $question_id = $this->test_sequence->getQuestionForSequence($sequence_key);
1186 if (!$this->test_sequence->isQuestionOptional($question_id)) {
1195 return $this->test_sequence->isPostponedQuestion($question_id);
1200 string $form_action,
1201 bool $is_question_worked_through,
1202 bool $instant_response
1204 $question_navigation_gui = $this->buildReadOnlyStateQuestionNavigationGUI($question_gui->getObject()->
getId());
1205 $question_navigation_gui->setQuestionWorkedThrough($is_question_worked_through);
1210 $this->test_session->getActiveId(),
1211 $this->test_session->getPass(),
1215 $instant_response && $this->object->getSpecificAnswerFeedback(),
1223 $this->isShowingPostponeStatusReguired($question_gui->
getObject()->getId()),
1224 $this->test_session->getActiveId(),
1228 $this->tpl->setVariable(
1229 'LOCKSTATE_INFOBOX',
1230 $this->ui_renderer->render(
1231 $this->ui_factory->messageBox()->info($this->lng->txt(
'tst_player_answer_saved_and_locked'))
1234 $this->tpl->parseCurrentBlock();
1235 $this->tpl->setVariable(
'QUESTION_OUTPUT', $pageoutput);
1236 $this->tpl->setVariable(
'FORMACTION', $form_action);
1237 $this->tpl->setVariable(
'ENCTYPE',
'enctype="' . $question_gui->
getFormEncodingType() .
'"');
1238 $this->tpl->setVariable(
'FORM_TIMESTAMP', time());
1239 $this->populateQuestionEditControl($question_gui);
1244 string $form_action,
1245 bool $is_question_worked_through,
1246 bool $instant_response
1248 $question_navigation_gui = $this->buildEditableStateQuestionNavigationGUI($question_gui->getObject()->
getId());
1249 $question_navigation_gui->setQuestionWorkedThrough($is_question_worked_through);
1250 if ($is_question_worked_through) {
1251 $question_navigation_gui->setDiscardSolutionButtonEnabled(
true);
1253 } elseif ($this->
object->isPostponingEnabled()) {
1254 $question_navigation_gui->setSkipQuestionLinkTarget(
1260 $user_post_solution =
false;
1261 if ($this->testrequest->isset(
'save_error')
1262 && $this->testrequest->int(
'save_error') === 1
1268 $question_config = $question_gui->
getObject()->getTestPresentationConfig();
1271 $question_config->setWorkedThrough($is_question_worked_through);
1274 if ($question_config->isPreviousPassSolutionReuseAllowed()) {
1275 $pass_index = $this->determineSolutionPassIndex($question_gui);
1276 if ($pass_index < $this->test_session->getPass()) {
1277 $question_config->setSolutionInitiallyPrefilled(
true);
1280 $pass_index = $this->test_session->getPass();
1284 $this->modal_signals = $this->populateModals();
1285 $question_navigation_gui->setShowDiscardModalSignal($this->modal_signals[self::DISCARD_MODAL]);
1289 $this->test_session->getActiveId(),
1291 $this->isShowingPostponeStatusReguired($question_gui->
getObject()->getId()),
1292 $user_post_solution,
1293 $instant_response && $this->object->getSpecificAnswerFeedback()
1296 $this->populateQuestionEditControl($question_gui);
1301 if ($this->
object->isPreviousSolutionReuseEnabled()) {
1302 $currentSolutionAvailable = $question_gui->
getObject()->authorizedOrIntermediateSolutionExists(
1303 $this->test_session->getActiveId(),
1304 $this->test_session->getPass()
1307 if (!$currentSolutionAvailable) {
1308 $previousPass = $question_gui->
getObject()->getSolutionMaxPass(
1309 $this->test_session->getActiveId()
1312 $previousSolutionAvailable = $question_gui->
getObject()->authorizedSolutionExists(
1313 $this->test_session->getActiveId(),
1317 if ($previousSolutionAvailable) {
1318 return $previousPass;
1324 return $this->test_session->getPass();
1333 $this->
object->startWorkingTime(
1334 $this->test_session->getActiveId(),
1335 $this->test_session->getPass()
1339 $this->
help->setScreenIdComponent(
'tst');
1340 $this->
help->setScreenId(
'assessment');
1341 $this->
help->setSubScreenId(
'question');
1343 $sequence_element = $this->getCurrentSequenceElement();
1345 if (!$this->isValidSequenceElement($sequence_element)) {
1346 $sequence_element = $this->test_sequence->getFirstSequence();
1349 $this->test_session->setLastSequence($sequence_element ?? 0);
1350 $this->test_session->saveToDb();
1352 $question_id = $this->test_sequence->getQuestionForSequence($sequence_element ?? 0);
1353 if ($question_id ===
null && $this->test_session->isObjectiveOriented()) {
1354 $this->handleTearsAndAngerNoObjectiveOrientedQuestion();
1357 if ($question_id !==
null && !$this->test_sequence->isQuestionPresented($question_id)) {
1358 $this->test_sequence->setQuestionPresented($question_id);
1359 $this->test_sequence->saveToDb();
1362 $question_worked_through = $this->questionrepository->lookupResultRecordExist(
1363 $this->test_session->getActiveId(),
1365 $this->test_session->getPass()
1368 $instant_response =
false;
1369 if ($this->isParticipantsAnswerFixed($question_id)) {
1371 $s = $this->
object->getMainSettings()->getQuestionBehaviourSettings();
1372 if ($s->getInstantFeedbackGenericEnabled()
1373 || $s->getInstantFeedbackPointsEnabled()
1374 || $s->getInstantFeedbackSolutionEnabled()
1375 || $s->getInstantFeedbackSpecificEnabled()) {
1376 $instant_response =
true;
1380 if (!$this->
object->isInstantFeedbackAnswerFixationEnabled()) {
1381 $instant_response = $this->getInstantResponseParameter();
1385 $question_gui = $this->getQuestionGuiInstance($question_id);
1388 $this->handleTearsAndAngerQuestionIsNull($question_id, $sequence_element);
1391 $question_gui->
setSequenceNumber($this->test_sequence->getPositionOfSequence($sequence_element));
1392 $question_gui->
setQuestionCount($this->test_sequence->getUserQuestionCount());
1395 $header_block_builder->setHeaderMode($this->
object->getTitleOutput());
1396 $header_block_builder->setQuestionTitle($question_gui->
getObject()->getTitleForHTMLOutput());
1397 $header_block_builder->setQuestionPoints($question_gui->
getObject()->getPoints());
1398 $header_block_builder->setQuestionPosition($this->test_sequence->getPositionOfSequence($sequence_element));
1399 $header_block_builder->setQuestionCount($this->test_sequence->getUserQuestionCount());
1400 $header_block_builder->setQuestionPostponed($this->test_sequence->isPostponedQuestion($question_id));
1401 if ($this->test_session->isObjectiveOriented()) {
1403 $objectives_adapter->buildQuestionRelatedObjectiveList($this->test_sequence, $this->question_related_objectives_list);
1404 $this->question_related_objectives_list->loadObjectivesTitles();
1406 $header_block_builder->setQuestionRelatedObjectives(
1407 $this->question_related_objectives_list->getQuestionRelatedObjectiveTitles($question_id)
1412 $this->prepareTestPage($presentation_mode, $sequence_element, $question_id);
1414 $navigation_toolbar_gui = $this->getTestNavigationToolbarGUI();
1415 $navigation_toolbar_gui->setFinishTestButtonEnabled(
true);
1417 $is_next_primary = $this->handlePrimaryButton($navigation_toolbar_gui, $question_id);
1419 $this->
ctrl->setParameter($this,
'sequence', $sequence_element);
1420 $this->
ctrl->setParameter($this,
'pmode', $presentation_mode);
1423 switch ($presentation_mode) {
1425 $navigation_toolbar_gui->setDisabledStateEnabled(
false);
1426 $this->showQuestionEditable(
1429 $question_worked_through,
1433 if ($this->
ctrl->getCmd() !== self::FINISH_TEST_CMD
1434 && $this->logger->isLoggingEnabled()
1435 && !$this->getObject()->getAnonymity()) {
1436 $this->
logger->logParticipantInteraction(
1437 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
1438 $this->object->getRefId(),
1440 $this->user->getId(),
1441 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
1442 TestParticipantInteractionTypes::QUESTION_SHOWN,
1450 if ($this->test_sequence->isQuestionOptional($question_gui->
getObject()->getId())) {
1451 $this->populateQuestionOptionalMessage();
1454 $this->showQuestionViewable(
1457 $question_worked_through,
1466 $navigation_toolbar_gui->build();
1467 $this->populateTestNavigationToolbar($navigation_toolbar_gui);
1468 $this->populateQuestionNavigation($sequence_element, $is_next_primary);
1470 if ($instant_response) {
1471 $this->populateInstantResponseBlocks(
1477 if ($this->isForcedFeedbackNavUrlRegistered()) {
1478 $this->populateInstantResponseModal($question_gui, $this->getRegisteredForcedFeedbackNavUrl());
1479 $this->unregisterForcedFeedbackNavUrl();
1491 if ($this->saveQuestionSolution(
true,
false)) {
1492 $question_id = $this->test_sequence->getQuestionForSequence(
1493 $this->getCurrentSequenceElement()
1496 $this->removeIntermediateSolution();
1498 if ($this->
object->isForceInstantFeedbackEnabled()) {
1499 $this->
ctrl->setParameter($this,
'instresp', 1);
1501 $this->test_sequence->setQuestionChecked($question_id);
1502 $this->test_sequence->saveToDb();
1505 if ($this->getNextCommandParameter()) {
1506 if ($this->getNextSequenceParameter()) {
1507 $this->
ctrl->setParameter($this,
'sequence', $this->getNextSequenceParameter());
1508 $this->
ctrl->setParameter($this,
'pmode',
'');
1511 $this->
ctrl->redirect($this, $this->getNextCommandParameter());
1520 $this->saveNavigationPreventConfirmation();
1524 if ($this->getNavigationUrlParameter()) {
1527 $this->
ctrl->saveParameter($this,
'sequence');
1536 $this->removeIntermediateSolution();
1537 $this->setAnswerChangedParameter(
false);
1538 $this->
ctrl->saveParameter($this,
'sequence');
1545 $current_sequence_element = $this->getCurrentSequenceElement();
1547 $current_question_obj = $this->getQuestionInstance(
1548 $this->test_sequence->getQuestionForSequence($current_sequence_element)
1550 $current_question_obj->setTestId($this->
object->getId());
1552 $current_question_obj->resetUsersAnswer(
1553 $this->test_session->getActiveId(),
1554 $this->test_session->getPass()
1557 if ($this->
logger->isLoggingEnabled()
1558 && !$this->getObject()->getAnonymity()) {
1559 $this->
logger->logParticipantInteraction(
1560 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
1561 $this->object->getRefId(),
1562 $this->test_sequence->getQuestionForSequence($current_sequence_element),
1563 $this->user->getId(),
1564 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
1565 TestParticipantInteractionTypes::ANSWER_DELETED,
1571 $this->
ctrl->saveParameter($this,
'sequence');
1580 $current_sequence_element = $this->getCurrentSequenceElement();
1581 $next_sequence_element = $this->test_sequence->getNextSequence($current_sequence_element);
1583 if (!$this->isValidSequenceElement($next_sequence_element)) {
1584 $next_sequence_element = $this->test_sequence->getFirstSequence();
1587 if ($this->
object->isPostponingEnabled()) {
1588 $this->test_sequence->postponeSequence($current_sequence_element);
1589 $this->test_sequence->saveToDb();
1592 if ($this->
logger->isLoggingEnabled()
1593 && !$this->getObject()->getAnonymity()) {
1594 $this->
logger->logParticipantInteraction(
1595 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
1596 $this->object->getRefId(),
1597 $this->test_sequence->getQuestionForSequence($current_sequence_element),
1598 $this->user->getId(),
1599 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
1600 TestParticipantInteractionTypes::QUESTION_SKIPPED,
1606 $this->
ctrl->setParameter($this,
'sequence', $next_sequence_element);
1607 $this->
ctrl->setParameter($this,
'pmode',
'');
1617 $this->test_session->setUserId($this->
user->getId());
1619 if ($access_code !=
null && isset($access_code[$this->
object->getTestId()])) {
1620 $this->test_session->setAnonymousId($access_code[$this->
object->getTestId()]);
1622 if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
1623 $this->test_session->setObjectiveOrientedContainerId($this->getObjectiveOrientedContainer()->getObjId());
1625 $this->test_session->saveToDb();
1627 $active_id = $this->test_session->getActiveId();
1628 $this->
ctrl->setParameter($this,
"active_id", $active_id);
1630 $shuffle = $this->
object->getShuffleQuestions();
1631 if ($this->
object->isRandomTest()) {
1632 $this->generateRandomTestPassForActiveUser();
1634 $this->
object->loadQuestions();
1638 $this->test_result_repository->updateTestAttemptResult(
1640 $this->test_session->getPass(),
1642 $this->object->getId()
1646 if (!$this->test_sequence->hasSequence()) {
1647 $this->test_sequence->createNewSequence($this->
object->getQuestionCount(), $shuffle);
1648 $this->test_sequence->saveToDb();
1651 $this->test_sequence->loadFromDb();
1652 $this->test_sequence->loadQuestions();
1654 if ($this->test_session->isObjectiveOriented()) {
1657 $objectivesAdapter->notifyTestStart($this->test_session, $this->
object->getId());
1658 $objectivesAdapter->prepareTestPass($this->test_session, $this->test_sequence);
1660 $objectivesAdapter->buildQuestionRelatedObjectiveList(
1661 $this->test_sequence,
1662 $this->question_related_objectives_list
1665 if ($this->test_sequence->hasOptionalQuestions()) {
1666 $this->adoptUserSolutionsFromPreviousPass();
1668 $this->test_sequence->reorderOptionalQuestionsToSequenceEnd();
1669 $this->test_sequence->saveToDb();
1673 $active_time_id = $this->
object->startWorkingTime(
1674 $this->test_session->getActiveId(),
1675 $this->test_session->getPass()
1679 $this->updateLearningProgressOnTestStart();
1681 $sequence_element = $this->test_sequence->getFirstSequence();
1683 $this->
ctrl->setParameter($this,
'sequence', $sequence_element);
1684 $this->
ctrl->setParameter($this,
'pmode',
'');
1686 if ($this->
logger->isLoggingEnabled()
1687 && !$this->getObject()->getAnonymity()) {
1688 $this->
logger->logParticipantInteraction(
1689 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
1690 $this->object->getRefId(),
1692 $this->user->getId(),
1693 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
1694 TestParticipantInteractionTypes::TEST_RUN_STARTED,
1700 if ($this->
object->getListOfQuestionsStart()) {
1701 $this->
ctrl->setParameterByClass(static::class,
'first',
'1');
1713 return !$this->isNrOfTriesReached()
1714 and !$this->isMaxProcessingTimeReached()
1715 and $this->
object->startingTimeReached()
1716 and !$this->
object->endingTimeReached();
1724 return $this->
object->hasNrOfTriesRestriction() && $this->
object->isNrOfTriesReached($this->test_session->getPass());
1735 $this->test_session->increasePass();
1736 $this->test_session->setLastSequence(0);
1737 $this->test_session->saveToDb();
1739 $this->redirectBackCmd();
1751 $this->suspendTestCmd();
1761 $this->tpl->addBlockFile($this->getContentBlockName(),
"adm_content",
"tpl.il_as_tst_submit_answers_confirm.html",
"components/ILIAS/Test");
1762 $this->tpl->setCurrentBlock(
"adm_content");
1763 if ($this->
object->isTestFinished($this->test_session->getActiveId())) {
1764 $this->tpl->setCurrentBlock(
"not_submit_allowed");
1765 $this->tpl->setVariable(
"TEXT_ALREADY_SUBMITTED", $this->
lng->txt(
"tst_already_submitted"));
1766 $this->tpl->setVariable(
"BTN_OK", $this->
lng->txt(
"tst_show_answer_sheet"));
1768 $this->tpl->setCurrentBlock(
"submit_allowed");
1769 $this->tpl->setVariable(
"TEXT_CONFIRM_SUBMIT_RESULTS", $this->
lng->txt(
"tst_confirm_submit_answers"));
1770 $this->tpl->setVariable(
"BTN_OK", $this->
lng->txt(
"tst_submit_results"));
1772 $this->tpl->setVariable(
"BTN_BACK", $this->
lng->txt(
"back"));
1773 $this->tpl->setVariable(
"FORMACTION", $this->
ctrl->getFormAction($this,
"finalSubmission"));
1774 $this->tpl->parseCurrentBlock();
1779 $starting_time = $this->
object->getStartingTimeOfUser($active_id);
1785 $this->
object->getProcessingTimeInSeconds($active_id)
1788 $this->tpl->setCurrentBlock(
'enableprocessingtime');
1789 $this->tpl->setVariable(
'USER_WORKING_TIME_MESSAGE_BOX', $working_time->getMessageBox($verbose));
1790 $this->tpl->parseCurrentBlock();
1792 $working_time_js_template = $working_time->prepareWorkingTimeJsTemplate(
1794 getdate($starting_time),
1795 $this->
ctrl->getLinkTarget($this,
'checkWorkingTime',
'',
true),
1799 $this->tpl->addOnLoadCode($working_time_js_template->get());
1811 $active_id = $this->test_session->getActiveId();
1812 echo (
string) $this->
object->getProcessingTimeInSeconds($active_id);
1818 $question_summary_data = $this->service->getQuestionSummaryData($this->test_sequence);
1822 foreach ($question_summary_data as $idx => $row) {
1823 $title = htmlspecialchars($row[
'title'], ENT_QUOTES,
null,
false);
1825 if ($row[
'description'] !==
'') {
1826 $description = htmlspecialchars($row[
'description'], ENT_QUOTES,
null,
false);
1829 if (!$row[
'disabled']) {
1830 $this->
ctrl->setParameter($this,
'pmode',
'');
1831 $this->
ctrl->setParameter($this,
'sequence', $row[
'sequence']);
1834 $this->
ctrl->setParameter($this,
'sequence', $this->getCurrentSequenceElement($current_sequence_element));
1840 ($row[
'worked_through'] || $row[
'isAnswered'])
1841 && $row[
'has_authorized_answer']
1846 $questions[] = $this->ui_factory->listing()->workflow()
1847 ->step($title, $description, $action)
1848 ->withStatus($status);
1849 $active = $row[
'sequence'] == $current_sequence_element ? $idx : $active;
1852 $question_listing = $this->ui_factory->listing()->workflow()->linear(
1853 $this->
lng->txt(
'mainbar_button_label_questionlist'),
1855 )->withActive($active);
1858 $this->global_screen->tool()->context()->current()->addAdditionalData(
1869 $this->
help->setScreenIdComponent(
'tst');
1870 $this->
help->setScreenId(
'assessment');
1871 $this->
help->setSubScreenId(
'question_summary');
1873 $is_first_page = $this->testrequest->strVal(
'first') ===
'1';
1875 $this->tpl->addBlockFile(
1876 $this->getContentBlockName(),
1878 'tpl.il_as_tst_question_summary.html',
1879 'components/ILIAS/Test'
1882 $this->global_screen->tool()->context()->current()->getAdditionalData()->replace(
1884 $this->getObject()->
getTitle() .
' - ' . $this->
lng->txt(
'question_summary')
1887 $active_id = $this->test_session->getActiveId();
1888 $question_summary_data = $this->service->getQuestionSummaryData($this->test_sequence);
1890 $this->
ctrl->setParameter($this,
'sequence', $this->testrequest->raw(
'sequence'));
1900 $question_summary_data
1902 $this->tpl->setVariable(
'TABLE_LIST_OF_QUESTIONS', $this->ui_renderer->render($table->buildComponents($is_first_page)));
1904 if ($this->
object->getEnableProcessingTime()) {
1905 $this->outProcessingTime($active_id,
true);
1908 if ($this->
object->isShowExamIdInTestPassEnabled()) {
1909 $this->tpl->setCurrentBlock(
'exam_id_footer');
1911 $this->test_session->getActiveId(),
1912 $this->test_session->getPass(),
1913 $this->object->getId()
1915 $this->tpl->setVariable(
'EXAM_ID_TXT', $this->
lng->txt(
'exam_id'));
1916 $this->tpl->parseCurrentBlock();
1930 $this->tpl->addBlockFile(
"ADM_CONTENT",
"adm_content",
"tpl.il_as_tst_correct_solution.html",
"components/ILIAS/Test");
1932 $this->tpl->setCurrentBlock(
"ContentStyle");
1934 $this->tpl->parseCurrentBlock();
1936 $this->tpl->setCurrentBlock(
"SyntaxStyle");
1938 $this->tpl->parseCurrentBlock();
1941 if ($this->
object->getShowSolutionAnswersOnly()) {
1945 $this->tpl->setCurrentBlock(
"adm_content");
1946 $solution = $this->getCorrectSolutionOutput($this->testrequest->raw(
"evaluation"), $this->testrequest->raw(
"active_id"), $this->testrequest->raw(
"pass"));
1947 $this->tpl->setVariable(
"OUTPUT_SOLUTION", $solution);
1948 $this->tpl->setVariable(
"TEXT_BACK", $this->
lng->txt(
"back"));
1949 $this->
ctrl->saveParameter($this,
"pass");
1950 $this->
ctrl->saveParameter($this,
"active_id");
1951 $this->tpl->setVariable(
"URL_BACK", $this->
ctrl->getLinkTarget($this,
"outUserResultsOverview"));
1952 $this->tpl->parseCurrentBlock();
1966 $this->tpl->addBlockFile($this->getContentBlockName(),
"adm_content",
"tpl.il_as_tst_finish_list_of_answers.html",
"components/ILIAS/Test");
1968 $result_array = $this->
object->getTestResult(
1972 !$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()
1977 foreach ($result_array as $question_data) {
1978 $question = $question_data[
"qid"];
1979 if (is_numeric($question)) {
1980 $this->tpl->setCurrentBlock(
"printview_question");
1981 $question_gui = $this->
object->createQuestionGUI(
"", $question);
1982 $template =
new ilTemplate(
"tpl.il_as_qpl_question_printview.html",
true,
true,
"components/ILIAS/TestQuestionPool");
1983 $template->setVariable(
"COUNTER_QUESTION",
$counter .
". ");
1984 $template->setVariable(
"QUESTION_TITLE", $question_gui->
getObject()->getTitleForHTMLOutput());
1986 $show_question_only = ($this->
object->getShowSolutionAnswersOnly()) ?
true :
false;
1992 $show_question_only,
1993 $this->
object->getShowSolutionFeedback()
1995 $template->setVariable(
"SOLUTION_OUTPUT", $result_output);
1996 $this->tpl->setVariable(
"QUESTION_OUTPUT", $template->get());
1997 $this->tpl->parseCurrentBlock();
2003 if ($this->
object->getShowSolutionAnswersOnly()) {
2006 if (strlen($top_data)) {
2007 $this->tpl->setCurrentBlock(
"top_data");
2008 $this->tpl->setVariable(
"TOP_DATA", $top_data);
2009 $this->tpl->parseCurrentBlock();
2012 if (strlen($bottom_data)) {
2013 $this->tpl->setCurrentBlock(
"bottom_data");
2014 $this->tpl->setVariable(
"FORMACTION", $this->
ctrl->getFormAction($this));
2015 $this->tpl->setVariable(
"BOTTOM_DATA", $bottom_data);
2016 $this->tpl->parseCurrentBlock();
2019 $this->tpl->setCurrentBlock(
"adm_content");
2020 $this->tpl->setVariable(
"TXT_ANSWER_SHEET", $this->
lng->txt(
"tst_list_of_answers"));
2021 $user_data = $this->getAdditionalUsrDataHtmlAndPopulateWindowTitle($this->test_session, $active_id,
true);
2022 $signature = $this->getResultsSignature();
2023 $this->tpl->setVariable(
"USER_DETAILS", $user_data);
2024 $this->tpl->setVariable(
"SIGNATURE", $signature);
2025 $this->tpl->setVariable(
"TITLE", $this->
object->getTitle());
2026 $this->tpl->setVariable(
"TXT_TEST_PROLOG", $this->
lng->txt(
"tst_your_answers"));
2027 $invited_user = &$this->
object->getInvitedUsers($this->
user->getId());
2028 $pagetitle = $this->
object->getTitle() .
' - ' . $this->
lng->txt(
'clientip') .
2029 ': ' .
$_SERVER[
'REMOTE_ADDR'] .
' - ' .
2030 $this->
lng->txt(
'matriculation') .
': ' .
2031 $invited_user[$this->
user->getId()][
'matriculation'];
2032 $this->tpl->setVariable(
'PAGETITLE', $pagetitle);
2033 $this->tpl->parseCurrentBlock();
2043 return "ADM_CONTENT";
2045 if ($this->
object->getKioskMode()) {
2046 $this->tpl->setBodyClass(
"kiosk");
2047 $this->tpl->hideFooter();
2050 return "ADM_CONTENT";
2056 $this->
ctrl->redirectByClass(
2057 [ilRepositoryGUI::class, ilObjTestGUI::class, ilTestEvaluationGUI::class],
2058 "outUserResultsOverview"
2065 return $sequence_element == $this->test_sequence->getFirstSequence();
2070 return $sequence_element == $this->test_sequence->getLastSequence();
2075 $question_id = $this->test_sequence->getQuestionForSequence(
2076 $this->getCurrentSequenceElement()
2079 if (!$this->isParticipantsAnswerFixed($question_id)) {
2080 $this->updateWorkingTime();
2081 $this->saveQuestionSolution(
false);
2083 $this->setAnswerChangedParameter(
true);
2092 $question_id = $this->test_sequence->getQuestionForSequence(
2093 $this->getCurrentSequenceElement()
2096 if (!$this->isParticipantsAnswerFixed($question_id)) {
2097 if ($this->saveQuestionSolution(
true)) {
2098 $this->removeIntermediateSolution();
2099 $this->setAnswerChangedParameter(
false);
2103 $this->test_sequence->setQuestionChecked($question_id);
2104 $this->test_sequence->saveToDb();
2105 } elseif ($this->
object->isForceInstantFeedbackEnabled()) {
2106 $this->test_sequence->setQuestionChecked($question_id);
2107 $this->test_sequence->saveToDb();
2110 $this->
ctrl->setParameter($this,
'instresp', 1);
2113 if ($this->getNavigationUrlParameter()) {
2114 $this->saveNavigationPreventConfirmation();
2115 $this->registerForcedFeedbackNavUrl($this->getNavigationUrlParameter());
2123 $this->handleCheckTestPassValid();
2124 $last_sequence_element = $this->getCurrentSequenceElement();
2125 $next_sequence_element = $this->test_sequence->getNextSequence($last_sequence_element);
2127 $question_id = $this->test_sequence->getQuestionForSequence($last_sequence_element);
2128 $is_worked_through = $this->questionrepository->lookupResultRecordExist(
2129 $this->test_session->getActiveId(),
2131 $this->test_session->getPass()
2134 if (!$is_worked_through) {
2135 if ($this->
logger->isLoggingEnabled()
2136 && !$this->getObject()->getAnonymity()) {
2137 $this->
logger->logParticipantInteraction(
2138 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
2139 $this->object->getRefId(),
2141 $this->user->getId(),
2142 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
2143 TestParticipantInteractionTypes::QUESTION_SKIPPED,
2148 if ($this->
object->isPostponingEnabled()) {
2149 $this->handleQuestionPostponing($question_id);
2153 if (!$this->isValidSequenceElement($next_sequence_element)) {
2154 $next_sequence_element = $this->test_sequence->getFirstSequence();
2157 $this->
ctrl->setParameter($this,
'sequence', $next_sequence_element);
2158 $this->
ctrl->setParameter($this,
'pmode',
'');
2165 $this->handleCheckTestPassValid();
2167 $sequence_element = $this->test_sequence->getPreviousSequence(
2168 $this->getCurrentSequenceElement()
2171 if (!$this->isValidSequenceElement($sequence_element)) {
2172 $sequence_element = $this->test_sequence->getLastSequence();
2175 $this->
ctrl->setParameter($this,
'sequence', $sequence_element);
2176 $this->
ctrl->setParameter($this,
'pmode',
'');
2183 $this->tpl->addBlockFile(
2184 $this->getContentBlockName(),
2186 'tpl.il_as_tst_question_summary.html',
2187 'components/ILIAS/Test'
2194 let key_event = (
event) => {
2195 if(
event.key === 13 &&
event.target.tagName.toLowerCase() ===
"a" ) {
2198 if (
event.key === 13 &&
2199 event.target.tagName.toLowerCase() !==
"textarea" &&
2200 (
event.target.tagName.toLowerCase() !==
"input" ||
event.target.type.toLowerCase() !==
"submit")) {
2201 event.preventDefault();
2205 let
form = document.getElementById(
'taForm');
2206 form.onkeyup = key_event;
2207 form.onkeydown = key_event;
2208 form.onkeypress = key_event;
2210 $this->tpl->addOnLoadCode($onload_js);
2211 $this->tpl->addBlockFile(
2212 $this->getContentBlockName(),
2214 'tpl.il_as_tst_output.html',
2215 'components/ILIAS/Test'
2227 if ($this->test_session->isPasswordChecked() ===
true) {
2231 if ($this->
ctrl->getNextClass() ===
'iltestpasswordprotectiongui') {
2235 if (!$this->password_checker->isPasswordProtectionPageRedirectRequired()) {
2236 $this->test_session->setPasswordChecked(
true);
2240 $this->
ctrl->setParameterByClass(self::class,
'lock', $this->getLockParameter());
2243 $this->
ctrl->setParameterByClass(ilTestPasswordProtectionGUI::class,
'nextCommand', $next_command);
2244 $this->
ctrl->redirectByClass(ilTestPasswordProtectionGUI::class,
'showPasswordForm');
2249 if ($this->
object->isInstantFeedbackAnswerFixationEnabled()) {
2250 return $this->test_sequence->isQuestionChecked($question_id);
2253 if ($this->
object->isFollowupQuestionAnswerFixationEnabled()) {
2254 return $this->isForcedFeedbackNavUrlRegistered() || $this->test_sequence->isNextQuestionPresented($question_id);
2265 return $this->
lng->txt(
"save_introduction");
2270 $this->ass_settings =
new ilSetting(
'assessment');
2281 $this->
object->getTestId(),
2282 $this->object->getRefId(),
2283 $this->skills_service->profile(),
2284 $this->skills_service->personal()
2287 $skill_evaluation->setUserId($test_session->
getUserId());
2288 $skill_evaluation->setActiveId($test_session->
getActiveId());
2289 $skill_evaluation->setPass($test_session->
getPass());
2291 $skill_evaluation->setNumRequiredBookingsForSkillTriggering(
2292 $this->
object->getGlobalSettings()->getSkillTriggeringNumberOfAnswers()
2295 $question_list = $this->buildTestPassQuestionList();
2296 $question_list->load();
2297 $skill_evaluation->init($question_list);
2298 $skill_evaluation->evaluate(
2299 $this->
object->getTestResult(
2306 $skill_evaluation->handleSkillTriggering();
2313 $confirmation->setFormAction($this->
ctrl->getFormAction($this));
2314 $confirmation->setCancelCmd(
'cancelAnswerOptionalQuestions');
2315 $confirmation->setConfirmCmd(
'confirmAnswerOptionalQuestions');
2317 $confirmation->build($this->
object->isFixedTest());
2319 $this->populateHelperGuiContent($confirmation);
2324 $this->test_sequence->setAnsweringOptionalQuestionsConfirmed(
true);
2325 $this->test_sequence->saveToDb();
2327 $this->
ctrl->setParameter($this,
'activecommand',
'gotoquestion');
2328 $this->
ctrl->redirect($this,
'redirectQuestion');
2333 if ($this->
object->getListOfQuestions()) {
2334 $this->
ctrl->setParameter($this,
'activecommand',
'summary');
2336 $this->
ctrl->setParameter($this,
'activecommand',
'previous');
2339 $this->
ctrl->redirect($this,
'redirectQuestion');
2347 $this->tpl->setVariable($this->getContentBlockName(), $this->
ctrl->getHTML($helperGui));
2353 $navigation_toolbar->setSuspendTestButtonEnabled($this->
object->getShowCancel());
2354 $navigation_toolbar->setUserPassOverviewEnabled($this->
object->getUsrPassOverviewEnabled());
2355 $navigation_toolbar->setFinishTestCommand($this->getFinishTestCommand());
2356 return $navigation_toolbar;
2367 if (!$this->isParticipantsAnswerFixed($question_id)) {
2371 if ($this->
object->getShowMarker()) {
2375 if (count($solved_array) > 0) {
2376 $solved = array_pop($solved_array);
2377 $solved = $solved[
"solved"];
2382 $navigationGUI->setQuestionMarked(
true);
2385 $navigationGUI->setQuestionMarked(
false);
2390 return $navigationGUI;
2404 if ($this->
object->getSpecificAnswerFeedback()
2405 || $this->object->getGenericAnswerFeedback()
2406 || $this->object->getAnswerFeedbackPoints()
2407 || $this->object->getInstantFeedbackSolution()) {
2408 $navigation_gui->setAnswerFreezingEnabled($this->
object->isInstantFeedbackAnswerFixationEnabled());
2410 if ($this->
object->isForceInstantFeedbackEnabled()) {
2411 $navigation_gui->setForceInstantResponseEnabled(
true);
2418 if ($this->
object->getShowMarker()) {
2422 if (count($solved_array) > 0) {
2423 $solved = array_pop($solved_array);
2424 $solved = $solved[
'solved'];
2427 if ($solved === 1) {
2429 $navigation_gui->setQuestionMarked(
true);
2432 $navigation_gui->setQuestionMarked(
false);
2435 return $navigation_gui;
2440 if (!$this->
object->getListOfQuestionsEnd()) {
2452 $answer_feedback_enabled = $this->
object->getSpecificAnswerFeedback();
2455 $this->test_session->getActiveId(), #active_id
2456 $this->test_session->getPass(), #pass
2457 false, #graphical_output
2458 false, #result_output
2459 true, #show_question_only
2460 $answer_feedback_enabled, #show_feedback
2461 false, #show_correct_solution
2462 false, #show_manual_scoring
2463 true #show_question_text
2468 $this->isShowingPostponeStatusReguired($question_gui->
getObject()->getId()),
2469 $this->test_session->getActiveId(),
2473 $tpl =
new ilTemplate(
'tpl.tst_player_response_modal.html',
true,
true,
'components/ILIAS/Test');
2476 $saved_tpl = $this->tpl;
2478 $this->populateInstantResponseBlocks($question_gui,
true);
2479 $this->tpl = $saved_tpl;
2481 $tpl->setVariable(
'QUESTION_OUTPUT', $pageoutput);
2482 $this->tpl->setVariable(
'INSTANT_RESPONSE_MODAL', $this->getQuestionFeedbackModalHtml($tpl, $nav_url));
2487 $modal = $this->ui_factory->modal()->roundtrip(
2488 $this->
lng->txt(
'tst_instant_feedback'),
2489 $this->ui_factory->legacy()->content($tpl->
get()),
2491 )->withActionButtons([
2492 $this->ui_factory->button()->standard($this->lng->txt(
'proceed'), $nav_url)
2495 return $this->ui_renderer->render([
2496 $modal->withOnLoad($modal->getShowSignal())
2506 $response_available =
false;
2507 $jump_to_response =
false;
2511 if ($this->
object->getInstantFeedbackSolution()) {
2512 $show_question_inline_score = $this->determineInlineScoreDisplay();
2516 $this->test_session->getActiveId(), #active_id
2517 $this->test_session->getPass(), #pass
2518 false, #graphical_output
2519 $show_question_inline_score, #result_output
2520 true, #show_question_only
2521 false, #show_feedback
2522 true, #show_correct_solution
2523 false, #show_manual_scoring
2524 false #show_question_text
2526 $solutionoutput = str_replace(
'<h1 class="ilc_page_title_PageTitle"></h1>',
'', $solutionoutput);
2527 $this->populateSolutionBlock($solutionoutput);
2528 $response_available =
true;
2529 $jump_to_response =
true;
2532 $reachedPoints = $question_gui->
getObject()->getAdjustedReachedPoints(
2533 $this->test_session->getActiveId(),
2538 $maxPoints = $question_gui->
getObject()->getMaximumPoints();
2540 $solutionCorrect = ($reachedPoints == $maxPoints);
2544 if ($this->
object->getAnswerFeedbackPoints()) {
2545 $this->populateScoreBlock($reachedPoints, $maxPoints);
2546 $response_available =
true;
2547 $jump_to_response =
true;
2552 if ($this->
object->getGenericAnswerFeedback()) {
2553 if ($this->populateGenericFeedbackBlock($question_gui, $solutionCorrect)) {
2554 $response_available =
true;
2555 $jump_to_response =
true;
2561 if ($this->
object->getSpecificAnswerFeedback()) {
2564 $jump_to_response =
false;
2565 } elseif ($this->populateSpecificFeedbackBlock($question_gui)) {
2566 $response_available =
true;
2567 $jump_to_response =
true;
2571 $this->populateFeedbackBlockHeader($jump_to_response);
2572 if (!$response_available) {
2574 $this->populateFeedbackBlockMessage($this->
lng->txt(
'tst_feedback_is_given_inline'));
2576 $this->populateFeedbackBlockMessage($this->
lng->txt(
'tst_feedback_not_available_for_answer'));
2583 if ($withFocusAnchor) {
2584 $this->tpl->setCurrentBlock(
'inst_resp_id');
2585 $this->tpl->setVariable(
'INSTANT_RESPONSE_FOCUS_ID',
'focus');
2586 $this->tpl->parseCurrentBlock();
2589 $this->tpl->setCurrentBlock(
'instant_response_header');
2590 $this->tpl->setVariable(
'INSTANT_RESPONSE_HEADER', $this->
lng->txt(
'tst_feedback'));
2591 $this->tpl->parseCurrentBlock();
2596 $this->tpl->setCurrentBlock(
'instant_response_message');
2597 $this->tpl->setVariable(
'INSTANT_RESPONSE_MESSAGE', $a_message);
2598 $this->tpl->parseCurrentBlock();
2604 if ($this->getSequenceElementParameter()) {
2605 return $this->getSequenceElementParameter();
2608 return $this->test_session->getLastSequence();
2613 if ($this->testrequest->isset(
'sequence')) {
2614 return $this->testrequest->int(
'sequence');
2622 if ($this->testrequest->isset(
'pmode')) {
2623 return $this->testrequest->raw(
'pmode');
2631 return $this->testrequest->isInstanceResponseRequested();
2637 if ($this->testrequest->isset(
'nextcmd')) {
2638 $nextcmd = $this->testrequest->strVal(
'nextcmd');
2641 return $nextcmd !==
'' ? $nextcmd :
null;
2646 return $this->testrequest->int(
'nextseq');
2651 $navigation_url = $this->testrequest->strVal(
'test_player_navigation_url');
2652 if ($navigation_url !==
'') {
2653 $navigation_url_parts = parse_url($navigation_url);
2656 if (!isset($navigation_url_parts[
'host']) || ($ilias_url_parts[
'host'] === $navigation_url_parts[
'host'])) {
2657 return $navigation_url;
2665 return !empty($this->testrequest->raw(
'test_answer_changed'));
2670 $this->
ctrl->setParameter($this,
'test_answer_changed', $changed ?
'1' :
'0');
2675 if ($this->getAnswerChangedParameter()) {
2676 $this->saveQuestionSolution(
false);
2678 $this->removeIntermediateSolution();
2680 $this->setAnswerChangedParameter($this->getAnswerChangedParameter());
2685 if ($this->testrequest->retrieveBoolFromPost(
'save_on_navigation_prevent_confirmation')) {
2689 if ($this->testrequest->retrieveBoolFromPost(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM)) {
2690 ilSession::set(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM,
true);
2698 if (!$from_cache || !isset($this->cached_question_guis[$question_id])) {
2699 $question_gui = $this->
object->createQuestionGUI(
"", $question_id);
2703 $question->setShuffler($this->shuffler->getAnswerShuffleFor(
2705 $this->test_session->getActiveId(),
2706 $this->test_session->getPass()
2712 $this->initTestQuestionConfig($question_gui->
getObject());
2715 $this->cached_question_guis[$question_id] = $question_gui;
2718 return $this->cached_question_guis[$question_id];
2723 if ($from_cache && isset($this->cached_question_objects[$question_id])) {
2724 return $this->cached_question_objects[$question_id];
2727 $ass_settings =
new ilSetting(
'assessment');
2730 $process_locker_factory->setQuestionId($question->getId());
2731 $process_locker_factory->setUserId($this->
user->getId());
2732 $question->setProcessLocker($process_locker_factory->getLocker());
2734 $this->initTestQuestionConfig($question);
2736 $this->cached_question_objects[$question_id] = $question;
2743 $this->
object->isPreviousSolutionReuseEnabled()
2751 .
"active={$this->test_session->getActiveId()} "
2752 .
"qId=$question_id seq=$sequence_element "
2753 . serialize($this->test_sequence)
2756 $this->
ctrl->setParameter($this,
'sequence', $this->test_sequence->getFirstSequence());
2762 if ($this->
object->getKioskMode()) {
2763 $this->tpl->addBlockfile($this->getContentBlockName(),
'content',
"tpl.il_as_tst_kiosk_mode_content.html",
"components/ILIAS/Test");
2764 $this->tpl->setContent($content_html);
2767 $this->tpl->setVariable($this->getContentBlockName(), $content_html);
2775 $signals = [self::DISCARD_MODAL => $this->populateDiscardSolutionModal()];
2777 if ($this->
object->isFollowupQuestionAnswerFixationEnabled()) {
2778 $signals[self::LOCKS_CHANGED_MODAL] = $this->populateNextLocksChangedModal();
2779 $signals[self::LOCKS_UNCHANGED_MODAL] = $this->populateNextLocksUnchangedModal();
2787 $modal = $this->ui_factory->modal()->interruptive(
2788 $this->
lng->txt(
'discard_answer'),
2789 $this->lng->txt(
'discard_answer_confirmation'),
2791 )->withActionButtonLabel($this->
lng->txt(
'discard_answer'));
2793 $this->tpl->setCurrentBlock(
'discard_solution_modal');
2794 $this->tpl->setVariable(
'DISCARD_SOLUTION_MODAL', $this->ui_renderer->render($modal));
2795 $this->tpl->parseCurrentBlock();
2796 return $modal->getShowSignal();
2801 $modal = $this->ui_factory->modal()->interruptive(
2802 $this->
lng->txt(
'tst_nav_next_locks_empty_answer_header'),
2803 $this->lng->txt(
'tst_nav_next_locks_empty_answer_confirm'),
2804 'javascript:il.TestPlayerQuestionEditControl.confirmNextLocksUnchanged()'
2805 )->withActionButtonLabel($this->
lng->txt(
'tst_proceed'));
2807 $this->tpl->setCurrentBlock(
'next_locks_unchanged_modal');
2808 $this->tpl->setVariable(
'NEXT_LOCKS_UNCHANGED_MODAL', $this->ui_renderer->render($modal));
2809 $this->tpl->parseCurrentBlock();
2810 return $modal->getShowSignal();
2815 $empty_signal = new \ILIAS\UI\Implementation\Component\Signal(
'');
2816 if ($this->isFollowUpQuestionLocksConfirmationPrevented()) {
2817 return $empty_signal;
2820 $modal_message = $this->ui_factory->messageBox()->confirmation(
2821 $this->
lng->txt(
'tst_nav_next_locks_current_answer_confirm')
2823 $modal_checkbox = $this->ui_factory->input()->field()->checkbox(
2824 $this->
lng->txt(
'tst_dont_show_msg_again_in_current_session')
2825 )->withDedicatedName(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM);
2827 $modal = $this->ui_factory->modal()->roundtrip(
2828 $this->
lng->txt(
'tst_nav_next_locks_current_answer_header'),
2830 [ $modal_checkbox ],
2831 'javascript:il.TestPlayerQuestionEditControl.confirmNextLocksChanged()'
2832 )->withSubmitLabel($this->
lng->txt(
'tst_proceed'));
2834 $this->tpl->setCurrentBlock(
'next_locks_changed_modal');
2835 $this->tpl->setVariable(
'NEXT_LOCKS_CHANGED_MODAL', $this->ui_renderer->render($modal));
2836 $this->tpl->parseCurrentBlock();
2837 return $modal->getShowSignal();
2840 public const FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM =
'followup_qst_locks_prevent_confirmation';
2844 ilSession::set(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM,
true);
2849 if (
ilSession::get(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM) ==
null) {
2853 return ilSession::get(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM);
2859 $state = $question_gui->
getObject()->lookupForExistingSolutions($this->test_session->getActiveId(), $this->test_session->getPass());
2860 $config[
'isAnswered'] = $state[
'authorized'];
2861 $config[
'isAnswerChanged'] = $state[
'intermediate'] || $this->getAnswerChangedParameter();
2862 $config[
'isAnswerFixed'] = $this->isParticipantsAnswerFixed($question_gui->
getObject()->getId());
2865 $config[
'autosaveUrl'] =
'';
2866 $config[
'autosaveInterval'] = 0;
2869 $config[
'autosaveInterval'] = $this->
object->getMainSettings()->getQuestionBehaviourSettings()->getAutosaveInterval();
2872 $question_config = $question_gui->
getObject()->getTestPresentationConfig();
2874 $config[
'withFormChangeDetection'] = $question_config->isFormChangeDetectionEnabled();
2877 $config[
'withBackgroundChangeDetection'] = $question_config->isBackgroundChangeDetectionEnabled();
2881 $config[
'forcedInstantFeedback'] = $this->
object->isForceInstantFeedbackEnabled();
2882 $config[
'questionLocked'] = $this->isParticipantsAnswerFixed($question_gui->
getObject()->getId());
2883 $config[
'nextQuestionLocks'] = $this->
object->isFollowupQuestionAnswerFixationEnabled();
2884 $config[
'autosaveFailureMessage'] = $this->
lng->txt(
'autosave_failed');
2887 $config[
'modalSignals'] = array_map(fn(
Signal $signal) => $signal->
getId(), $this->modal_signals);
2888 $config[
'preventConfirmationParam'] = self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM;
2890 $this->tpl->addJavascript(
'assets/js/ilTestPlayerQuestionEditControl.js');
2891 $this->tpl->addOnLoadCode(
'il.TestPlayerQuestionEditControl.init(' . json_encode($config) .
')');
2897 return self::PRESENTATION_MODE_EDIT;
2905 $forced_feeback_navigation_url =
ilSession::get(
'forced_feedback_navigation_url');
2906 $forced_feeback_navigation_url[$this->test_session->getActiveId()] = $forced_feedback_nav_url;
2907 ilSession::set(
'forced_feedback_navigation_url', $forced_feeback_navigation_url);
2915 $forced_feedback_navigation_url =
ilSession::get(
'forced_feedback_navigation_url');
2916 if (!isset($forced_feedback_navigation_url[$this->test_session->getActiveId()])) {
2920 return $forced_feedback_navigation_url[$this->test_session->getActiveId()];
2925 return $this->getRegisteredForcedFeedbackNavUrl() !==
null;
2930 $forced_feedback_navigation_url =
ilSession::get(
'forced_feedback_navigation_url');
2931 if (isset($forced_feedback_navigation_url[$this->test_session->getActiveId()])) {
2932 unset($forced_feedback_navigation_url[$this->test_session->getActiveId()]);
2933 ilSession::set(
'forced_feedback_navigation_url', $forced_feedback_navigation_url);
2939 $this->updateWorkingTime();
2940 $this->saveQuestionSolution(
false);
2951 if ($sequence_element ===
false) {
2955 if ($sequence_element < 1) {
2959 if (!$this->test_sequence->getPositionOfSequence($sequence_element)) {
2968 if ($this->
object->isForceInstantFeedbackEnabled()) {
2969 $this->submitSolutionCmd();
2973 if ($this->saveQuestionSolution(
true,
false)) {
2974 $this->test_sequence->getQuestionForSequence(
2975 $this->getCurrentSequenceElement()
2978 $this->removeIntermediateSolution();
2980 $next_sequence_element = $this->test_sequence->getNextSequence($this->getCurrentSequenceElement());
2982 if (!$this->isValidSequenceElement($next_sequence_element)) {
2983 $next_sequence_element = $this->test_sequence->getFirstSequence();
2986 $this->test_session->setLastSequence($next_sequence_element ?? 0);
2987 $this->test_session->saveToDb();
2989 $this->
ctrl->setParameter($this,
'sequence', $next_sequence_element);
2990 $this->
ctrl->setParameter($this,
'pmode',
'');
2999 $this->test_sequence->postponeQuestion($question_id);
3000 $this->test_sequence->saveToDb();
3005 $testObj =
new ilObjTest($this->ref_id,
true);
3007 $participants = $testObj->getActiveParticipantList();
3008 $participant = $participants->getParticipantByActiveId($this->testrequest->getActiveId());
3009 if ($participant && $participant->hasUnfinishedPasses()) {
3012 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
'tst_current_run_no_longer_valid'),
true);
3013 if ($with_redirect) {
3014 $this->
ctrl->redirectByClass([
3015 ilRepositoryGUI::class,
3016 ilObjTestGUI::class,
3017 TestScreenGUI::class
3024 if ($this->test_session->getActiveId() > 0) {
3025 if ($this->test_sequence->hasRandomQuestionsForPass($this->test_session->getActiveId(), $this->test_session->getPass()) > 0) {
3027 __METHOD__ .
' Random Questions allready exists for user ' .
3028 $this->
user->getId() .
' in test ' . $this->object->getTestId()
3034 $this->
logger->info(__METHOD__ .
' ' . sprintf(
3035 $this->
lng->txt(
"error_random_question_generation"),
3036 $this->user->getId(),
3037 $this->object->getTestId()
3053 $this->component_repository,
3055 $this->questionrepository
3057 $questionSetConfig->loadFromDb();
3062 $sourcePoolDefinitionList->loadDefinitions();
3064 $this->process_locker->executeRandomPassBuildOperation(
function () use ($questionSetConfig, $sourcePoolDefinitionList) {
3065 if (!$this->performTearsAndAngerBrokenConfessionChecks()) {
3074 $sourcePoolDefinitionList,
3075 $stagingPoolQuestionList
3078 $questionSetBuilder->performBuild($this->test_session);
3080 }, $sourcePoolDefinitionList->hasTaxonomyFilters());
3085 $ass_settings =
new ilSetting(
'assessment');
3088 $userSolutionAdopter->setUserId($this->
user->getId());
3089 $userSolutionAdopter->setActiveId($this->test_session->getActiveId());
3090 $userSolutionAdopter->setTargetPass($this->test_sequence->getPass());
3091 $userSolutionAdopter->setQuestionIds($this->test_sequence->getOptionalQuestions());
3093 $userSolutionAdopter->perform();
3098 $this->tpl->setOnScreenMessage(
'failure', sprintf($this->
lng->txt(
'tst_objective_oriented_test_pass_without_questions'), $this->object->getTitle()),
true);
3099 $this->
ctrl->redirectByClass(ilObjTestGUI::class);
3104 $is_next_primary =
true;
3106 if ($this->
object->isForceInstantFeedbackEnabled()) {
3107 $is_next_primary =
false;
3110 $questions_missing_result = $this->questionrepository->getQuestionsMissingResultRecord(
3111 $this->test_session->getActiveId(),
3112 $this->test_session->getPass(),
3113 $this->test_sequence->getOrderedSequenceQuestions()
3116 if ($questions_missing_result === []) {
3121 if (count($questions_missing_result) === 1
3122 && $current_question_id === current($questions_missing_result)) {
3127 return $is_next_primary;
3132 $title_content = $this->ui_factory->listing()->property();
3134 if ($this->
object->getShowKioskModeParticipant()) {
3135 $pax_name_label = $this->
lng->txt(
"conf_user_name");
3139 $pax_name_value =
"<span class='il-test-kiosk-head__participant-name'>"
3140 . $this->
user->getFullname() .
"</span>";
3141 $title_content = $title_content->withProperty($pax_name_label, $pax_name_value,
false);
3144 if ($this->
object->isShowExamIdInTestPassEnabled()) {
3145 $exam_id_label = $this->
lng->txt(
"exam_id_label");
3147 $this->test_session->getActiveId(),
3148 $this->test_session->getPass(),
3149 $this->object->getId()
3151 $title_content = $title_content->withProperty($exam_id_label, $exam_id_value);
3154 if ($this->
object->getShowKioskModeTitle()) {
3155 $test_title_label = $this->
lng->txt(
"test");
3156 $test_title_value = $this->
object->getTitle();
3157 $title_content = $title_content->withProperty($test_title_label, $test_title_value,
false);
3160 return $this->ui_renderer->render($title_content);
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
const PRESENTATION_CONTEXT_TEST
outQuestionForTest(string $formaction, int $active_id, ?int $pass, bool $is_question_postponed=false, array|bool $user_post_solutions=false, bool $show_specific_inline_feedback=false)
setPresentationContext(string $presentationContext)
setTargetGui($linkTargetGui)
getQuestionHeaderBlockBuilder()
setQuestionHeaderBlockBuilder(\ilQuestionHeaderBlockBuilder $questionHeaderBlockBuilder)
setSequenceNumber(int $nr)
setObject(assQuestion $question)
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
getGenericFeedbackOutput(int $active_id, ?int $pass)
getSpecificFeedbackOutput(array $userSolution)
Returns the answer specific feedback for the question.
populateJavascriptFilesRequiredForWorkForm(ilGlobalTemplateInterface $tpl)
setQuestionCount(int $a_question_count)
getSolutionOutput(int $active_id, ?int $pass=null, bool $graphical_output=false, bool $result_output=false, bool $show_question_only=true, bool $show_feedback=false, bool $show_correct_solution=false, bool $show_manual_scoring=false, bool $show_question_text=true, bool $show_inline_feedback=true)
setNavigationGUI(?ilTestQuestionNavigationGUI $navigationGUI)
answerToParticipantInteraction(AdditionalInformationGenerator $additional_info, int $test_ref_id, int $active_id, int $pass, string $source_ip, TestParticipantInteractionTypes $interaction_type)
getTestPresentationConfig()
persistWorkingState(int $active_id, $pass, bool $authorized=true)
persists the working state for current testactive and testpass
static instantiateQuestion(int $question_id)
const CSS_CLASS_FEEDBACK_WRONG
const CSS_CLASS_FEEDBACK_CORRECT
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ?ilObjUser $user=null,)
@classDescription Date and time handling
static getInstance(ilTestSession $a_test_session)
static _updateStatus(int $a_obj_id, int $a_usr_id, ?object $a_obj=null, bool $a_percentage=false, bool $a_force_raise=false)
static getLogger(string $a_component_id)
Get component logger.
static getContentStylePath(int $a_style_id, bool $add_random=true, bool $add_token=true)
get content style path static (to avoid full reading)
static getSyntaxStylePath()
static lookupExamId($active_id, $pass)
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
static buildExamId($active_id, $pass, $test_obj_id=null)
static _getSolvedQuestions($active_id, $question_fi=null)
get solved questions
static get(string $a_var)
static clear(string $a_var)
static set(string $a_var, $a_val)
Set a value.
static logoutUrl(array $parameters=[])
Return the logout URL with a valid CSRF token.
special template class to simplify handling of ITX/PEAR
get(string $part=ilGlobalTemplateInterface::DEFAULT_BLOCK)
Returns a block with all replacements done.
Base Exception for all Exceptions relating to Modules/Test.
Class ilTestPassFinishTasks.
populateContentStyleBlock()
outQuestionSummaryCmd()
Output of a summary of all test questions for test participants.
populateDiscardSolutionModal()
redirectAfterAutosaveCmd()
Redirect the user after an automatic save when the time limit is reached.
getQuestionFeedbackModalHtml(ilTemplate $tpl, string $nav_url)
populateMessageContent(string $content_html)
saveTagsCmd()
Save tags for tagging gui.
ilTestPasswordChecker $password_checker
buildReadOnlyStateQuestionNavigationGUI($question_id)
ilTestQuestionRelatedObjectivesList $question_related_objectives_list
const FIXED_SHUFFLER_SEED_MIN_LENGTH
populateLowerNextButtonBlock($primary_next)
populateNextLocksChangedModal()
checkWorkingTimeCmd()
This is asynchronously called by tpl.workingtime.js to check for changes in the user's processing tim...
registerForcedFeedbackNavUrl(string $forced_feedback_nav_url)
getNextCommandParameter()
generateRandomTestPassForActiveUser()
removeIntermediateSolution()
initTestQuestionConfig(assQuestion $question_obj)
populateNextLocksUnchangedModal()
populateFeedbackBlockMessage(string $a_message)
populateUpperPreviousButtonBlock()
autosaveOnTimeLimitCmd()
Automatically save a user answer when the limited duration of a test run is reached (called by synchr...
populateUpperNextButtonBlock($primaryNext)
populateInstantResponseModal(assQuestionGUI $question_gui, $nav_url)
populatePreviousButtons()
ilTestSession $test_session
populateLowerPreviousButtonBlock()
getPresentationModeParameter()
startPlayerCmd()
Start a test for the first time.
populateSolutionBlock($solutionoutput)
getQuestionsDefaultPresentationMode()
initProcessLocker($activeId)
showQuestionViewable(assQuestionGUI $question_gui, string $form_action, bool $is_question_worked_through, bool $instant_response)
adoptUserSolutionsFromPreviousPass()
prepareTestPage($presentationMode, $sequenceElement, $question_id)
handleCheckTestPassValid(bool $with_redirect=false)
submitIntermediateSolutionCmd()
__construct(ilObjTest $object)
isNrOfTriesReached()
nr of tries exceeded
const LOCKS_CHANGED_MODAL
handleQuestionPostponing(int $question_id)
const LOCKS_UNCHANGED_MODAL
max_processing_time_reached()
Outputs a message when the maximum processing time is reached.
populateQuestionNavigation($sequence_element, $primary_next)
const PRESENTATION_MODE_EDIT
ilTestSequence $test_sequence
InterruptiveModal $finish_test_modal
outProcessingTime(int $active_id, bool $verbose)
cancelAnswerOptionalQuestionsCmd()
bool $max_processing_time_reached
handleQuestionActionCmd()
handleTearsAndAngerQuestionIsNull(int $question_id, $sequence_element)
handlePasswordProtectionRedirect()
submitSolutionAndNextCmd()
populateGenericFeedbackBlock(assQuestionGUI $question_gui, $solutionCorrect)
getRegisteredForcedFeedbackNavUrl()
unmarkQuestionCmd()
Set a question unsolved.
markQuestionAndSaveIntermediateCmd()
getCurrentSequenceElement()
populateSyntaxStyleBlock()
isShowingPostponeStatusReguired(int $question_id)
initTestCmd()
Start a test for the first time after a redirect.
save(assQuestion $question_obj, bool $authorized)
redirectAfterQuestionListCmd()
isParticipantsAnswerFixed($question_id)
endingTimeReached()
handle endingTimeReached
array $cached_question_guis
populateQuestionEditControl(assQuestionGUI $question_gui)
getInstantResponseParameter()
unmarkQuestionAndSaveIntermediateCmd()
handleIntermediateSubmit()
isFirstQuestionInSequence($sequence_element)
populateQuestionOptionalMessage()
getIntroductionPageButtonLabel()
confirmSubmitAnswers()
confirm submit results if confirm then results are submitted and the screen will be redirected to the...
autosaveCmd()
Automatically save a user answer while working on the test (called repeatedly by asynchronous posts i...
getSequenceElementParameter()
array $cached_question_objects
showSideList($current_sequence_element)
determineInlineScoreDisplay()
populateScoreBlock($reachedPoints, $maxPoints)
checkAndUpdateSaveAllowedByFormTimestamp(bool $force)
updateWorkingTime()
updates working time and stores state saveresult to see if question has to be stored or not
getQuestionInstance(int $question_id, bool $from_cache=true)
populateHelperGuiContent($helperGui)
handleUserSettings()
Handles some form parameters on starting and resuming a test.
bool $ending_time_reached
checkTestSessionUser(ilTestSession $test_session)
saveQuestionSolution(bool $authorized=true, bool $force=false)
handleSkillTriggering(ilTestSession $test_session)
populateNextButtons($primary_next)
buildNextButtonInstance($primaryNext)
performTearsAndAngerBrokenConfessionChecks()
outCorrectSolution()
Creates an output of the solution of an answer compared to the correct solution.
showAnswerOptionalQuestionsConfirmation()
detectChangesCmd()
Detect changes sent in the background to the server This is called by ajax from ilTestPlayerQuestionE...
getTestNavigationToolbarGUI()
markQuestionCmd()
Set a question solved.
const PRESENTATION_MODE_VIEW
getNavigationUrlParameter()
setFollowUpQuestionLocksConfirmationPrevented()
populateTestNavigationToolbar(ilTestNavigationToolbarGUI $toolbar_gui)
isOptionalQuestionAnsweringConfirmationRequired(int $sequence_key)
populateFeedbackBlockHeader($withFocusAnchor)
confirmAnswerOptionalQuestionsCmd()
getAnswerChangedParameter()
ensureExistingTestSession(ilTestSession $test_session)
isLastQuestionInSequence($sequence_element)
handleTearsAndAngerNoObjectiveOrientedQuestion()
buildTestPassQuestionList()
populateInstantResponseBlocks(assQuestionGUI $question_gui, $authorizedSolution)
populateSpecificFeedbackBlock(assQuestionGUI $question_gui)
getOnLoadCodeForNavigationButtons(string $target, string $cmd)
isValidSequenceElement($sequence_element)
handlePrimaryButton(ilTestNavigationToolbarGUI $navigation_toolbar_gui, int $current_question_id)
determineSolutionPassIndex(assQuestionGUI $question_gui)
ilTestProcessLocker $process_locker
unregisterForcedFeedbackNavUrl()
afterTestPassFinishedCmd()
isFollowUpQuestionLocksConfirmationPrevented()
executeCommand()
execute command
setAnswerChangedParameter(bool $changed=true)
isMaxProcessingTimeReached()
setAnonymousIdCmd()
Sets a session variable with the test access code for an anonymous test user.
saveNavigationPreventConfirmation()
updateLearningProgressOnTestStart()
getQuestionGuiInstance(int $question_id, bool $from_cache=true)
getNextSequenceParameter()
isTestAccessible()
test accessible returns true if the user can perform the test
showQuestionEditable(assQuestionGUI $question_gui, string $form_action, bool $is_question_worked_through, bool $instant_response)
getContentBlockName()
Returns the name of the current content block (depends on the kiosk mode setting)
performTestPassFinishedTasks(StatusOfAttempt $status_of_attempt)
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...
isForcedFeedbackNavUrlRegistered()
outUserResultsOverviewCmd()
buildPreviousButtonInstance()
buildEditableStateQuestionNavigationGUI($question_id)
const REDIRECT_ON_TIME_LIMIT
const AUTO_SAVE_ON_TIME_LIMIT
const SHOW_INSTANT_RESPONSE
const REDIRECT_AFTER_QUESTION_LIST
const SUBMIT_INTERMEDIATE_SOLUTION
const AFTER_TEST_PASS_FINISHED
const SHOW_FINAL_STATMENT
static isTestExecutionCommand($cmd)
const ACCESS_CODE_CONFIRMED
const DISPLAY_ACCESS_CODE
const UNMARK_QUESTION_SAVE
const TEST_PLAYER_VIEW_TITLE
const TEST_PLAYER_KIOSK_MODE_ENABLED
const TEST_PLAYER_SHORT_TITLE
const TEST_PLAYER_QUESTIONLIST
static getInstance(ilDBInterface $db, ilLanguage $lng, TestLogger $logger, ilObjTest $testOBJ, ilTestRandomQuestionSetConfig $questionSetConfig, ilTestRandomQuestionSetSourcePoolDefinitionList $sourcePoolDefinitionList, ilTestRandomQuestionSetStagingPoolQuestionList $stagingPoolQuestionList)
getSequenceByTestSession($testSession)
creates and returns an instance of a test sequence that corresponds to the current test mode and the ...
Service GUI class for tests.
ilTestSequenceFactory $test_sequence_factory
getObjectiveOrientedContainer()
readonly ilDBInterface $db
getAccessCodeFromSession()
setAnonymousId(string $anonymous_id)
doesAccessCodeInSessionExists()
Class ilTestSubmissionReviewGUI.
static getStyleSheetLocation(string $mode="output", string $a_css_name="")
get full style sheet file name (path inclusive) of current user
static redirect(string $a_script)
static initjQuery(?ilGlobalTemplateInterface $a_tpl=null)
inits and adds the jQuery JS-File to the global or a passed template
const MESSAGE_TYPE_FAILURE
getId()
Get the ID of this signal.
static http()
Fetches the global http state from ILIAS.
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
form(?array $class_path, string $cmd, string $submit_caption="")
TestParticipantInteractionTypes