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());
1037 !$this->testrequest->isset(
'skipfinalstatement')
1038 && $this->object->getMainSettings()->getFinishingSettings()->getConcludingRemarksEnabled()
1044 $redirection_mode = $this->
object->getMainSettings()->getFinishingSettings()->getRedirectionMode();
1045 if ($redirection_mode === RedirectionModes::NONE || $this->
object->canShowTestResults($this->test_session)) {
1046 $this->redirectBackCmd();
1049 if ($redirection_mode === RedirectionModes::IF_KIOSK_ACTIVATED && !$this->
object->getKioskMode()) {
1050 $this->redirectBackCmd();
1057 $redirection_url = $this->
object->getMainSettings()->getFinishingSettings()->getRedirectionUrl();
1059 $redirection_url ?
ilUtil::redirect($redirection_url) : $this->redirectBackCmd();
1064 $class = get_class($this);
1065 $this->
ctrl->setParameterByClass($class,
'finalization_confirmed',
'confirmed');
1067 $this->
ctrl->clearParameterByClass($class,
'finalization_confirmed');
1069 $message = $this->
lng->txt(
'tst_finish_confirmation_question');
1070 if (($this->
object->getNrOfTries() - 1) === $this->test_session->getPass()) {
1071 $message = $this->
lng->txt(
'tst_finish_confirmation_question_no_attempts_left');
1074 return $this->ui_factory->modal()->interruptive(
1075 $this->
lng->txt(
'finish_test'),
1078 )->withActionButtonLabel($this->
lng->txt(
'tst_finish_confirm_button'));
1084 $testPassesSelector->setActiveId($this->test_session->getActiveId());
1085 $testPassesSelector->setLastFinishedPass($this->test_session->getLastFinishedPass());
1087 if (count($testPassesSelector->getReportablePasses())) {
1088 if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
1089 $this->
ctrl->redirectByClass([
'ilTestResultsGUI',
'ilTestEvalObjectiveOrientedGUI']);
1092 $this->
ctrl->redirectByClass([ilTestResultsGUI::class, ilMyTestResultsGUI::class, ilTestEvaluationGUI::class]);
1095 $this->
ctrl->redirectByClass(TestScreenGUI::class, TestScreenGUI::DEFAULT_CMD);
1103 $this->global_screen->tool()->context()->current()->getAdditionalData()->replace(
1105 $this->
object->getTitle() .
' - ' . $this->lng->txt(
'final_statement')
1108 $this->content_style->gui()->addCss($this->tpl, $this->ref_id);
1109 $this->
ctrl->setParameterByClass(ilTestPageGUI::class,
'page_type',
'concludingremarkspage');
1110 $this->
ctrl->setParameterByClass(static::class,
'skipfinalstatement', 1);
1111 $this->tpl->setVariable(
1112 $this->getContentBlockName(),
1113 $this->ui_renderer->render([
1114 $this->ui_factory->legacy()->content(
1115 $this->object->prepareTextareaOutput($this->object->getFinalStatement(),
true)
1117 $this->ui_factory->button()->standard(
1118 $this->lng->txt(
'btn_next'),
1127 $this->navigation_history->addItem(
1128 $this->test_session->getRefId(),
1133 $this->initTestPageTemplate();
1134 $this->populateContentStyleBlock();
1135 $this->populateSyntaxStyleBlock();
1137 if ($this->isMaxProcessingTimeReached()) {
1138 $this->max_processing_time_reached();
1142 if ($this->
object->endingTimeReached()) {
1143 $this->endingTimeReached();
1147 if ($this->isOptionalQuestionAnsweringConfirmationRequired($sequenceElement)) {
1148 $this->
ctrl->setParameter($this,
"sequence", $sequenceElement);
1149 $this->showAnswerOptionalQuestionsConfirmation();
1153 $this->tpl->setVariable(
"TEST_ID", (
string) $this->
object->getTestId());
1154 $this->tpl->setVariable(
"LOGIN", $this->
user->getLogin());
1156 $this->tpl->setVariable(
"SEQ_ID", $sequenceElement);
1157 $this->tpl->setVariable(
"QUEST_ID", $question_id);
1159 if ($this->
object->getEnableProcessingTime()) {
1160 $this->outProcessingTime($this->test_session->getActiveId(),
false);
1163 $this->tpl->setVariable(
"PAGETITLE",
"- " . $this->
object->getTitle());
1165 if ($this->
object->isShowExamIdInTestPassEnabled() && !$this->object->getKioskMode()) {
1166 $this->tpl->setCurrentBlock(
'exam_id_footer');
1168 $this->test_session->getActiveId(),
1169 $this->test_session->getPass(),
1170 $this->object->getId()
1172 $this->tpl->setVariable(
'EXAM_ID_TXT', $this->
lng->txt(
'exam_id'));
1173 $this->tpl->parseCurrentBlock();
1176 if ($this->
object->getListOfQuestions()) {
1177 $this->showSideList($sequenceElement);
1183 if ($this->test_sequence->isAnsweringOptionalQuestionsConfirmed()) {
1187 $question_id = $this->test_sequence->getQuestionForSequence($sequence_key);
1189 if (!$this->test_sequence->isQuestionOptional($question_id)) {
1198 return $this->test_sequence->isPostponedQuestion($question_id);
1203 string $form_action,
1204 bool $is_question_worked_through,
1205 bool $instant_response
1207 $question_navigation_gui = $this->buildReadOnlyStateQuestionNavigationGUI($question_gui->getObject()->
getId());
1208 $question_navigation_gui->setQuestionWorkedThrough($is_question_worked_through);
1213 $this->test_session->getActiveId(),
1214 $this->test_session->getPass(),
1218 $instant_response && $this->object->getSpecificAnswerFeedback(),
1226 $this->isShowingPostponeStatusReguired($question_gui->
getObject()->getId()),
1227 $this->test_session->getActiveId(),
1231 $this->tpl->setVariable(
1232 'LOCKSTATE_INFOBOX',
1233 $this->ui_renderer->render(
1234 $this->ui_factory->messageBox()->info($this->lng->txt(
'tst_player_answer_saved_and_locked'))
1237 $this->tpl->parseCurrentBlock();
1238 $this->tpl->setVariable(
'QUESTION_OUTPUT', $pageoutput);
1239 $this->tpl->setVariable(
'FORMACTION', $form_action);
1240 $this->tpl->setVariable(
'ENCTYPE',
'enctype="' . $question_gui->
getFormEncodingType() .
'"');
1241 $this->tpl->setVariable(
'FORM_TIMESTAMP', time());
1242 $this->populateQuestionEditControl($question_gui);
1247 string $form_action,
1248 bool $is_question_worked_through,
1249 bool $instant_response
1251 $question_navigation_gui = $this->buildEditableStateQuestionNavigationGUI($question_gui->getObject()->
getId());
1252 $question_navigation_gui->setQuestionWorkedThrough($is_question_worked_through);
1253 if ($is_question_worked_through) {
1254 $question_navigation_gui->setDiscardSolutionButtonEnabled(
true);
1256 } elseif ($this->
object->isPostponingEnabled()) {
1257 $question_navigation_gui->setSkipQuestionLinkTarget(
1263 $user_post_solution =
false;
1264 if ($this->testrequest->isset(
'save_error')
1265 && $this->testrequest->int(
'save_error') === 1
1271 $question_config = $question_gui->
getObject()->getTestPresentationConfig();
1274 $question_config->setWorkedThrough($is_question_worked_through);
1277 if ($question_config->isPreviousPassSolutionReuseAllowed()) {
1278 $pass_index = $this->determineSolutionPassIndex($question_gui);
1279 if ($pass_index < $this->test_session->getPass()) {
1280 $question_config->setSolutionInitiallyPrefilled(
true);
1283 $pass_index = $this->test_session->getPass();
1287 $this->modal_signals = $this->populateModals();
1288 $question_navigation_gui->setShowDiscardModalSignal($this->modal_signals[self::DISCARD_MODAL]);
1292 $this->test_session->getActiveId(),
1294 $this->isShowingPostponeStatusReguired($question_gui->
getObject()->getId()),
1295 $user_post_solution,
1296 $instant_response && $this->object->getSpecificAnswerFeedback()
1299 $this->populateQuestionEditControl($question_gui);
1304 if ($this->
object->isPreviousSolutionReuseEnabled()) {
1305 $currentSolutionAvailable = $question_gui->
getObject()->authorizedOrIntermediateSolutionExists(
1306 $this->test_session->getActiveId(),
1307 $this->test_session->getPass()
1310 if (!$currentSolutionAvailable) {
1311 $previousPass = $question_gui->
getObject()->getSolutionMaxPass(
1312 $this->test_session->getActiveId()
1315 $previousSolutionAvailable = $question_gui->
getObject()->authorizedSolutionExists(
1316 $this->test_session->getActiveId(),
1320 if ($previousSolutionAvailable) {
1321 return $previousPass;
1327 return $this->test_session->getPass();
1336 $this->
object->startWorkingTime(
1337 $this->test_session->getActiveId(),
1338 $this->test_session->getPass()
1342 $this->
help->setScreenIdComponent(
'tst');
1343 $this->
help->setScreenId(
'assessment');
1344 $this->
help->setSubScreenId(
'question');
1346 $sequence_element = $this->getCurrentSequenceElement();
1348 if (!$this->isValidSequenceElement($sequence_element)) {
1349 $sequence_element = $this->test_sequence->getFirstSequence();
1352 $this->test_session->setLastSequence($sequence_element ?? 0);
1353 $this->test_session->saveToDb();
1355 $question_id = $this->test_sequence->getQuestionForSequence($sequence_element ?? 0);
1356 if ($question_id ===
null && $this->test_session->isObjectiveOriented()) {
1357 $this->handleTearsAndAngerNoObjectiveOrientedQuestion();
1360 if ($question_id !==
null && !$this->test_sequence->isQuestionPresented($question_id)) {
1361 $this->test_sequence->setQuestionPresented($question_id);
1362 $this->test_sequence->saveToDb();
1365 $question_worked_through = $this->questionrepository->lookupResultRecordExist(
1366 $this->test_session->getActiveId(),
1368 $this->test_session->getPass()
1371 $instant_response =
false;
1372 if ($this->isParticipantsAnswerFixed($question_id)) {
1374 $s = $this->
object->getMainSettings()->getQuestionBehaviourSettings();
1375 if ($s->getInstantFeedbackGenericEnabled()
1376 || $s->getInstantFeedbackPointsEnabled()
1377 || $s->getInstantFeedbackSolutionEnabled()
1378 || $s->getInstantFeedbackSpecificEnabled()) {
1379 $instant_response =
true;
1383 if (!$this->
object->isInstantFeedbackAnswerFixationEnabled()) {
1384 $instant_response = $this->getInstantResponseParameter();
1388 $question_gui = $this->getQuestionGuiInstance($question_id);
1391 $this->handleTearsAndAngerQuestionIsNull($question_id, $sequence_element);
1394 $question_gui->
setSequenceNumber($this->test_sequence->getPositionOfSequence($sequence_element));
1395 $question_gui->
setQuestionCount($this->test_sequence->getUserQuestionCount());
1398 $header_block_builder->setHeaderMode($this->
object->getTitleOutput());
1399 $header_block_builder->setQuestionTitle($question_gui->
getObject()->getTitleForHTMLOutput());
1400 $header_block_builder->setQuestionPoints($question_gui->
getObject()->getPoints());
1401 $header_block_builder->setQuestionPosition($this->test_sequence->getPositionOfSequence($sequence_element));
1402 $header_block_builder->setQuestionCount($this->test_sequence->getUserQuestionCount());
1403 $header_block_builder->setQuestionPostponed($this->test_sequence->isPostponedQuestion($question_id));
1404 if ($this->test_session->isObjectiveOriented()) {
1406 $objectives_adapter->buildQuestionRelatedObjectiveList($this->test_sequence, $this->question_related_objectives_list);
1407 $this->question_related_objectives_list->loadObjectivesTitles();
1409 $header_block_builder->setQuestionRelatedObjectives(
1410 $this->question_related_objectives_list->getQuestionRelatedObjectiveTitles($question_id)
1415 $this->prepareTestPage($presentation_mode, $sequence_element, $question_id);
1417 $navigation_toolbar_gui = $this->getTestNavigationToolbarGUI();
1418 $navigation_toolbar_gui->setFinishTestButtonEnabled(
true);
1420 $is_next_primary = $this->handlePrimaryButton($navigation_toolbar_gui, $question_id);
1422 $this->
ctrl->setParameter($this,
'sequence', $sequence_element);
1423 $this->
ctrl->setParameter($this,
'pmode', $presentation_mode);
1426 switch ($presentation_mode) {
1428 $navigation_toolbar_gui->setDisabledStateEnabled(
false);
1429 $this->showQuestionEditable(
1432 $question_worked_through,
1436 if ($this->
ctrl->getCmd() !== self::FINISH_TEST_CMD
1437 && $this->logger->isLoggingEnabled()
1438 && !$this->getObject()->getAnonymity()) {
1439 $this->
logger->logParticipantInteraction(
1440 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
1441 $this->object->getRefId(),
1443 $this->user->getId(),
1444 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
1445 TestParticipantInteractionTypes::QUESTION_SHOWN,
1453 if ($this->test_sequence->isQuestionOptional($question_gui->
getObject()->getId())) {
1454 $this->populateQuestionOptionalMessage();
1457 $this->showQuestionViewable(
1460 $question_worked_through,
1469 $navigation_toolbar_gui->build();
1470 $this->populateTestNavigationToolbar($navigation_toolbar_gui);
1471 $this->populateQuestionNavigation($sequence_element, $is_next_primary);
1473 if ($instant_response) {
1474 $this->populateInstantResponseBlocks(
1480 if ($this->isForcedFeedbackNavUrlRegistered()) {
1481 $this->populateInstantResponseModal($question_gui, $this->getRegisteredForcedFeedbackNavUrl());
1482 $this->unregisterForcedFeedbackNavUrl();
1494 if ($this->saveQuestionSolution(
true,
false)) {
1495 $question_id = $this->test_sequence->getQuestionForSequence(
1496 $this->getCurrentSequenceElement()
1499 $this->removeIntermediateSolution();
1501 if ($this->
object->isForceInstantFeedbackEnabled()) {
1502 $this->
ctrl->setParameter($this,
'instresp', 1);
1504 $this->test_sequence->setQuestionChecked($question_id);
1505 $this->test_sequence->saveToDb();
1508 if ($this->getNextCommandParameter()) {
1509 if ($this->getNextSequenceParameter()) {
1510 $this->
ctrl->setParameter($this,
'sequence', $this->getNextSequenceParameter());
1511 $this->
ctrl->setParameter($this,
'pmode',
'');
1514 $this->
ctrl->redirect($this, $this->getNextCommandParameter());
1523 $this->saveNavigationPreventConfirmation();
1527 if ($this->getNavigationUrlParameter()) {
1530 $this->
ctrl->saveParameter($this,
'sequence');
1539 $this->removeIntermediateSolution();
1540 $this->setAnswerChangedParameter(
false);
1541 $this->
ctrl->saveParameter($this,
'sequence');
1548 $current_sequence_element = $this->getCurrentSequenceElement();
1550 $current_question_obj = $this->getQuestionInstance(
1551 $this->test_sequence->getQuestionForSequence($current_sequence_element)
1553 $current_question_obj->setTestId($this->
object->getId());
1555 $current_question_obj->resetUsersAnswer(
1556 $this->test_session->getActiveId(),
1557 $this->test_session->getPass()
1560 if ($this->
logger->isLoggingEnabled()
1561 && !$this->getObject()->getAnonymity()) {
1562 $this->
logger->logParticipantInteraction(
1563 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
1564 $this->object->getRefId(),
1565 $this->test_sequence->getQuestionForSequence($current_sequence_element),
1566 $this->user->getId(),
1567 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
1568 TestParticipantInteractionTypes::ANSWER_DELETED,
1574 $this->
ctrl->saveParameter($this,
'sequence');
1583 $current_sequence_element = $this->getCurrentSequenceElement();
1584 $next_sequence_element = $this->test_sequence->getNextSequence($current_sequence_element);
1586 if (!$this->isValidSequenceElement($next_sequence_element)) {
1587 $next_sequence_element = $this->test_sequence->getFirstSequence();
1590 if ($this->
object->isPostponingEnabled()) {
1591 $this->test_sequence->postponeSequence($current_sequence_element);
1592 $this->test_sequence->saveToDb();
1595 if ($this->
logger->isLoggingEnabled()
1596 && !$this->getObject()->getAnonymity()) {
1597 $this->
logger->logParticipantInteraction(
1598 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
1599 $this->object->getRefId(),
1600 $this->test_sequence->getQuestionForSequence($current_sequence_element),
1601 $this->user->getId(),
1602 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
1603 TestParticipantInteractionTypes::QUESTION_SKIPPED,
1609 $this->
ctrl->setParameter($this,
'sequence', $next_sequence_element);
1610 $this->
ctrl->setParameter($this,
'pmode',
'');
1620 $this->test_session->setUserId($this->
user->getId());
1622 if ($access_code !=
null && isset($access_code[$this->
object->getTestId()])) {
1623 $this->test_session->setAnonymousId($access_code[$this->
object->getTestId()]);
1625 if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
1626 $this->test_session->setObjectiveOrientedContainerId($this->getObjectiveOrientedContainer()->getObjId());
1628 $this->test_session->saveToDb();
1630 $active_id = $this->test_session->getActiveId();
1631 $this->
ctrl->setParameter($this,
"active_id", $active_id);
1633 $shuffle = $this->
object->getShuffleQuestions();
1634 if ($this->
object->isRandomTest()) {
1635 $this->generateRandomTestPassForActiveUser();
1637 $this->
object->loadQuestions();
1641 $this->test_result_repository->updateTestAttemptResult(
1643 $this->test_session->getPass(),
1645 $this->object->getId()
1649 if (!$this->test_sequence->hasSequence()) {
1650 $this->test_sequence->createNewSequence($this->
object->getQuestionCount(), $shuffle);
1651 $this->test_sequence->saveToDb();
1654 $this->test_sequence->loadFromDb();
1655 $this->test_sequence->loadQuestions();
1657 if ($this->test_session->isObjectiveOriented()) {
1660 $objectivesAdapter->notifyTestStart($this->test_session, $this->
object->getId());
1661 $objectivesAdapter->prepareTestPass($this->test_session, $this->test_sequence);
1663 $objectivesAdapter->buildQuestionRelatedObjectiveList(
1664 $this->test_sequence,
1665 $this->question_related_objectives_list
1668 if ($this->test_sequence->hasOptionalQuestions()) {
1669 $this->adoptUserSolutionsFromPreviousPass();
1671 $this->test_sequence->reorderOptionalQuestionsToSequenceEnd();
1672 $this->test_sequence->saveToDb();
1676 $active_time_id = $this->
object->startWorkingTime(
1677 $this->test_session->getActiveId(),
1678 $this->test_session->getPass()
1682 $this->updateLearningProgressOnTestStart();
1684 $sequence_element = $this->test_sequence->getFirstSequence();
1686 $this->
ctrl->setParameter($this,
'sequence', $sequence_element);
1687 $this->
ctrl->setParameter($this,
'pmode',
'');
1689 if ($this->
logger->isLoggingEnabled()
1690 && !$this->getObject()->getAnonymity()) {
1691 $this->
logger->logParticipantInteraction(
1692 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
1693 $this->object->getRefId(),
1695 $this->user->getId(),
1696 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
1697 TestParticipantInteractionTypes::TEST_RUN_STARTED,
1703 if ($this->
object->getListOfQuestionsStart()) {
1704 $this->
ctrl->setParameterByClass(static::class,
'first',
'1');
1716 return !$this->isNrOfTriesReached()
1717 and !$this->isMaxProcessingTimeReached()
1718 and $this->
object->startingTimeReached()
1719 and !$this->
object->endingTimeReached();
1727 return $this->
object->hasNrOfTriesRestriction() && $this->
object->isNrOfTriesReached($this->test_session->getPass());
1738 $this->test_session->increasePass();
1739 $this->test_session->setLastSequence(0);
1740 $this->test_session->saveToDb();
1742 $this->redirectBackCmd();
1754 $this->suspendTestCmd();
1764 $this->tpl->addBlockFile($this->getContentBlockName(),
"adm_content",
"tpl.il_as_tst_submit_answers_confirm.html",
"components/ILIAS/Test");
1765 $this->tpl->setCurrentBlock(
"adm_content");
1766 if ($this->
object->isTestFinished($this->test_session->getActiveId())) {
1767 $this->tpl->setCurrentBlock(
"not_submit_allowed");
1768 $this->tpl->setVariable(
"TEXT_ALREADY_SUBMITTED", $this->
lng->txt(
"tst_already_submitted"));
1769 $this->tpl->setVariable(
"BTN_OK", $this->
lng->txt(
"tst_show_answer_sheet"));
1771 $this->tpl->setCurrentBlock(
"submit_allowed");
1772 $this->tpl->setVariable(
"TEXT_CONFIRM_SUBMIT_RESULTS", $this->
lng->txt(
"tst_confirm_submit_answers"));
1773 $this->tpl->setVariable(
"BTN_OK", $this->
lng->txt(
"tst_submit_results"));
1775 $this->tpl->setVariable(
"BTN_BACK", $this->
lng->txt(
"back"));
1776 $this->tpl->setVariable(
"FORMACTION", $this->
ctrl->getFormAction($this,
"finalSubmission"));
1777 $this->tpl->parseCurrentBlock();
1782 $starting_time = $this->
object->getStartingTimeOfUser($active_id);
1788 $this->
object->getProcessingTimeInSeconds($active_id)
1791 $this->tpl->setCurrentBlock(
'enableprocessingtime');
1792 $this->tpl->setVariable(
'USER_WORKING_TIME_MESSAGE_BOX', $working_time->getMessageBox($verbose));
1793 $this->tpl->parseCurrentBlock();
1795 $working_time_js_template = $working_time->prepareWorkingTimeJsTemplate(
1797 getdate($starting_time),
1798 $this->
ctrl->getLinkTarget($this,
'checkWorkingTime',
'',
true),
1802 $this->tpl->addOnLoadCode($working_time_js_template->get());
1814 $active_id = $this->test_session->getActiveId();
1815 echo (
string) $this->
object->getProcessingTimeInSeconds($active_id);
1821 $question_summary_data = $this->service->getQuestionSummaryData($this->test_sequence);
1825 foreach ($question_summary_data as $idx => $row) {
1826 $title = htmlspecialchars($row[
'title'], ENT_QUOTES,
null,
false);
1828 if ($row[
'description'] !==
'') {
1829 $description = htmlspecialchars($row[
'description'], ENT_QUOTES,
null,
false);
1832 if (!$row[
'disabled']) {
1833 $this->
ctrl->setParameter($this,
'pmode',
'');
1834 $this->
ctrl->setParameter($this,
'sequence', $row[
'sequence']);
1837 $this->
ctrl->setParameter($this,
'sequence', $this->getCurrentSequenceElement($current_sequence_element));
1843 ($row[
'worked_through'] || $row[
'isAnswered'])
1844 && $row[
'has_authorized_answer']
1849 $questions[] = $this->ui_factory->listing()->workflow()
1850 ->step($title, $description, $action)
1851 ->withStatus($status);
1852 $active = $row[
'sequence'] == $current_sequence_element ? $idx : $active;
1855 $question_listing = $this->ui_factory->listing()->workflow()->linear(
1856 $this->
lng->txt(
'mainbar_button_label_questionlist'),
1858 )->withActive($active);
1861 $this->global_screen->tool()->context()->current()->addAdditionalData(
1872 $this->
help->setScreenIdComponent(
'tst');
1873 $this->
help->setScreenId(
'assessment');
1874 $this->
help->setSubScreenId(
'question_summary');
1876 $is_first_page = $this->testrequest->strVal(
'first') ===
'1';
1878 $this->tpl->addBlockFile(
1879 $this->getContentBlockName(),
1881 'tpl.il_as_tst_question_summary.html',
1882 'components/ILIAS/Test'
1885 $this->global_screen->tool()->context()->current()->getAdditionalData()->replace(
1887 $this->getObject()->
getTitle() .
' - ' . $this->
lng->txt(
'question_summary')
1890 $active_id = $this->test_session->getActiveId();
1891 $question_summary_data = $this->service->getQuestionSummaryData($this->test_sequence);
1893 $this->
ctrl->setParameter($this,
'sequence', $this->testrequest->raw(
'sequence'));
1903 $question_summary_data
1905 $this->tpl->setVariable(
'TABLE_LIST_OF_QUESTIONS', $this->ui_renderer->render($table->buildComponents($is_first_page)));
1907 if ($this->
object->getEnableProcessingTime()) {
1908 $this->outProcessingTime($active_id,
true);
1911 if ($this->
object->isShowExamIdInTestPassEnabled()) {
1912 $this->tpl->setCurrentBlock(
'exam_id_footer');
1914 $this->test_session->getActiveId(),
1915 $this->test_session->getPass(),
1916 $this->object->getId()
1918 $this->tpl->setVariable(
'EXAM_ID_TXT', $this->
lng->txt(
'exam_id'));
1919 $this->tpl->parseCurrentBlock();
1933 $this->tpl->addBlockFile(
"ADM_CONTENT",
"adm_content",
"tpl.il_as_tst_correct_solution.html",
"components/ILIAS/Test");
1935 $this->tpl->setCurrentBlock(
"ContentStyle");
1937 $this->tpl->parseCurrentBlock();
1939 $this->tpl->setCurrentBlock(
"SyntaxStyle");
1941 $this->tpl->parseCurrentBlock();
1944 if ($this->
object->getShowSolutionAnswersOnly()) {
1948 $this->tpl->setCurrentBlock(
"adm_content");
1949 $solution = $this->getCorrectSolutionOutput($this->testrequest->raw(
"evaluation"), $this->testrequest->raw(
"active_id"), $this->testrequest->raw(
"pass"));
1950 $this->tpl->setVariable(
"OUTPUT_SOLUTION", $solution);
1951 $this->tpl->setVariable(
"TEXT_BACK", $this->
lng->txt(
"back"));
1952 $this->
ctrl->saveParameter($this,
"pass");
1953 $this->
ctrl->saveParameter($this,
"active_id");
1954 $this->tpl->setVariable(
"URL_BACK", $this->
ctrl->getLinkTarget($this,
"outUserResultsOverview"));
1955 $this->tpl->parseCurrentBlock();
1969 $this->tpl->addBlockFile($this->getContentBlockName(),
"adm_content",
"tpl.il_as_tst_finish_list_of_answers.html",
"components/ILIAS/Test");
1971 $result_array = $this->
object->getTestResult(
1975 !$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()
1980 foreach ($result_array as $question_data) {
1981 $question = $question_data[
"qid"];
1982 if (is_numeric($question)) {
1983 $this->tpl->setCurrentBlock(
"printview_question");
1984 $question_gui = $this->
object->createQuestionGUI(
"", $question);
1985 $template =
new ilTemplate(
"tpl.il_as_qpl_question_printview.html",
true,
true,
"components/ILIAS/TestQuestionPool");
1986 $template->setVariable(
"COUNTER_QUESTION",
$counter .
". ");
1987 $template->setVariable(
"QUESTION_TITLE", $question_gui->
getObject()->getTitleForHTMLOutput());
1989 $show_question_only = ($this->
object->getShowSolutionAnswersOnly()) ?
true :
false;
1995 $show_question_only,
1996 $this->
object->getShowSolutionFeedback()
1998 $template->setVariable(
"SOLUTION_OUTPUT", $result_output);
1999 $this->tpl->setVariable(
"QUESTION_OUTPUT", $template->get());
2000 $this->tpl->parseCurrentBlock();
2006 if ($this->
object->getShowSolutionAnswersOnly()) {
2009 if (strlen($top_data)) {
2010 $this->tpl->setCurrentBlock(
"top_data");
2011 $this->tpl->setVariable(
"TOP_DATA", $top_data);
2012 $this->tpl->parseCurrentBlock();
2015 if (strlen($bottom_data)) {
2016 $this->tpl->setCurrentBlock(
"bottom_data");
2017 $this->tpl->setVariable(
"FORMACTION", $this->
ctrl->getFormAction($this));
2018 $this->tpl->setVariable(
"BOTTOM_DATA", $bottom_data);
2019 $this->tpl->parseCurrentBlock();
2022 $this->tpl->setCurrentBlock(
"adm_content");
2023 $this->tpl->setVariable(
"TXT_ANSWER_SHEET", $this->
lng->txt(
"tst_list_of_answers"));
2024 $user_data = $this->getAdditionalUsrDataHtmlAndPopulateWindowTitle($this->test_session, $active_id,
true);
2025 $signature = $this->getResultsSignature();
2026 $this->tpl->setVariable(
"USER_DETAILS", $user_data);
2027 $this->tpl->setVariable(
"SIGNATURE", $signature);
2028 $this->tpl->setVariable(
"TITLE", $this->
object->getTitle());
2029 $this->tpl->setVariable(
"TXT_TEST_PROLOG", $this->
lng->txt(
"tst_your_answers"));
2030 $invited_user = &$this->
object->getInvitedUsers($this->
user->getId());
2031 $pagetitle = $this->
object->getTitle() .
' - ' . $this->
lng->txt(
'clientip') .
2032 ': ' .
$_SERVER[
'REMOTE_ADDR'] .
' - ' .
2033 $this->
lng->txt(
'matriculation') .
': ' .
2034 $invited_user[$this->
user->getId()][
'matriculation'];
2035 $this->tpl->setVariable(
'PAGETITLE', $pagetitle);
2036 $this->tpl->parseCurrentBlock();
2046 return "ADM_CONTENT";
2048 if ($this->
object->getKioskMode()) {
2049 $this->tpl->setBodyClass(
"kiosk");
2050 $this->tpl->hideFooter();
2053 return "ADM_CONTENT";
2059 $this->
ctrl->redirectByClass(
2060 [ilRepositoryGUI::class, ilObjTestGUI::class, ilTestEvaluationGUI::class],
2061 "outUserResultsOverview"
2068 return $sequence_element == $this->test_sequence->getFirstSequence();
2073 return $sequence_element == $this->test_sequence->getLastSequence();
2078 $question_id = $this->test_sequence->getQuestionForSequence(
2079 $this->getCurrentSequenceElement()
2082 if (!$this->isParticipantsAnswerFixed($question_id)) {
2083 $this->updateWorkingTime();
2084 $this->saveQuestionSolution(
false);
2086 $this->setAnswerChangedParameter(
true);
2095 $question_id = $this->test_sequence->getQuestionForSequence(
2096 $this->getCurrentSequenceElement()
2099 if (!$this->isParticipantsAnswerFixed($question_id)) {
2100 if ($this->saveQuestionSolution(
true)) {
2101 $this->removeIntermediateSolution();
2102 $this->setAnswerChangedParameter(
false);
2106 $this->test_sequence->setQuestionChecked($question_id);
2107 $this->test_sequence->saveToDb();
2108 } elseif ($this->
object->isForceInstantFeedbackEnabled()) {
2109 $this->test_sequence->setQuestionChecked($question_id);
2110 $this->test_sequence->saveToDb();
2113 $this->
ctrl->setParameter($this,
'instresp', 1);
2116 if ($this->getNavigationUrlParameter()) {
2117 $this->saveNavigationPreventConfirmation();
2118 $this->registerForcedFeedbackNavUrl($this->getNavigationUrlParameter());
2126 $this->handleCheckTestPassValid();
2127 $last_sequence_element = $this->getCurrentSequenceElement();
2128 $next_sequence_element = $this->test_sequence->getNextSequence($last_sequence_element);
2130 $question_id = $this->test_sequence->getQuestionForSequence($last_sequence_element);
2131 $is_worked_through = $this->questionrepository->lookupResultRecordExist(
2132 $this->test_session->getActiveId(),
2134 $this->test_session->getPass()
2137 if (!$is_worked_through) {
2138 if ($this->
logger->isLoggingEnabled()
2139 && !$this->getObject()->getAnonymity()) {
2140 $this->
logger->logParticipantInteraction(
2141 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
2142 $this->object->getRefId(),
2144 $this->user->getId(),
2145 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
2146 TestParticipantInteractionTypes::QUESTION_SKIPPED,
2151 if ($this->
object->isPostponingEnabled()) {
2152 $this->handleQuestionPostponing($question_id);
2156 if (!$this->isValidSequenceElement($next_sequence_element)) {
2157 $next_sequence_element = $this->test_sequence->getFirstSequence();
2160 $this->
ctrl->setParameter($this,
'sequence', $next_sequence_element);
2161 $this->
ctrl->setParameter($this,
'pmode',
'');
2168 $this->handleCheckTestPassValid();
2170 $sequence_element = $this->test_sequence->getPreviousSequence(
2171 $this->getCurrentSequenceElement()
2174 if (!$this->isValidSequenceElement($sequence_element)) {
2175 $sequence_element = $this->test_sequence->getLastSequence();
2178 $this->
ctrl->setParameter($this,
'sequence', $sequence_element);
2179 $this->
ctrl->setParameter($this,
'pmode',
'');
2186 $this->tpl->addBlockFile(
2187 $this->getContentBlockName(),
2189 'tpl.il_as_tst_question_summary.html',
2190 'components/ILIAS/Test'
2197 let key_event = (
event) => {
2198 if(
event.key === 13 &&
event.target.tagName.toLowerCase() ===
"a" ) {
2201 if (
event.key === 13 &&
2202 event.target.tagName.toLowerCase() !==
"textarea" &&
2203 (
event.target.tagName.toLowerCase() !==
"input" ||
event.target.type.toLowerCase() !==
"submit")) {
2204 event.preventDefault();
2208 let
form = document.getElementById(
'taForm');
2209 form.onkeyup = key_event;
2210 form.onkeydown = key_event;
2211 form.onkeypress = key_event;
2213 $this->tpl->addOnLoadCode($onload_js);
2214 $this->tpl->addBlockFile(
2215 $this->getContentBlockName(),
2217 'tpl.il_as_tst_output.html',
2218 'components/ILIAS/Test'
2230 if ($this->test_session->isPasswordChecked() ===
true) {
2234 if ($this->
ctrl->getNextClass() ===
'iltestpasswordprotectiongui') {
2238 if (!$this->password_checker->isPasswordProtectionPageRedirectRequired()) {
2239 $this->test_session->setPasswordChecked(
true);
2243 $this->
ctrl->setParameterByClass(self::class,
'lock', $this->getLockParameter());
2246 $this->
ctrl->setParameterByClass(ilTestPasswordProtectionGUI::class,
'nextCommand', $next_command);
2247 $this->
ctrl->redirectByClass(ilTestPasswordProtectionGUI::class,
'showPasswordForm');
2252 if ($this->
object->isInstantFeedbackAnswerFixationEnabled()) {
2253 return $this->test_sequence->isQuestionChecked($question_id);
2256 if ($this->
object->isFollowupQuestionAnswerFixationEnabled()) {
2257 return $this->isForcedFeedbackNavUrlRegistered() || $this->test_sequence->isNextQuestionPresented($question_id);
2268 return $this->
lng->txt(
"save_introduction");
2273 $this->ass_settings =
new ilSetting(
'assessment');
2284 $this->
object->getTestId(),
2285 $this->object->getRefId(),
2286 $this->skills_service->profile(),
2287 $this->skills_service->personal()
2290 $skill_evaluation->setUserId($test_session->
getUserId());
2291 $skill_evaluation->setActiveId($test_session->
getActiveId());
2292 $skill_evaluation->setPass($test_session->
getPass());
2294 $skill_evaluation->setNumRequiredBookingsForSkillTriggering(
2295 $this->
object->getGlobalSettings()->getSkillTriggeringNumberOfAnswers()
2298 $question_list = $this->buildTestPassQuestionList();
2299 $question_list->load();
2300 $skill_evaluation->init($question_list);
2301 $skill_evaluation->evaluate(
2302 $this->
object->getTestResult(
2309 $skill_evaluation->handleSkillTriggering();
2316 $confirmation->setFormAction($this->
ctrl->getFormAction($this));
2317 $confirmation->setCancelCmd(
'cancelAnswerOptionalQuestions');
2318 $confirmation->setConfirmCmd(
'confirmAnswerOptionalQuestions');
2320 $confirmation->build($this->
object->isFixedTest());
2322 $this->populateHelperGuiContent($confirmation);
2327 $this->test_sequence->setAnsweringOptionalQuestionsConfirmed(
true);
2328 $this->test_sequence->saveToDb();
2330 $this->
ctrl->setParameter($this,
'activecommand',
'gotoquestion');
2331 $this->
ctrl->redirect($this,
'redirectQuestion');
2336 if ($this->
object->getListOfQuestions()) {
2337 $this->
ctrl->setParameter($this,
'activecommand',
'summary');
2339 $this->
ctrl->setParameter($this,
'activecommand',
'previous');
2342 $this->
ctrl->redirect($this,
'redirectQuestion');
2350 $this->tpl->setVariable($this->getContentBlockName(), $this->
ctrl->getHTML($helperGui));
2356 $navigation_toolbar->setSuspendTestButtonEnabled($this->
object->getShowCancel());
2357 $navigation_toolbar->setUserPassOverviewEnabled($this->
object->getUsrPassOverviewEnabled());
2358 $navigation_toolbar->setFinishTestCommand($this->getFinishTestCommand());
2359 return $navigation_toolbar;
2370 $navigationGUI->setFeedbackButtonEnabled(
2371 $this->
object->getMainSettings()->getQuestionBehaviourSettings()->isAnyInstantFeedbackOptionEnabled()
2374 if (!$this->isParticipantsAnswerFixed($question_id)) {
2378 if ($this->
object->getShowMarker()) {
2382 if (count($solved_array) > 0) {
2383 $solved = array_pop($solved_array);
2384 $solved = $solved[
"solved"];
2389 $navigationGUI->setQuestionMarked(
true);
2392 $navigationGUI->setQuestionMarked(
false);
2397 return $navigationGUI;
2408 $navigation_gui->setFeedbackButtonEnabled(
2409 $this->
object->getMainSettings()->getQuestionBehaviourSettings()->isAnyInstantFeedbackOptionEnabled()
2415 if ($this->
object->getSpecificAnswerFeedback()
2416 || $this->object->getGenericAnswerFeedback()
2417 || $this->object->getAnswerFeedbackPoints()
2418 || $this->object->getInstantFeedbackSolution()) {
2419 $navigation_gui->setAnswerFreezingEnabled($this->
object->isInstantFeedbackAnswerFixationEnabled());
2421 if ($this->
object->isForceInstantFeedbackEnabled()) {
2422 $navigation_gui->setForceInstantResponseEnabled(
true);
2429 if ($this->
object->getShowMarker()) {
2433 if (count($solved_array) > 0) {
2434 $solved = array_pop($solved_array);
2435 $solved = $solved[
'solved'];
2438 if ($solved === 1) {
2440 $navigation_gui->setQuestionMarked(
true);
2443 $navigation_gui->setQuestionMarked(
false);
2446 return $navigation_gui;
2451 if (!$this->
object->getListOfQuestionsEnd()) {
2463 $answer_feedback_enabled = $this->
object->getSpecificAnswerFeedback();
2466 $this->test_session->getActiveId(), #active_id
2467 $this->test_session->getPass(), #pass
2468 false, #graphical_output
2469 false, #result_output
2470 true, #show_question_only
2471 $answer_feedback_enabled, #show_feedback
2472 false, #show_correct_solution
2473 false, #show_manual_scoring
2474 true #show_question_text
2479 $this->isShowingPostponeStatusReguired($question_gui->
getObject()->getId()),
2480 $this->test_session->getActiveId(),
2484 $tpl =
new ilTemplate(
'tpl.tst_player_response_modal.html',
true,
true,
'components/ILIAS/Test');
2487 $saved_tpl = $this->tpl;
2489 $this->populateInstantResponseBlocks($question_gui,
true);
2490 $this->tpl = $saved_tpl;
2492 $tpl->setVariable(
'QUESTION_OUTPUT', $pageoutput);
2493 $this->tpl->setVariable(
'INSTANT_RESPONSE_MODAL', $this->getQuestionFeedbackModalHtml($tpl, $nav_url));
2498 $modal = $this->ui_factory->modal()->roundtrip(
2499 $this->
lng->txt(
'tst_instant_feedback'),
2500 $this->ui_factory->legacy()->content($tpl->
get()),
2502 )->withActionButtons([
2503 $this->ui_factory->button()->standard($this->lng->txt(
'proceed'), $nav_url)
2506 return $this->ui_renderer->render([
2507 $modal->withOnLoad($modal->getShowSignal())
2517 $response_available =
false;
2518 $jump_to_response =
false;
2522 if ($this->
object->getInstantFeedbackSolution()) {
2523 $show_question_inline_score = $this->determineInlineScoreDisplay();
2527 $this->test_session->getActiveId(), #active_id
2528 $this->test_session->getPass(), #pass
2529 false, #graphical_output
2530 $show_question_inline_score, #result_output
2531 true, #show_question_only
2532 false, #show_feedback
2533 true, #show_correct_solution
2534 false, #show_manual_scoring
2535 false #show_question_text
2537 $solutionoutput = str_replace(
'<h1 class="ilc_page_title_PageTitle"></h1>',
'', $solutionoutput);
2538 $this->populateSolutionBlock($solutionoutput);
2539 $response_available =
true;
2540 $jump_to_response =
true;
2543 $reachedPoints = $question_gui->
getObject()->getAdjustedReachedPoints(
2544 $this->test_session->getActiveId(),
2549 $maxPoints = $question_gui->
getObject()->getMaximumPoints();
2551 $solutionCorrect = ($reachedPoints == $maxPoints);
2555 if ($this->
object->getAnswerFeedbackPoints()) {
2556 $this->populateScoreBlock($reachedPoints, $maxPoints);
2557 $response_available =
true;
2558 $jump_to_response =
true;
2563 if ($this->
object->getGenericAnswerFeedback()) {
2564 if ($this->populateGenericFeedbackBlock($question_gui, $solutionCorrect)) {
2565 $response_available =
true;
2566 $jump_to_response =
true;
2572 if ($this->
object->getSpecificAnswerFeedback()) {
2575 $jump_to_response =
false;
2576 } elseif ($this->populateSpecificFeedbackBlock($question_gui)) {
2577 $response_available =
true;
2578 $jump_to_response =
true;
2582 $this->populateFeedbackBlockHeader($jump_to_response);
2583 if (!$response_available) {
2585 $this->populateFeedbackBlockMessage($this->
lng->txt(
'tst_feedback_is_given_inline'));
2587 $this->populateFeedbackBlockMessage($this->
lng->txt(
'tst_feedback_not_available_for_answer'));
2594 if ($withFocusAnchor) {
2595 $this->tpl->setCurrentBlock(
'inst_resp_id');
2596 $this->tpl->setVariable(
'INSTANT_RESPONSE_FOCUS_ID',
'focus');
2597 $this->tpl->parseCurrentBlock();
2600 $this->tpl->setCurrentBlock(
'instant_response_header');
2601 $this->tpl->setVariable(
'INSTANT_RESPONSE_HEADER', $this->
lng->txt(
'tst_feedback'));
2602 $this->tpl->parseCurrentBlock();
2607 $this->tpl->setCurrentBlock(
'instant_response_message');
2608 $this->tpl->setVariable(
'INSTANT_RESPONSE_MESSAGE', $a_message);
2609 $this->tpl->parseCurrentBlock();
2615 if ($this->getSequenceElementParameter()) {
2616 return $this->getSequenceElementParameter();
2619 return $this->test_session->getLastSequence();
2624 if ($this->testrequest->isset(
'sequence')) {
2625 return $this->testrequest->int(
'sequence');
2633 if ($this->testrequest->isset(
'pmode')) {
2634 return $this->testrequest->raw(
'pmode');
2642 return $this->testrequest->isInstanceResponseRequested();
2648 if ($this->testrequest->isset(
'nextcmd')) {
2649 $nextcmd = $this->testrequest->strVal(
'nextcmd');
2652 return $nextcmd !==
'' ? $nextcmd :
null;
2657 return $this->testrequest->int(
'nextseq');
2662 $navigation_url = $this->testrequest->strVal(
'test_player_navigation_url');
2663 if ($navigation_url !==
'') {
2664 $navigation_url_parts = parse_url($navigation_url);
2667 if (!isset($navigation_url_parts[
'host']) || ($ilias_url_parts[
'host'] === $navigation_url_parts[
'host'])) {
2668 return $navigation_url;
2676 return !empty($this->testrequest->raw(
'test_answer_changed'));
2681 $this->
ctrl->setParameter($this,
'test_answer_changed', $changed ?
'1' :
'0');
2686 if ($this->getAnswerChangedParameter()) {
2687 $this->saveQuestionSolution(
false);
2689 $this->removeIntermediateSolution();
2691 $this->setAnswerChangedParameter($this->getAnswerChangedParameter());
2696 if ($this->testrequest->retrieveBoolFromPost(
'save_on_navigation_prevent_confirmation')) {
2700 if ($this->testrequest->retrieveBoolFromPost(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM)) {
2701 ilSession::set(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM,
true);
2709 if (!$from_cache || !isset($this->cached_question_guis[$question_id])) {
2710 $question_gui = $this->
object->createQuestionGUI(
"", $question_id);
2714 $question->setShuffler($this->shuffler->getAnswerShuffleFor(
2716 $this->test_session->getActiveId(),
2717 $this->test_session->getPass()
2723 $this->initTestQuestionConfig($question_gui->
getObject());
2726 $this->cached_question_guis[$question_id] = $question_gui;
2729 return $this->cached_question_guis[$question_id];
2734 if ($from_cache && isset($this->cached_question_objects[$question_id])) {
2735 return $this->cached_question_objects[$question_id];
2738 $ass_settings =
new ilSetting(
'assessment');
2741 $process_locker_factory->setQuestionId($question->getId());
2742 $process_locker_factory->setUserId($this->
user->getId());
2743 $question->setProcessLocker($process_locker_factory->getLocker());
2745 $this->initTestQuestionConfig($question);
2747 $this->cached_question_objects[$question_id] = $question;
2754 $this->
object->isPreviousSolutionReuseEnabled()
2762 .
"active={$this->test_session->getActiveId()} "
2763 .
"qId=$question_id seq=$sequence_element "
2764 . serialize($this->test_sequence)
2767 $this->
ctrl->setParameter($this,
'sequence', $this->test_sequence->getFirstSequence());
2773 if ($this->
object->getKioskMode()) {
2774 $this->tpl->addBlockfile($this->getContentBlockName(),
'content',
"tpl.il_as_tst_kiosk_mode_content.html",
"components/ILIAS/Test");
2775 $this->tpl->setContent($content_html);
2778 $this->tpl->setVariable($this->getContentBlockName(), $content_html);
2786 $signals = [self::DISCARD_MODAL => $this->populateDiscardSolutionModal()];
2788 if ($this->
object->isFollowupQuestionAnswerFixationEnabled()) {
2789 $signals[self::LOCKS_CHANGED_MODAL] = $this->populateNextLocksChangedModal();
2790 $signals[self::LOCKS_UNCHANGED_MODAL] = $this->populateNextLocksUnchangedModal();
2798 $modal = $this->ui_factory->modal()->interruptive(
2799 $this->
lng->txt(
'discard_answer'),
2800 $this->lng->txt(
'discard_answer_confirmation'),
2802 )->withActionButtonLabel($this->
lng->txt(
'discard_answer'));
2804 $this->tpl->setCurrentBlock(
'discard_solution_modal');
2805 $this->tpl->setVariable(
'DISCARD_SOLUTION_MODAL', $this->ui_renderer->render($modal));
2806 $this->tpl->parseCurrentBlock();
2807 return $modal->getShowSignal();
2812 $modal = $this->ui_factory->modal()->interruptive(
2813 $this->
lng->txt(
'tst_nav_next_locks_empty_answer_header'),
2814 $this->lng->txt(
'tst_nav_next_locks_empty_answer_confirm'),
2815 'javascript:il.TestPlayerQuestionEditControl.confirmNextLocksUnchanged()'
2816 )->withActionButtonLabel($this->
lng->txt(
'tst_proceed'));
2818 $this->tpl->setCurrentBlock(
'next_locks_unchanged_modal');
2819 $this->tpl->setVariable(
'NEXT_LOCKS_UNCHANGED_MODAL', $this->ui_renderer->render($modal));
2820 $this->tpl->parseCurrentBlock();
2821 return $modal->getShowSignal();
2826 $empty_signal = new \ILIAS\UI\Implementation\Component\Signal(
'');
2827 if ($this->isFollowUpQuestionLocksConfirmationPrevented()) {
2828 return $empty_signal;
2831 $modal_message = $this->ui_factory->messageBox()->confirmation(
2832 $this->
lng->txt(
'tst_nav_next_locks_current_answer_confirm')
2834 $modal_checkbox = $this->ui_factory->input()->field()->checkbox(
2835 $this->
lng->txt(
'tst_dont_show_msg_again_in_current_session')
2836 )->withDedicatedName(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM);
2838 $modal = $this->ui_factory->modal()->roundtrip(
2839 $this->
lng->txt(
'tst_nav_next_locks_current_answer_header'),
2841 [ $modal_checkbox ],
2842 'javascript:il.TestPlayerQuestionEditControl.confirmNextLocksChanged()'
2843 )->withSubmitLabel($this->
lng->txt(
'tst_proceed'));
2845 $this->tpl->setCurrentBlock(
'next_locks_changed_modal');
2846 $this->tpl->setVariable(
'NEXT_LOCKS_CHANGED_MODAL', $this->ui_renderer->render($modal));
2847 $this->tpl->parseCurrentBlock();
2848 return $modal->getShowSignal();
2851 public const FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM =
'followup_qst_locks_prevent_confirmation';
2855 ilSession::set(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM,
true);
2860 if (
ilSession::get(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM) ==
null) {
2864 return ilSession::get(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM);
2870 $state = $question_gui->
getObject()->lookupForExistingSolutions($this->test_session->getActiveId(), $this->test_session->getPass());
2871 $config[
'isAnswered'] = $state[
'authorized'];
2872 $config[
'isAnswerChanged'] = $state[
'intermediate'] || $this->getAnswerChangedParameter();
2873 $config[
'isAnswerFixed'] = $this->isParticipantsAnswerFixed($question_gui->
getObject()->getId());
2876 $config[
'autosaveUrl'] =
'';
2877 $config[
'autosaveInterval'] = 0;
2880 $config[
'autosaveInterval'] = $this->
object->getMainSettings()->getQuestionBehaviourSettings()->getAutosaveInterval();
2883 $question_config = $question_gui->
getObject()->getTestPresentationConfig();
2885 $config[
'withFormChangeDetection'] = $question_config->isFormChangeDetectionEnabled();
2888 $config[
'withBackgroundChangeDetection'] = $question_config->isBackgroundChangeDetectionEnabled();
2892 $config[
'forcedInstantFeedback'] = $this->
object->isForceInstantFeedbackEnabled();
2893 $config[
'questionLocked'] = $this->isParticipantsAnswerFixed($question_gui->
getObject()->getId());
2894 $config[
'nextQuestionLocks'] = $this->
object->isFollowupQuestionAnswerFixationEnabled();
2895 $config[
'autosaveFailureMessage'] = $this->
lng->txt(
'autosave_failed');
2898 $config[
'modalSignals'] = array_map(fn(
Signal $signal) => $signal->
getId(), $this->modal_signals);
2899 $config[
'preventConfirmationParam'] = self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM;
2901 $this->tpl->addJavascript(
'assets/js/ilTestPlayerQuestionEditControl.js');
2902 $this->tpl->addOnLoadCode(
'il.TestPlayerQuestionEditControl.init(' . json_encode($config) .
')');
2908 return self::PRESENTATION_MODE_EDIT;
2916 $forced_feeback_navigation_url =
ilSession::get(
'forced_feedback_navigation_url');
2917 $forced_feeback_navigation_url[$this->test_session->getActiveId()] = $forced_feedback_nav_url;
2918 ilSession::set(
'forced_feedback_navigation_url', $forced_feeback_navigation_url);
2926 $forced_feedback_navigation_url =
ilSession::get(
'forced_feedback_navigation_url');
2927 if (!isset($forced_feedback_navigation_url[$this->test_session->getActiveId()])) {
2931 return $forced_feedback_navigation_url[$this->test_session->getActiveId()];
2936 return $this->getRegisteredForcedFeedbackNavUrl() !==
null;
2941 $forced_feedback_navigation_url =
ilSession::get(
'forced_feedback_navigation_url');
2942 if (isset($forced_feedback_navigation_url[$this->test_session->getActiveId()])) {
2943 unset($forced_feedback_navigation_url[$this->test_session->getActiveId()]);
2944 ilSession::set(
'forced_feedback_navigation_url', $forced_feedback_navigation_url);
2950 $this->updateWorkingTime();
2951 $this->saveQuestionSolution(
false);
2962 if ($sequence_element ===
false) {
2966 if ($sequence_element < 1) {
2970 if (!$this->test_sequence->getPositionOfSequence($sequence_element)) {
2979 if ($this->
object->isForceInstantFeedbackEnabled()) {
2980 $this->submitSolutionCmd();
2984 if ($this->saveQuestionSolution(
true,
false)) {
2985 $this->test_sequence->getQuestionForSequence(
2986 $this->getCurrentSequenceElement()
2989 $this->removeIntermediateSolution();
2991 $next_sequence_element = $this->test_sequence->getNextSequence($this->getCurrentSequenceElement());
2993 if (!$this->isValidSequenceElement($next_sequence_element)) {
2994 $next_sequence_element = $this->test_sequence->getFirstSequence();
2997 $this->test_session->setLastSequence($next_sequence_element ?? 0);
2998 $this->test_session->saveToDb();
3000 $this->
ctrl->setParameter($this,
'sequence', $next_sequence_element);
3001 $this->
ctrl->setParameter($this,
'pmode',
'');
3010 $this->test_sequence->postponeQuestion($question_id);
3011 $this->test_sequence->saveToDb();
3016 $testObj =
new ilObjTest($this->ref_id,
true);
3018 $participants = $testObj->getActiveParticipantList();
3019 $participant = $participants->getParticipantByActiveId($this->testrequest->getActiveId());
3020 if ($participant && $participant->hasUnfinishedPasses()) {
3023 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
'tst_current_run_no_longer_valid'),
true);
3024 if ($with_redirect) {
3025 $this->
ctrl->redirectByClass([
3026 ilRepositoryGUI::class,
3027 ilObjTestGUI::class,
3028 TestScreenGUI::class
3035 if ($this->test_session->getActiveId() > 0) {
3036 if ($this->test_sequence->hasRandomQuestionsForPass($this->test_session->getActiveId(), $this->test_session->getPass()) > 0) {
3038 __METHOD__ .
' Random Questions allready exists for user ' .
3039 $this->
user->getId() .
' in test ' . $this->object->getTestId()
3045 $this->
logger->info(__METHOD__ .
' ' . sprintf(
3046 $this->
lng->txt(
"error_random_question_generation"),
3047 $this->user->getId(),
3048 $this->object->getTestId()
3064 $this->component_repository,
3066 $this->questionrepository
3068 $questionSetConfig->loadFromDb();
3073 $sourcePoolDefinitionList->loadDefinitions();
3075 $this->process_locker->executeRandomPassBuildOperation(
function () use ($questionSetConfig, $sourcePoolDefinitionList) {
3076 if (!$this->performTearsAndAngerBrokenConfessionChecks()) {
3085 $sourcePoolDefinitionList,
3086 $stagingPoolQuestionList
3089 $questionSetBuilder->performBuild($this->test_session);
3091 }, $sourcePoolDefinitionList->hasTaxonomyFilters());
3096 $ass_settings =
new ilSetting(
'assessment');
3099 $userSolutionAdopter->setUserId($this->
user->getId());
3100 $userSolutionAdopter->setActiveId($this->test_session->getActiveId());
3101 $userSolutionAdopter->setTargetPass($this->test_sequence->getPass());
3102 $userSolutionAdopter->setQuestionIds($this->test_sequence->getOptionalQuestions());
3104 $userSolutionAdopter->perform();
3109 $this->tpl->setOnScreenMessage(
'failure', sprintf($this->
lng->txt(
'tst_objective_oriented_test_pass_without_questions'), $this->object->getTitle()),
true);
3110 $this->
ctrl->redirectByClass(ilObjTestGUI::class);
3115 $is_next_primary =
true;
3117 if ($this->
object->isForceInstantFeedbackEnabled()) {
3118 $is_next_primary =
false;
3121 $questions_missing_result = $this->questionrepository->getQuestionsMissingResultRecord(
3122 $this->test_session->getActiveId(),
3123 $this->test_session->getPass(),
3124 $this->test_sequence->getOrderedSequenceQuestions()
3127 if ($questions_missing_result === []) {
3132 if (count($questions_missing_result) === 1
3133 && $current_question_id === current($questions_missing_result)) {
3138 return $is_next_primary;
3143 $title_content = $this->ui_factory->listing()->property();
3145 if ($this->
object->getShowKioskModeParticipant()) {
3146 $pax_name_label = $this->
lng->txt(
"conf_user_name");
3150 $pax_name_value =
"<span class='il-test-kiosk-head__participant-name'>"
3151 . $this->
user->getFullname() .
"</span>";
3152 $title_content = $title_content->withProperty($pax_name_label, $pax_name_value,
false);
3155 if ($this->
object->isShowExamIdInTestPassEnabled()) {
3156 $exam_id_label = $this->
lng->txt(
"exam_id_label");
3158 $this->test_session->getActiveId(),
3159 $this->test_session->getPass(),
3160 $this->object->getId()
3162 $title_content = $title_content->withProperty($exam_id_label, $exam_id_value);
3165 if ($this->
object->getShowKioskModeTitle()) {
3166 $test_title_label = $this->
lng->txt(
"test");
3167 $test_title_value = $this->
object->getTitle();
3168 $title_content = $title_content->withProperty($test_title_label, $test_title_value,
false);
3171 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