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) {
359 $saved = $this->
save($question_obj, $authorized);
366 $this->
ctrl->setParameter($this,
'save_error',
'1');
367 ilSession::set(
'previouspost', $this->testrequest->getParsedBody());
379 $formtimestamp = $this->testrequest->int(
'formtimestamp');
391 $q_id = $this->test_sequence->getQuestionForSequence($this->testrequest->int(
'sequence'));
393 if ($this->isParticipantsAnswerFixed($q_id)) {
398 if ($q_id ===
null) {
402 return $this->getQuestionInstance($q_id);
407 $active_id = $this->test_session->getActiveId();
417 if ($authorized && $this->test_session->isObjectiveOriented()) {
419 $objectivesAdapter->updateQuestionResult($this->test_session, $question_obj);
422 if ($authorized && $this->
object->isSkillServiceToBeConsidered()) {
423 $this->handleSkillTriggering($this->test_session);
426 if ($authorized && $this->
logger->isLoggingEnabled()
427 && !$this->getObject()->getAnonymity()
429 $this->logger->getAdditionalInformationGenerator(),
430 $this->getObject()->getRefId(),
433 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
434 TestParticipantInteractionTypes::ANSWER_SUBMITTED
436 $this->
logger->logParticipantInteraction($interaction);
443 return !$this->
object->endingTimeReached() && !$this->isMaxProcessingTimeReached() && !$this->isNrOfTriesReached();
448 $this->
ctrl->redirectByClass(TestScreenGUI::class, TestScreenGUI::DEFAULT_CMD);
453 $active_id = $this->test_session->getActiveId();
454 $starting_time = $this->
object->getStartingTimeOfUser($active_id);
455 if ($starting_time ===
false) {
458 return $this->
object->isMaxProcessingTimeReached($starting_time, $active_id);
464 $show_question_inline_score =
false;
465 if ($this->
object->getAnswerFeedbackPoints()) {
466 $show_question_inline_score =
true;
467 return $show_question_inline_score;
469 return $show_question_inline_score;
474 $this->tpl->setCurrentBlock(
'test_nav_toolbar');
475 $this->tpl->setVariable(
'TEST_NAV_TOOLBAR', $toolbar_gui->getHTML());
476 $this->tpl->parseCurrentBlock();
478 if ($this->finish_test_modal ===
null) {
482 $this->tpl->setCurrentBlock(
'finish_test_modal');
483 $this->tpl->setVariable(
485 $this->ui_renderer->render(
486 $this->finish_test_modal->withOnLoad($this->finish_test_modal->getShowSignal())
489 $this->tpl->parseCurrentBlock();
494 if (!$this->isFirstQuestionInSequence($sequence_element)) {
495 $this->populatePreviousButtons();
498 if (!$this->isLastQuestionInSequence($sequence_element)) {
499 $this->populateNextButtons($primary_next);
505 $this->populateUpperPreviousButtonBlock();
506 $this->populateLowerPreviousButtonBlock();
511 $this->populateUpperNextButtonBlock($primary_next);
512 $this->populateLowerNextButtonBlock($primary_next);
517 $button = $this->buildNextButtonInstance($primary_next);
519 $this->tpl->setCurrentBlock(
"next_bottom");
520 $this->tpl->setVariable(
"BTN_NEXT_BOTTOM", $this->ui_renderer->render($button));
521 $this->tpl->parseCurrentBlock();
526 $button = $this->buildNextButtonInstance($primaryNext);
528 $this->tpl->setCurrentBlock(
"next");
529 $this->tpl->setVariable(
"BTN_NEXT", $this->ui_renderer->render($button));
530 $this->tpl->parseCurrentBlock();
535 $button = $this->buildPreviousButtonInstance();
537 $this->tpl->setCurrentBlock(
"prev_bottom");
538 $this->tpl->setVariable(
"BTN_PREV_BOTTOM", $this->ui_renderer->render($button));
539 $this->tpl->parseCurrentBlock();
544 $button = $this->buildPreviousButtonInstance();
546 $this->tpl->setCurrentBlock(
"prev");
547 $this->tpl->setVariable(
"BTN_PREV", $this->ui_renderer->render($button));
548 $this->tpl->parseCurrentBlock();
559 $button = $this->ui_factory->button()->primary(
560 $this->
lng->txt(
'next_question') . $this->ui_renderer->render($this->ui_factory->symbol()->glyph()->next()),
562 )->withUnavailableAction(
true)
565 $button = $this->ui_factory->button()->standard(
566 $this->
lng->txt(
'next_question') . $this->ui_renderer->render($this->ui_factory->symbol()->glyph()->next()),
568 )->withUnavailableAction(
true)
581 $button = $this->ui_factory->button()->standard(
582 $this->ui_renderer->render($this->ui_factory->symbol()->glyph()->back()) . $this->lng->txt(
'previous_question'),
584 )->withUnavailableAction(
true)
591 return static function (
string $id) use ($target, $cmd):
string {
592 return "document.getElementById('{$id}').addEventListener('click', "
593 .
"(e) => {il.TestPlayerQuestionEditControl.checkNavigation('{$target}', '{$cmd}', e);}"
595 .
"document.getElementById('{$id}').removeAttribute('disabled');";
604 $solutionValues = $question_gui->
getObject()->getSolutionValues(
605 $this->test_session->getActiveId(),
610 $question_gui->
getObject()->fetchIndexedValuesFromValuePairs($solutionValues)
613 if (!empty($feedback)) {
614 $this->tpl->setCurrentBlock(
"specific_feedback");
615 $this->tpl->setVariable(
"SPECIFIC_FEEDBACK", $feedback);
616 $this->tpl->parseCurrentBlock();
628 $feedback = $question_gui->
getGenericFeedbackOutput($this->test_session->getActiveId(), $this->test_session->getPass());
630 if (strlen($feedback)) {
636 $this->tpl->setCurrentBlock(
"answer_feedback");
637 $this->tpl->setVariable(
"ANSWER_FEEDBACK", $feedback);
638 $this->tpl->setVariable(
"ILC_FB_CSS_CLASS", $cssClass);
639 $this->tpl->parseCurrentBlock();
647 $scoreInformation = sprintf(
648 $this->
lng->txt(
"you_received_a_of_b_points"),
653 $this->tpl->setCurrentBlock(
"received_points_information");
654 $this->tpl->setVariable(
"RECEIVED_POINTS_INFORMATION", $scoreInformation);
655 $this->tpl->parseCurrentBlock();
660 if (strlen($solutionoutput)) {
661 $this->tpl->setCurrentBlock(
"solution_output");
662 $this->tpl->setVariable(
"CORRECT_SOLUTION", $this->
lng->txt(
"tst_best_solution_is"));
663 $this->tpl->setVariable(
"QUESTION_FEEDBACK", $solutionoutput);
664 $this->tpl->parseCurrentBlock();
670 $this->tpl->setCurrentBlock(
"SyntaxStyle");
671 $this->tpl->setVariable(
672 "LOCATION_SYNTAX_STYLESHEET",
675 $this->tpl->parseCurrentBlock();
680 $this->tpl->setCurrentBlock(
"ContentStyle");
681 $this->tpl->setVariable(
682 "LOCATION_CONTENT_STYLESHEET",
685 $this->tpl->parseCurrentBlock();
695 if ($this->test_session->isAnonymousUser()) {
696 $this->test_session->setAccessCodeToSession($this->testrequest->strVal(
'anonymous_id'));
699 $this->
ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, ilInfoScreenGUI::class]);
710 $testStartLock = $this->getLockParameter();
711 $isFirstTestStartRequest =
false;
713 $this->process_locker->executeTestStartLockOperation(
function () use ($testStartLock, &$isFirstTestStartRequest) {
714 if ($this->test_session->lookupTestStartLock() !== $testStartLock) {
715 $this->test_session->persistTestStartLock($testStartLock);
716 $isFirstTestStartRequest = true;
720 if ($isFirstTestStartRequest) {
721 $this->handleUserSettings();
725 $this->
ctrl->setParameterByClass(
'ilObjTestGUI',
'lock', $testStartLock);
726 $this->
ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, ilInfoScreenGUI::class]);
731 if ($this->testrequest->isset(
'lock') && strlen($this->testrequest->raw(
'lock'))) {
732 return $this->testrequest->raw(
'lock');
740 $this->handleUserSettings();
742 $active_id = $this->test_session->getActiveId();
743 $this->
ctrl->setParameter($this,
"active_id", $active_id);
745 $active_time_id = $this->
object->startWorkingTime($active_id, $this->test_session->getPass());
749 if ($this->
object->isRandomTest()) {
750 if (!$this->test_sequence->hasRandomQuestionsForPass($active_id, $this->test_session->getPass())) {
752 $this->generateRandomTestPassForActiveUser();
756 $shuffle = $this->
object->getShuffleQuestions();
757 if ($this->
object->isRandomTest()) {
761 $this->test_result_repository->updateTestAttemptResult(
763 $this->test_session->getPass(),
765 $this->object->getId()
769 if (!$this->test_sequence->hasSequence()) {
770 $this->test_sequence->createNewSequence($this->
object->getQuestionCount(), $shuffle);
771 $this->test_sequence->saveToDb();
774 if ($this->
object->getListOfQuestionsStart()) {
778 $this->
ctrl->setParameter($this,
'sequence', $this->test_session->getLastSequence());
779 $this->
ctrl->setParameter($this,
'pmode',
'');
788 if ($this->test_session->isAnonymousUser()
789 && !$this->test_session->doesAccessCodeInSessionExists()) {
790 $access_code = $this->test_session->createNewAccessCode();
792 $this->test_session->setAccessCodeToSession($access_code);
793 $this->test_session->setAnonymousId($access_code);
794 $this->test_session->saveToDb();
799 if (!$this->test_session->isAnonymousUser()) {
800 $this->test_session->unsetAccessCodeInSession();
807 $this->tpl->addBlockFile($this->getContentBlockName(),
"adm_content",
"tpl.il_as_tst_anonymous_code_presentation.html",
"components/ILIAS/Test");
808 $this->tpl->setCurrentBlock(
"adm_content");
809 $this->tpl->setVariable(
"TEXT_ANONYMOUS_CODE_CREATED", $this->
lng->txt(
"tst_access_code_created"));
810 $this->tpl->setVariable(
"TEXT_ANONYMOUS_CODE", $this->test_session->getAccessCodeFromSession());
811 $this->tpl->setVariable(
"FORMACTION", $this->
ctrl->getFormAction($this));
813 $this->tpl->setVariable(
"TXT_CONFIRM", $this->
lng->txt(
"continue_work"));
814 $this->tpl->parseCurrentBlock();
827 if ($this->
object->getNrOfTries() != 1
828 && $this->object->getUsePreviousAnswers() == 1
830 $chb_use_previous_answers = 0;
831 if ($this->post_wrapper->has(
'chb_use_previous_answers')) {
832 $chb_use_previous_answers = $this->post_wrapper->retrieve(
833 'chb_use_previous_answers',
837 $this->
user->writePref(
"tst_use_previous_answers", (
string) $chb_use_previous_answers);
847 $this->performTestPassFinishedTasks(StatusOfAttempt::FINISHED_BY_DURATION);
849 $this->redirectAfterFinish();
854 $this->performTestPassFinishedTasks(StatusOfAttempt::FINISHED_BY_DURATION);
856 $this->redirectAfterFinish();
863 $this->tpl->addBlockFile($this->getContentBlockName(),
"adm_content",
"tpl.il_as_tst_redirect_autosave.html",
"components/ILIAS/Test");
864 $this->tpl->setVariable(
"TEXT_REDIRECT", $this->
lng->txt(
"redirectAfterSave"));
865 $this->tpl->setVariable(
"URL",
$url);
870 return $this->test_sequence->getQuestionForSequence($this->testrequest->int(
'sequence'));
879 if (!$this->
access->checkAccess(
'read',
'', $this->ref_id)) {
880 echo $this->
lng->txt(
'autosave_failed') .
': ' . $this->
lng->txt(
'msg_no_perm_read_item');
883 $test_can_run = $this->
object->isExecutable($this->test_session, $this->test_session->getUserId());
884 if (!$test_can_run[
'executable']) {
885 echo $test_can_run[
'errormessage'];
888 if ($this->testrequest->getPostKeys() === []) {
893 if (!$this->canSaveResult() || $this->isParticipantsAnswerFixed($this->getCurrentQuestionId())) {
898 if ($this->saveQuestionSolution(!$this->getAnswerChangedParameter(),
true)) {
899 echo $this->
lng->txt(
'autosave_success');
903 echo $this->
lng->txt(
'autosave_failed');
913 if (!$this->isParticipantsAnswerFixed($this->getCurrentQuestionId())) {
914 $this->saveQuestionSolution(
false,
true);
928 $question_id = $this->getCurrentQuestionId();
929 $state = $this->getQuestionInstance($question_id)->lookupForExistingSolutions(
930 $this->test_session->getActiveId(),
931 $this->test_session->getPass()
934 $result[
'isAnswered'] = $state[
'authorized'];
935 $result[
'isAnswerChanged'] = $state[
'intermediate'];
937 echo json_encode($result);
944 $this->saveQuestionSolution(
false,
true);
946 $this->setAnswerChangedParameter(
true);
953 $this->handleIntermediateSubmit();
954 $this->markQuestionCmd();
962 $question_id = $this->test_sequence->getQuestionForSequence(
963 $this->getCurrentSequenceElement()
966 $this->
object->setQuestionSetSolved(1, $question_id, $this->test_session->getUserId());
974 $this->handleIntermediateSubmit();
976 $this->unmarkQuestionCmd();
984 $question_id = $this->test_sequence->getQuestionForSequence(
985 $this->getCurrentSequenceElement()
988 $this->
object->setQuestionSetSolved(0, $question_id, $this->test_session->getUserId());
995 $this->handleCheckTestPassValid();
998 if ($this->testrequest->strVal(
'finalization_confirmed') !==
'confirmed') {
999 $this->finish_test_modal = $this->buildFinishTestModal();
1000 $this->showQuestionCmd();
1009 $this->performTestPassFinishedTasks(StatusOfAttempt::FINISHED_BY_PARTICIPANT);
1011 if ($this->
logger->isLoggingEnabled()
1012 && !$this->getObject()->getAnonymity()
1013 && ($interaction = $this->logger->getInteractionFactory()->buildParticipantInteraction(
1016 $this->user->getId(),
1017 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
1021 $this->
logger->logParticipantInteraction($interaction);
1030 $this->test_session,
1032 $this->test_result_repository
1033 ))->performFinishTasks($this->process_locker, $status_of_attempt);
1034 $this->test_result_repository->updateTestResultCache($this->test_session->getActiveId());
1036 $this->sendNewPassFinishedNotificationEmailIfActivated(
1037 $this->test_session->getActiveId(),
1038 $this->test_session->getPass()
1044 $notification_type = $this->
object->getMainSettings()->getFinishingSettings()->getMailNotificationContentType();
1046 if ($notification_type === 0
1047 || !$this->
object->getMainSettings()->getFinishingSettings()->getAlwaysSendMailNotification()
1048 && $pass !== $this->object->getNrOfTries() - 1) {
1052 switch ($this->
object->getMainSettings()->getFinishingSettings()->getMailNotificationContentType()) {
1054 $this->
object->sendSimpleNotification($active_id);
1057 $this->
object->sendAdvancedNotification($active_id);
1065 if (!$this->testrequest->isset(
'skipfinalstatement')) {
1066 if ($this->
object->getMainSettings()->getFinishingSettings()->getConcludingRemarksEnabled()) {
1072 $redirection_mode = $this->
object->getMainSettings()->getFinishingSettings()->getRedirectionMode();
1073 $redirection_url = $this->
object->getMainSettings()->getFinishingSettings()->getRedirectionUrl();
1074 if (empty($redirection_url)
1075 || $this->
object->canShowTestResults($this->test_session)
1076 || $redirection_mode === RedirectionModes::NONE
1077 || $redirection_mode === RedirectionModes::IF_KIOSK_ACTIVATED && !$this->object->getKioskMode()) {
1078 $this->redirectBackCmd();
1090 $class = get_class($this);
1091 $this->
ctrl->setParameterByClass($class,
'finalization_confirmed',
'confirmed');
1093 $this->
ctrl->clearParameterByClass($class,
'finalization_confirmed');
1095 $message = $this->
lng->txt(
'tst_finish_confirmation_question');
1096 if (($this->
object->getNrOfTries() - 1) === $this->test_session->getPass()) {
1097 $message = $this->
lng->txt(
'tst_finish_confirmation_question_no_attempts_left');
1100 return $this->ui_factory->modal()->interruptive(
1101 $this->
lng->txt(
'finish_test'),
1104 )->withActionButtonLabel($this->
lng->txt(
'tst_finish_confirm_button'));
1110 $testPassesSelector->setActiveId($this->test_session->getActiveId());
1111 $testPassesSelector->setLastFinishedPass($this->test_session->getLastFinishedPass());
1113 if (count($testPassesSelector->getReportablePasses())) {
1114 if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
1115 $this->
ctrl->redirectByClass([
'ilTestResultsGUI',
'ilTestEvalObjectiveOrientedGUI']);
1118 $this->
ctrl->redirectByClass([ilTestResultsGUI::class, ilMyTestResultsGUI::class, ilTestEvaluationGUI::class]);
1121 $this->
ctrl->redirectByClass(TestScreenGUI::class, TestScreenGUI::DEFAULT_CMD);
1129 $this->global_screen->tool()->context()->current()->getAdditionalData()->replace(
1131 $this->
object->getTitle() .
' - ' . $this->lng->txt(
'final_statement')
1134 $this->content_style->gui()->addCss($this->tpl, $this->ref_id);
1135 $this->
ctrl->setParameterByClass(ilTestPageGUI::class,
'page_type',
'concludingremarkspage');
1136 $this->
ctrl->setParameterByClass(static::class,
'skipfinalstatement', 1);
1137 $this->tpl->setVariable(
1138 $this->getContentBlockName(),
1139 $this->ui_renderer->render([
1140 $this->ui_factory->legacy()->content(
1141 $this->object->prepareTextareaOutput($this->object->getFinalStatement(),
true)
1143 $this->ui_factory->button()->standard(
1144 $this->lng->txt(
'btn_next'),
1153 $this->navigation_history->addItem(
1154 $this->test_session->getRefId(),
1159 $this->initTestPageTemplate();
1160 $this->populateContentStyleBlock();
1161 $this->populateSyntaxStyleBlock();
1163 if ($this->isMaxProcessingTimeReached()) {
1164 $this->max_processing_time_reached();
1168 if ($this->
object->endingTimeReached()) {
1169 $this->endingTimeReached();
1173 if ($this->isOptionalQuestionAnsweringConfirmationRequired($sequenceElement)) {
1174 $this->
ctrl->setParameter($this,
"sequence", $sequenceElement);
1175 $this->showAnswerOptionalQuestionsConfirmation();
1179 $this->tpl->setVariable(
"TEST_ID", (
string) $this->
object->getTestId());
1180 $this->tpl->setVariable(
"LOGIN", $this->
user->getLogin());
1182 $this->tpl->setVariable(
"SEQ_ID", $sequenceElement);
1183 $this->tpl->setVariable(
"QUEST_ID", $question_id);
1185 if ($this->
object->getEnableProcessingTime()) {
1186 $this->outProcessingTime($this->test_session->getActiveId(),
false);
1189 $this->tpl->setVariable(
"PAGETITLE",
"- " . $this->
object->getTitle());
1191 if ($this->
object->isShowExamIdInTestPassEnabled() && !$this->object->getKioskMode()) {
1192 $this->tpl->setCurrentBlock(
'exam_id_footer');
1194 $this->test_session->getActiveId(),
1195 $this->test_session->getPass(),
1196 $this->object->getId()
1198 $this->tpl->setVariable(
'EXAM_ID_TXT', $this->
lng->txt(
'exam_id'));
1199 $this->tpl->parseCurrentBlock();
1202 if ($this->
object->getListOfQuestions()) {
1203 $this->showSideList($sequenceElement);
1209 if ($this->test_sequence->isAnsweringOptionalQuestionsConfirmed()) {
1213 $question_id = $this->test_sequence->getQuestionForSequence($sequence_key);
1215 if (!$this->test_sequence->isQuestionOptional($question_id)) {
1224 return $this->test_sequence->isPostponedQuestion($question_id);
1229 string $form_action,
1230 bool $is_question_worked_through,
1231 bool $instant_response
1233 $question_navigation_gui = $this->buildReadOnlyStateQuestionNavigationGUI($question_gui->getObject()->
getId());
1234 $question_navigation_gui->setQuestionWorkedThrough($is_question_worked_through);
1239 $this->test_session->getActiveId(),
1240 $this->test_session->getPass(),
1244 $instant_response && $this->object->getSpecificAnswerFeedback(),
1252 $this->isShowingPostponeStatusReguired($question_gui->
getObject()->getId()),
1253 $this->test_session->getActiveId(),
1257 $this->tpl->setVariable(
1258 'LOCKSTATE_INFOBOX',
1259 $this->ui_renderer->render(
1260 $this->ui_factory->messageBox()->info($this->lng->txt(
'tst_player_answer_saved_and_locked'))
1263 $this->tpl->parseCurrentBlock();
1264 $this->tpl->setVariable(
'QUESTION_OUTPUT', $pageoutput);
1265 $this->tpl->setVariable(
'FORMACTION', $form_action);
1266 $this->tpl->setVariable(
'ENCTYPE',
'enctype="' . $question_gui->
getFormEncodingType() .
'"');
1267 $this->tpl->setVariable(
'FORM_TIMESTAMP', time());
1268 $this->populateQuestionEditControl($question_gui);
1273 string $form_action,
1274 bool $is_question_worked_through,
1275 bool $instant_response
1277 $question_navigation_gui = $this->buildEditableStateQuestionNavigationGUI($question_gui->getObject()->
getId());
1278 $question_navigation_gui->setQuestionWorkedThrough($is_question_worked_through);
1279 if ($is_question_worked_through) {
1280 $question_navigation_gui->setDiscardSolutionButtonEnabled(
true);
1282 } elseif ($this->
object->isPostponingEnabled()) {
1283 $question_navigation_gui->setSkipQuestionLinkTarget(
1289 $user_post_solution =
false;
1290 if ($this->testrequest->isset(
'save_error')
1291 && $this->testrequest->int(
'save_error') === 1
1297 $question_config = $question_gui->
getObject()->getTestPresentationConfig();
1300 $question_config->setWorkedThrough($is_question_worked_through);
1303 if ($question_config->isPreviousPassSolutionReuseAllowed()) {
1304 $pass_index = $this->determineSolutionPassIndex($question_gui);
1305 if ($pass_index < $this->test_session->getPass()) {
1306 $question_config->setSolutionInitiallyPrefilled(
true);
1309 $pass_index = $this->test_session->getPass();
1313 $this->modal_signals = $this->populateModals();
1314 $question_navigation_gui->setShowDiscardModalSignal($this->modal_signals[self::DISCARD_MODAL]);
1318 $this->test_session->getActiveId(),
1320 $this->isShowingPostponeStatusReguired($question_gui->
getObject()->getId()),
1321 $user_post_solution,
1322 $instant_response && $this->object->getSpecificAnswerFeedback()
1325 $this->populateQuestionEditControl($question_gui);
1330 if ($this->
object->isPreviousSolutionReuseEnabled($this->test_session->getActiveId())) {
1331 $currentSolutionAvailable = $question_gui->
getObject()->authorizedOrIntermediateSolutionExists(
1332 $this->test_session->getActiveId(),
1333 $this->test_session->getPass()
1336 if (!$currentSolutionAvailable) {
1337 $previousPass = $question_gui->
getObject()->getSolutionMaxPass(
1338 $this->test_session->getActiveId()
1341 $previousSolutionAvailable = $question_gui->
getObject()->authorizedSolutionExists(
1342 $this->test_session->getActiveId(),
1346 if ($previousSolutionAvailable) {
1347 return $previousPass;
1353 return $this->test_session->getPass();
1362 $this->
object->startWorkingTime(
1363 $this->test_session->getActiveId(),
1364 $this->test_session->getPass()
1368 $this->
help->setScreenIdComponent(
'tst');
1369 $this->
help->setScreenId(
'assessment');
1370 $this->
help->setSubScreenId(
'question');
1372 $sequence_element = $this->getCurrentSequenceElement();
1374 if (!$this->isValidSequenceElement($sequence_element)) {
1375 $sequence_element = $this->test_sequence->getFirstSequence();
1378 $this->test_session->setLastSequence($sequence_element ?? 0);
1379 $this->test_session->saveToDb();
1381 $question_id = $this->test_sequence->getQuestionForSequence($sequence_element ?? 0);
1382 if ($question_id ===
null && $this->test_session->isObjectiveOriented()) {
1383 $this->handleTearsAndAngerNoObjectiveOrientedQuestion();
1386 if ($question_id !==
null && !$this->test_sequence->isQuestionPresented($question_id)) {
1387 $this->test_sequence->setQuestionPresented($question_id);
1388 $this->test_sequence->saveToDb();
1391 $question_worked_through = $this->questionrepository->lookupResultRecordExist(
1392 $this->test_session->getActiveId(),
1394 $this->test_session->getPass()
1397 $instant_response =
false;
1398 if ($this->isParticipantsAnswerFixed($question_id)) {
1400 $s = $this->
object->getMainSettings()->getQuestionBehaviourSettings();
1401 if ($s->getInstantFeedbackGenericEnabled()
1402 || $s->getInstantFeedbackPointsEnabled()
1403 || $s->getInstantFeedbackSolutionEnabled()
1404 || $s->getInstantFeedbackSpecificEnabled()) {
1405 $instant_response =
true;
1409 if (!$this->
object->isInstantFeedbackAnswerFixationEnabled()) {
1410 $instant_response = $this->getInstantResponseParameter();
1414 $question_gui = $this->getQuestionGuiInstance($question_id);
1417 $this->handleTearsAndAngerQuestionIsNull($question_id, $sequence_element);
1420 $question_gui->
setSequenceNumber($this->test_sequence->getPositionOfSequence($sequence_element));
1421 $question_gui->
setQuestionCount($this->test_sequence->getUserQuestionCount());
1424 $header_block_builder->setHeaderMode($this->
object->getTitleOutput());
1425 $header_block_builder->setQuestionTitle($question_gui->
getObject()->getTitleForHTMLOutput());
1426 $header_block_builder->setQuestionPoints($question_gui->
getObject()->getPoints());
1427 $header_block_builder->setQuestionPosition($this->test_sequence->getPositionOfSequence($sequence_element));
1428 $header_block_builder->setQuestionCount($this->test_sequence->getUserQuestionCount());
1429 $header_block_builder->setQuestionPostponed($this->test_sequence->isPostponedQuestion($question_id));
1430 if ($this->test_session->isObjectiveOriented()) {
1432 $objectives_adapter->buildQuestionRelatedObjectiveList($this->test_sequence, $this->question_related_objectives_list);
1433 $this->question_related_objectives_list->loadObjectivesTitles();
1435 $header_block_builder->setQuestionRelatedObjectives(
1436 $this->question_related_objectives_list->getQuestionRelatedObjectiveTitles($question_id)
1441 $this->prepareTestPage($presentation_mode, $sequence_element, $question_id);
1443 $navigation_toolbar_gui = $this->getTestNavigationToolbarGUI();
1444 $navigation_toolbar_gui->setFinishTestButtonEnabled(
true);
1446 $is_next_primary = $this->handlePrimaryButton($navigation_toolbar_gui, $question_id);
1448 $this->
ctrl->setParameter($this,
'sequence', $sequence_element);
1449 $this->
ctrl->setParameter($this,
'pmode', $presentation_mode);
1452 switch ($presentation_mode) {
1454 $navigation_toolbar_gui->setDisabledStateEnabled(
false);
1455 $this->showQuestionEditable(
1458 $question_worked_through,
1462 if ($this->
ctrl->getCmd() !== self::FINISH_TEST_CMD
1463 && $this->logger->isLoggingEnabled()
1464 && !$this->getObject()->getAnonymity()) {
1465 $this->
logger->logParticipantInteraction(
1466 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
1467 $this->object->getRefId(),
1469 $this->user->getId(),
1470 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
1471 TestParticipantInteractionTypes::QUESTION_SHOWN,
1479 if ($this->test_sequence->isQuestionOptional($question_gui->
getObject()->getId())) {
1480 $this->populateQuestionOptionalMessage();
1483 $this->showQuestionViewable(
1486 $question_worked_through,
1495 $navigation_toolbar_gui->build();
1496 $this->populateTestNavigationToolbar($navigation_toolbar_gui);
1497 $this->populateQuestionNavigation($sequence_element, $is_next_primary);
1499 if ($instant_response) {
1500 $this->populateInstantResponseBlocks(
1506 if ($this->isForcedFeedbackNavUrlRegistered()) {
1507 $this->populateInstantResponseModal($question_gui, $this->getRegisteredForcedFeedbackNavUrl());
1508 $this->unregisterForcedFeedbackNavUrl();
1520 if ($this->saveQuestionSolution(
true,
false)) {
1521 $question_id = $this->test_sequence->getQuestionForSequence(
1522 $this->getCurrentSequenceElement()
1525 $this->removeIntermediateSolution();
1527 if ($this->
object->isForceInstantFeedbackEnabled()) {
1528 $this->
ctrl->setParameter($this,
'instresp', 1);
1530 $this->test_sequence->setQuestionChecked($question_id);
1531 $this->test_sequence->saveToDb();
1534 if ($this->getNextCommandParameter()) {
1535 if ($this->getNextSequenceParameter()) {
1536 $this->
ctrl->setParameter($this,
'sequence', $this->getNextSequenceParameter());
1537 $this->
ctrl->setParameter($this,
'pmode',
'');
1540 $this->
ctrl->redirect($this, $this->getNextCommandParameter());
1549 $this->saveNavigationPreventConfirmation();
1553 if ($this->getNavigationUrlParameter()) {
1556 $this->
ctrl->saveParameter($this,
'sequence');
1565 $this->removeIntermediateSolution();
1566 $this->setAnswerChangedParameter(
false);
1567 $this->
ctrl->saveParameter($this,
'sequence');
1574 $current_sequence_element = $this->getCurrentSequenceElement();
1576 $current_question_obj = $this->getQuestionInstance(
1577 $this->test_sequence->getQuestionForSequence($current_sequence_element)
1579 $current_question_obj->setTestId($this->
object->getId());
1581 $current_question_obj->resetUsersAnswer(
1582 $this->test_session->getActiveId(),
1583 $this->test_session->getPass()
1586 if ($this->
logger->isLoggingEnabled()
1587 && !$this->getObject()->getAnonymity()) {
1588 $this->
logger->logParticipantInteraction(
1589 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
1590 $this->object->getRefId(),
1591 $this->test_sequence->getQuestionForSequence($current_sequence_element),
1592 $this->user->getId(),
1593 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
1594 TestParticipantInteractionTypes::ANSWER_DELETED,
1600 $this->
ctrl->saveParameter($this,
'sequence');
1609 $current_sequence_element = $this->getCurrentSequenceElement();
1610 $next_sequence_element = $this->test_sequence->getNextSequence($current_sequence_element);
1612 if (!$this->isValidSequenceElement($next_sequence_element)) {
1613 $next_sequence_element = $this->test_sequence->getFirstSequence();
1616 if ($this->
object->isPostponingEnabled()) {
1617 $this->test_sequence->postponeSequence($current_sequence_element);
1618 $this->test_sequence->saveToDb();
1621 if ($this->
logger->isLoggingEnabled()
1622 && !$this->getObject()->getAnonymity()) {
1623 $this->
logger->logParticipantInteraction(
1624 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
1625 $this->object->getRefId(),
1626 $this->test_sequence->getQuestionForSequence($current_sequence_element),
1627 $this->user->getId(),
1628 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
1629 TestParticipantInteractionTypes::QUESTION_SKIPPED,
1635 $this->
ctrl->setParameter($this,
'sequence', $next_sequence_element);
1636 $this->
ctrl->setParameter($this,
'pmode',
'');
1646 $this->test_session->setUserId($this->
user->getId());
1648 if ($access_code !=
null && isset($access_code[$this->
object->getTestId()])) {
1649 $this->test_session->setAnonymousId($access_code[$this->
object->getTestId()]);
1651 if ($this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()) {
1652 $this->test_session->setObjectiveOrientedContainerId($this->getObjectiveOrientedContainer()->getObjId());
1654 $this->test_session->saveToDb();
1656 $active_id = $this->test_session->getActiveId();
1657 $this->
ctrl->setParameter($this,
"active_id", $active_id);
1659 $shuffle = $this->
object->getShuffleQuestions();
1660 if ($this->
object->isRandomTest()) {
1661 $this->generateRandomTestPassForActiveUser();
1663 $this->
object->loadQuestions();
1667 $this->test_result_repository->updateTestAttemptResult(
1669 $this->test_session->getPass(),
1671 $this->object->getId()
1675 if (!$this->test_sequence->hasSequence()) {
1676 $this->test_sequence->createNewSequence($this->
object->getQuestionCount(), $shuffle);
1677 $this->test_sequence->saveToDb();
1680 $this->test_sequence->loadFromDb();
1681 $this->test_sequence->loadQuestions();
1683 if ($this->test_session->isObjectiveOriented()) {
1686 $objectivesAdapter->notifyTestStart($this->test_session, $this->
object->getId());
1687 $objectivesAdapter->prepareTestPass($this->test_session, $this->test_sequence);
1689 $objectivesAdapter->buildQuestionRelatedObjectiveList(
1690 $this->test_sequence,
1691 $this->question_related_objectives_list
1694 if ($this->test_sequence->hasOptionalQuestions()) {
1695 $this->adoptUserSolutionsFromPreviousPass();
1697 $this->test_sequence->reorderOptionalQuestionsToSequenceEnd();
1698 $this->test_sequence->saveToDb();
1702 $active_time_id = $this->
object->startWorkingTime(
1703 $this->test_session->getActiveId(),
1704 $this->test_session->getPass()
1708 $this->updateLearningProgressOnTestStart();
1710 $sequence_element = $this->test_sequence->getFirstSequence();
1712 $this->
ctrl->setParameter($this,
'sequence', $sequence_element);
1713 $this->
ctrl->setParameter($this,
'pmode',
'');
1715 if ($this->
logger->isLoggingEnabled()
1716 && !$this->getObject()->getAnonymity()) {
1717 $this->
logger->logParticipantInteraction(
1718 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
1719 $this->object->getRefId(),
1721 $this->user->getId(),
1722 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
1723 TestParticipantInteractionTypes::TEST_RUN_STARTED,
1729 if ($this->
object->getListOfQuestionsStart()) {
1730 $this->
ctrl->setParameterByClass(static::class,
'first',
'1');
1742 return !$this->isNrOfTriesReached()
1743 and !$this->isMaxProcessingTimeReached()
1744 and $this->
object->startingTimeReached()
1745 and !$this->
object->endingTimeReached();
1753 return $this->
object->hasNrOfTriesRestriction() && $this->
object->isNrOfTriesReached($this->test_session->getPass());
1764 $this->test_session->increasePass();
1765 $this->test_session->setLastSequence(0);
1766 $this->test_session->saveToDb();
1768 $this->redirectBackCmd();
1780 $this->suspendTestCmd();
1790 $this->tpl->addBlockFile($this->getContentBlockName(),
"adm_content",
"tpl.il_as_tst_submit_answers_confirm.html",
"components/ILIAS/Test");
1791 $this->tpl->setCurrentBlock(
"adm_content");
1792 if ($this->
object->isTestFinished($this->test_session->getActiveId())) {
1793 $this->tpl->setCurrentBlock(
"not_submit_allowed");
1794 $this->tpl->setVariable(
"TEXT_ALREADY_SUBMITTED", $this->
lng->txt(
"tst_already_submitted"));
1795 $this->tpl->setVariable(
"BTN_OK", $this->
lng->txt(
"tst_show_answer_sheet"));
1797 $this->tpl->setCurrentBlock(
"submit_allowed");
1798 $this->tpl->setVariable(
"TEXT_CONFIRM_SUBMIT_RESULTS", $this->
lng->txt(
"tst_confirm_submit_answers"));
1799 $this->tpl->setVariable(
"BTN_OK", $this->
lng->txt(
"tst_submit_results"));
1801 $this->tpl->setVariable(
"BTN_BACK", $this->
lng->txt(
"back"));
1802 $this->tpl->setVariable(
"FORMACTION", $this->
ctrl->getFormAction($this,
"finalSubmission"));
1803 $this->tpl->parseCurrentBlock();
1808 $starting_time = $this->
object->getStartingTimeOfUser($active_id);
1814 $this->
object->getProcessingTimeInSeconds($active_id)
1817 $this->tpl->setCurrentBlock(
'enableprocessingtime');
1818 $this->tpl->setVariable(
'USER_WORKING_TIME_MESSAGE_BOX', $working_time->getMessageBox($verbose));
1819 $this->tpl->parseCurrentBlock();
1821 $working_time_js_template = $working_time->prepareWorkingTimeJsTemplate(
1823 getdate($starting_time),
1824 $this->
ctrl->getLinkTarget($this,
'checkWorkingTime',
'',
true),
1828 $this->tpl->addOnLoadCode($working_time_js_template->get());
1840 $active_id = $this->test_session->getActiveId();
1841 echo (
string) $this->
object->getProcessingTimeInSeconds($active_id);
1847 $question_summary_data = $this->service->getQuestionSummaryData($this->test_sequence);
1851 foreach ($question_summary_data as $idx => $row) {
1852 $title = htmlspecialchars($row[
'title'], ENT_QUOTES,
null,
false);
1854 if ($row[
'description'] !==
'') {
1855 $description = htmlspecialchars($row[
'description'], ENT_QUOTES,
null,
false);
1858 if (!$row[
'disabled']) {
1859 $this->
ctrl->setParameter($this,
'pmode',
'');
1860 $this->
ctrl->setParameter($this,
'sequence', $row[
'sequence']);
1863 $this->
ctrl->setParameter($this,
'sequence', $this->getCurrentSequenceElement($current_sequence_element));
1869 ($row[
'worked_through'] || $row[
'isAnswered'])
1870 && $row[
'has_authorized_answer']
1875 $questions[] = $this->ui_factory->listing()->workflow()
1876 ->step($title, $description, $action)
1877 ->withStatus($status);
1878 $active = $row[
'sequence'] == $current_sequence_element ? $idx : $active;
1881 $question_listing = $this->ui_factory->listing()->workflow()->linear(
1882 $this->
lng->txt(
'mainbar_button_label_questionlist'),
1884 )->withActive($active);
1887 $this->global_screen->tool()->context()->current()->addAdditionalData(
1898 $this->
help->setScreenIdComponent(
'tst');
1899 $this->
help->setScreenId(
'assessment');
1900 $this->
help->setSubScreenId(
'question_summary');
1902 $is_first_page = $this->testrequest->strVal(
'first') ===
'1';
1904 $this->tpl->addBlockFile(
1905 $this->getContentBlockName(),
1907 'tpl.il_as_tst_question_summary.html',
1908 'components/ILIAS/Test'
1911 $this->global_screen->tool()->context()->current()->getAdditionalData()->replace(
1913 $this->getObject()->
getTitle() .
' - ' . $this->
lng->txt(
'question_summary')
1916 $active_id = $this->test_session->getActiveId();
1917 $question_summary_data = $this->service->getQuestionSummaryData($this->test_sequence);
1919 $this->
ctrl->setParameter($this,
'sequence', $this->testrequest->raw(
'sequence'));
1929 $question_summary_data
1931 $this->tpl->setVariable(
'TABLE_LIST_OF_QUESTIONS', $this->ui_renderer->render($table->buildComponents($is_first_page)));
1933 if ($this->
object->getEnableProcessingTime()) {
1934 $this->outProcessingTime($active_id,
true);
1937 if ($this->
object->isShowExamIdInTestPassEnabled()) {
1938 $this->tpl->setCurrentBlock(
'exam_id_footer');
1940 $this->test_session->getActiveId(),
1941 $this->test_session->getPass(),
1942 $this->object->getId()
1944 $this->tpl->setVariable(
'EXAM_ID_TXT', $this->
lng->txt(
'exam_id'));
1945 $this->tpl->parseCurrentBlock();
1959 $this->tpl->addBlockFile(
"ADM_CONTENT",
"adm_content",
"tpl.il_as_tst_correct_solution.html",
"components/ILIAS/Test");
1961 $this->tpl->setCurrentBlock(
"ContentStyle");
1963 $this->tpl->parseCurrentBlock();
1965 $this->tpl->setCurrentBlock(
"SyntaxStyle");
1967 $this->tpl->parseCurrentBlock();
1970 if ($this->
object->getShowSolutionAnswersOnly()) {
1974 $this->tpl->setCurrentBlock(
"adm_content");
1975 $solution = $this->getCorrectSolutionOutput($this->testrequest->raw(
"evaluation"), $this->testrequest->raw(
"active_id"), $this->testrequest->raw(
"pass"));
1976 $this->tpl->setVariable(
"OUTPUT_SOLUTION", $solution);
1977 $this->tpl->setVariable(
"TEXT_BACK", $this->
lng->txt(
"back"));
1978 $this->
ctrl->saveParameter($this,
"pass");
1979 $this->
ctrl->saveParameter($this,
"active_id");
1980 $this->tpl->setVariable(
"URL_BACK", $this->
ctrl->getLinkTarget($this,
"outUserResultsOverview"));
1981 $this->tpl->parseCurrentBlock();
1995 $this->tpl->addBlockFile($this->getContentBlockName(),
"adm_content",
"tpl.il_as_tst_finish_list_of_answers.html",
"components/ILIAS/Test");
1997 $result_array = $this->
object->getTestResult(
2001 !$this->getObjectiveOrientedContainer()->isObjectiveOrientedPresentationRequired()
2006 foreach ($result_array as $question_data) {
2007 $question = $question_data[
"qid"];
2008 if (is_numeric($question)) {
2009 $this->tpl->setCurrentBlock(
"printview_question");
2010 $question_gui = $this->
object->createQuestionGUI(
"", $question);
2011 $template =
new ilTemplate(
"tpl.il_as_qpl_question_printview.html",
true,
true,
"components/ILIAS/TestQuestionPool");
2012 $template->setVariable(
"COUNTER_QUESTION",
$counter .
". ");
2013 $template->setVariable(
"QUESTION_TITLE", $question_gui->
getObject()->getTitleForHTMLOutput());
2015 $show_question_only = ($this->
object->getShowSolutionAnswersOnly()) ?
true :
false;
2021 $show_question_only,
2022 $this->
object->getShowSolutionFeedback()
2024 $template->setVariable(
"SOLUTION_OUTPUT", $result_output);
2025 $this->tpl->setVariable(
"QUESTION_OUTPUT", $template->get());
2026 $this->tpl->parseCurrentBlock();
2032 if ($this->
object->getShowSolutionAnswersOnly()) {
2035 if (strlen($top_data)) {
2036 $this->tpl->setCurrentBlock(
"top_data");
2037 $this->tpl->setVariable(
"TOP_DATA", $top_data);
2038 $this->tpl->parseCurrentBlock();
2041 if (strlen($bottom_data)) {
2042 $this->tpl->setCurrentBlock(
"bottom_data");
2043 $this->tpl->setVariable(
"FORMACTION", $this->
ctrl->getFormAction($this));
2044 $this->tpl->setVariable(
"BOTTOM_DATA", $bottom_data);
2045 $this->tpl->parseCurrentBlock();
2048 $this->tpl->setCurrentBlock(
"adm_content");
2049 $this->tpl->setVariable(
"TXT_ANSWER_SHEET", $this->
lng->txt(
"tst_list_of_answers"));
2050 $user_data = $this->getAdditionalUsrDataHtmlAndPopulateWindowTitle($this->test_session, $active_id,
true);
2051 $signature = $this->getResultsSignature();
2052 $this->tpl->setVariable(
"USER_DETAILS", $user_data);
2053 $this->tpl->setVariable(
"SIGNATURE", $signature);
2054 $this->tpl->setVariable(
"TITLE", $this->
object->getTitle());
2055 $this->tpl->setVariable(
"TXT_TEST_PROLOG", $this->
lng->txt(
"tst_your_answers"));
2056 $invited_user = &$this->
object->getInvitedUsers($this->
user->getId());
2057 $pagetitle = $this->
object->getTitle() .
' - ' . $this->
lng->txt(
'clientip') .
2058 ': ' .
$_SERVER[
'REMOTE_ADDR'] .
' - ' .
2059 $this->
lng->txt(
'matriculation') .
': ' .
2060 $invited_user[$this->
user->getId()][
'matriculation'];
2061 $this->tpl->setVariable(
'PAGETITLE', $pagetitle);
2062 $this->tpl->parseCurrentBlock();
2072 return "ADM_CONTENT";
2074 if ($this->
object->getKioskMode()) {
2075 $this->tpl->setBodyClass(
"kiosk");
2076 $this->tpl->hideFooter();
2079 return "ADM_CONTENT";
2085 $this->
ctrl->redirectByClass(
2086 [ilRepositoryGUI::class, ilObjTestGUI::class, ilTestEvaluationGUI::class],
2087 "outUserResultsOverview"
2094 return $sequence_element == $this->test_sequence->getFirstSequence();
2099 return $sequence_element == $this->test_sequence->getLastSequence();
2104 $question_id = $this->test_sequence->getQuestionForSequence(
2105 $this->getCurrentSequenceElement()
2108 if (!$this->isParticipantsAnswerFixed($question_id)) {
2109 $this->updateWorkingTime();
2110 $this->saveQuestionSolution(
false);
2112 $this->setAnswerChangedParameter(
true);
2121 $question_id = $this->test_sequence->getQuestionForSequence(
2122 $this->getCurrentSequenceElement()
2125 if (!$this->isParticipantsAnswerFixed($question_id)) {
2126 if ($this->saveQuestionSolution(
true)) {
2127 $this->removeIntermediateSolution();
2128 $this->setAnswerChangedParameter(
false);
2132 $this->test_sequence->setQuestionChecked($question_id);
2133 $this->test_sequence->saveToDb();
2134 } elseif ($this->
object->isForceInstantFeedbackEnabled()) {
2135 $this->test_sequence->setQuestionChecked($question_id);
2136 $this->test_sequence->saveToDb();
2139 $this->
ctrl->setParameter($this,
'instresp', 1);
2142 if ($this->getNavigationUrlParameter()) {
2143 $this->saveNavigationPreventConfirmation();
2144 $this->registerForcedFeedbackNavUrl($this->getNavigationUrlParameter());
2152 $this->handleCheckTestPassValid();
2153 $last_sequence_element = $this->getCurrentSequenceElement();
2154 $next_sequence_element = $this->test_sequence->getNextSequence($last_sequence_element);
2156 $question_id = $this->test_sequence->getQuestionForSequence($last_sequence_element);
2157 $is_worked_through = $this->questionrepository->lookupResultRecordExist(
2158 $this->test_session->getActiveId(),
2160 $this->test_session->getPass()
2163 if (!$is_worked_through) {
2164 if ($this->
logger->isLoggingEnabled()
2165 && !$this->getObject()->getAnonymity()) {
2166 $this->
logger->logParticipantInteraction(
2167 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
2168 $this->object->getRefId(),
2170 $this->user->getId(),
2171 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
2172 TestParticipantInteractionTypes::QUESTION_SKIPPED,
2177 if ($this->
object->isPostponingEnabled()) {
2178 $this->handleQuestionPostponing($question_id);
2182 if (!$this->isValidSequenceElement($next_sequence_element)) {
2183 $next_sequence_element = $this->test_sequence->getFirstSequence();
2186 $this->
ctrl->setParameter($this,
'sequence', $next_sequence_element);
2187 $this->
ctrl->setParameter($this,
'pmode',
'');
2194 $this->handleCheckTestPassValid();
2196 $sequence_element = $this->test_sequence->getPreviousSequence(
2197 $this->getCurrentSequenceElement()
2200 if (!$this->isValidSequenceElement($sequence_element)) {
2201 $sequence_element = $this->test_sequence->getLastSequence();
2204 $this->
ctrl->setParameter($this,
'sequence', $sequence_element);
2205 $this->
ctrl->setParameter($this,
'pmode',
'');
2212 $this->tpl->addBlockFile(
2213 $this->getContentBlockName(),
2215 'tpl.il_as_tst_question_summary.html',
2216 'components/ILIAS/Test'
2223 let key_event = (
event) => {
2224 if(
event.key === 13 &&
event.target.tagName.toLowerCase() ===
"a" ) {
2227 if (
event.key === 13 &&
2228 event.target.tagName.toLowerCase() !==
"textarea" &&
2229 (
event.target.tagName.toLowerCase() !==
"input" ||
event.target.type.toLowerCase() !==
"submit")) {
2230 event.preventDefault();
2234 let
form = document.getElementById(
'taForm');
2235 form.onkeyup = key_event;
2236 form.onkeydown = key_event;
2237 form.onkeypress = key_event;
2239 $this->tpl->addOnLoadCode($onload_js);
2240 $this->tpl->addBlockFile(
2241 $this->getContentBlockName(),
2243 'tpl.il_as_tst_output.html',
2244 'components/ILIAS/Test'
2256 if ($this->test_session->isPasswordChecked() ===
true) {
2260 if ($this->
ctrl->getNextClass() ===
'iltestpasswordprotectiongui') {
2264 if (!$this->password_checker->isPasswordProtectionPageRedirectRequired()) {
2265 $this->test_session->setPasswordChecked(
true);
2269 $this->
ctrl->setParameterByClass(self::class,
'lock', $this->getLockParameter());
2272 $this->
ctrl->setParameterByClass(ilTestPasswordProtectionGUI::class,
'nextCommand', $next_command);
2273 $this->
ctrl->redirectByClass(ilTestPasswordProtectionGUI::class,
'showPasswordForm');
2278 if ($this->
object->isInstantFeedbackAnswerFixationEnabled()) {
2279 return $this->test_sequence->isQuestionChecked($question_id);
2282 if ($this->
object->isFollowupQuestionAnswerFixationEnabled()) {
2283 return $this->isForcedFeedbackNavUrlRegistered() || $this->test_sequence->isNextQuestionPresented($question_id);
2294 return $this->
lng->txt(
"save_introduction");
2299 $this->ass_settings =
new ilSetting(
'assessment');
2310 $this->
object->getTestId(),
2311 $this->object->getRefId(),
2312 $this->skills_service->profile(),
2313 $this->skills_service->personal()
2316 $skill_evaluation->setUserId($test_session->
getUserId());
2317 $skill_evaluation->setActiveId($test_session->
getActiveId());
2318 $skill_evaluation->setPass($test_session->
getPass());
2320 $skill_evaluation->setNumRequiredBookingsForSkillTriggering(
2321 $this->
object->getGlobalSettings()->getSkillTriggeringNumberOfAnswers()
2324 $question_list = $this->buildTestPassQuestionList();
2325 $question_list->load();
2326 $skill_evaluation->init($question_list);
2327 $skill_evaluation->evaluate(
2328 $this->
object->getTestResult(
2335 $skill_evaluation->handleSkillTriggering();
2342 $confirmation->setFormAction($this->
ctrl->getFormAction($this));
2343 $confirmation->setCancelCmd(
'cancelAnswerOptionalQuestions');
2344 $confirmation->setConfirmCmd(
'confirmAnswerOptionalQuestions');
2346 $confirmation->build($this->
object->isFixedTest());
2348 $this->populateHelperGuiContent($confirmation);
2353 $this->test_sequence->setAnsweringOptionalQuestionsConfirmed(
true);
2354 $this->test_sequence->saveToDb();
2356 $this->
ctrl->setParameter($this,
'activecommand',
'gotoquestion');
2357 $this->
ctrl->redirect($this,
'redirectQuestion');
2362 if ($this->
object->getListOfQuestions()) {
2363 $this->
ctrl->setParameter($this,
'activecommand',
'summary');
2365 $this->
ctrl->setParameter($this,
'activecommand',
'previous');
2368 $this->
ctrl->redirect($this,
'redirectQuestion');
2376 $this->tpl->setVariable($this->getContentBlockName(), $this->
ctrl->getHTML($helperGui));
2382 $navigation_toolbar->setSuspendTestButtonEnabled($this->
object->getShowCancel());
2383 $navigation_toolbar->setUserPassOverviewEnabled($this->
object->getUsrPassOverviewEnabled());
2384 $navigation_toolbar->setFinishTestCommand($this->getFinishTestCommand());
2385 return $navigation_toolbar;
2396 if (!$this->isParticipantsAnswerFixed($question_id)) {
2400 if ($this->
object->getShowMarker()) {
2404 if (count($solved_array) > 0) {
2405 $solved = array_pop($solved_array);
2406 $solved = $solved[
"solved"];
2411 $navigationGUI->setQuestionMarked(
true);
2414 $navigationGUI->setQuestionMarked(
false);
2419 return $navigationGUI;
2433 if ($this->
object->getSpecificAnswerFeedback()
2434 || $this->object->getGenericAnswerFeedback()
2435 || $this->object->getAnswerFeedbackPoints()
2436 || $this->object->getInstantFeedbackSolution()) {
2437 $navigation_gui->setAnswerFreezingEnabled($this->
object->isInstantFeedbackAnswerFixationEnabled());
2439 if ($this->
object->isForceInstantFeedbackEnabled()) {
2440 $navigation_gui->setForceInstantResponseEnabled(
true);
2447 if ($this->
object->getShowMarker()) {
2451 if (count($solved_array) > 0) {
2452 $solved = array_pop($solved_array);
2453 $solved = $solved[
'solved'];
2456 if ($solved === 1) {
2458 $navigation_gui->setQuestionMarked(
true);
2461 $navigation_gui->setQuestionMarked(
false);
2464 return $navigation_gui;
2469 if (!$this->
object->getListOfQuestionsEnd()) {
2481 $answer_feedback_enabled = $this->
object->getSpecificAnswerFeedback();
2484 $this->test_session->getActiveId(), #active_id
2485 $this->test_session->getPass(), #pass
2486 false, #graphical_output
2487 false, #result_output
2488 true, #show_question_only
2489 $answer_feedback_enabled, #show_feedback
2490 false, #show_correct_solution
2491 false, #show_manual_scoring
2492 true #show_question_text
2497 $this->isShowingPostponeStatusReguired($question_gui->
getObject()->getId()),
2498 $this->test_session->getActiveId(),
2502 $tpl =
new ilTemplate(
'tpl.tst_player_response_modal.html',
true,
true,
'components/ILIAS/Test');
2505 $saved_tpl = $this->tpl;
2507 $this->populateInstantResponseBlocks($question_gui,
true);
2508 $this->tpl = $saved_tpl;
2510 $tpl->setVariable(
'QUESTION_OUTPUT', $pageoutput);
2511 $this->tpl->setVariable(
'INSTANT_RESPONSE_MODAL', $this->getQuestionFeedbackModalHtml($tpl, $nav_url));
2516 $modal = $this->ui_factory->modal()->roundtrip(
2517 $this->
lng->txt(
'tst_instant_feedback'),
2518 $this->ui_factory->legacy()->content($tpl->
get()),
2520 )->withActionButtons([
2521 $this->ui_factory->button()->standard($this->lng->txt(
'proceed'), $nav_url)
2524 return $this->ui_renderer->render([
2525 $modal->withOnLoad($modal->getShowSignal())
2535 $response_available =
false;
2536 $jump_to_response =
false;
2540 if ($this->
object->getInstantFeedbackSolution()) {
2541 $show_question_inline_score = $this->determineInlineScoreDisplay();
2545 $this->test_session->getActiveId(), #active_id
2546 $this->test_session->getPass(), #pass
2547 false, #graphical_output
2548 $show_question_inline_score, #result_output
2549 true, #show_question_only
2550 false, #show_feedback
2551 true, #show_correct_solution
2552 false, #show_manual_scoring
2553 false #show_question_text
2555 $solutionoutput = str_replace(
'<h1 class="ilc_page_title_PageTitle"></h1>',
'', $solutionoutput);
2556 $this->populateSolutionBlock($solutionoutput);
2557 $response_available =
true;
2558 $jump_to_response =
true;
2561 $reachedPoints = $question_gui->
getObject()->getAdjustedReachedPoints(
2562 $this->test_session->getActiveId(),
2567 $maxPoints = $question_gui->
getObject()->getMaximumPoints();
2569 $solutionCorrect = ($reachedPoints == $maxPoints);
2573 if ($this->
object->getAnswerFeedbackPoints()) {
2574 $this->populateScoreBlock($reachedPoints, $maxPoints);
2575 $response_available =
true;
2576 $jump_to_response =
true;
2581 if ($this->
object->getGenericAnswerFeedback()) {
2582 if ($this->populateGenericFeedbackBlock($question_gui, $solutionCorrect)) {
2583 $response_available =
true;
2584 $jump_to_response =
true;
2590 if ($this->
object->getSpecificAnswerFeedback()) {
2593 $jump_to_response =
false;
2594 } elseif ($this->populateSpecificFeedbackBlock($question_gui)) {
2595 $response_available =
true;
2596 $jump_to_response =
true;
2600 $this->populateFeedbackBlockHeader($jump_to_response);
2601 if (!$response_available) {
2603 $this->populateFeedbackBlockMessage($this->
lng->txt(
'tst_feedback_is_given_inline'));
2605 $this->populateFeedbackBlockMessage($this->
lng->txt(
'tst_feedback_not_available_for_answer'));
2612 if ($withFocusAnchor) {
2613 $this->tpl->setCurrentBlock(
'inst_resp_id');
2614 $this->tpl->setVariable(
'INSTANT_RESPONSE_FOCUS_ID',
'focus');
2615 $this->tpl->parseCurrentBlock();
2618 $this->tpl->setCurrentBlock(
'instant_response_header');
2619 $this->tpl->setVariable(
'INSTANT_RESPONSE_HEADER', $this->
lng->txt(
'tst_feedback'));
2620 $this->tpl->parseCurrentBlock();
2625 $this->tpl->setCurrentBlock(
'instant_response_message');
2626 $this->tpl->setVariable(
'INSTANT_RESPONSE_MESSAGE', $a_message);
2627 $this->tpl->parseCurrentBlock();
2633 if ($this->getSequenceElementParameter()) {
2634 return $this->getSequenceElementParameter();
2637 return $this->test_session->getLastSequence();
2642 if ($this->testrequest->isset(
'sequence')) {
2643 return $this->testrequest->int(
'sequence');
2651 if ($this->testrequest->isset(
'pmode')) {
2652 return $this->testrequest->raw(
'pmode');
2660 return $this->testrequest->isInstanceResponseRequested();
2666 if ($this->testrequest->isset(
'nextcmd')) {
2667 $nextcmd = $this->testrequest->strVal(
'nextcmd');
2670 return $nextcmd !==
'' ? $nextcmd :
null;
2675 return $this->testrequest->int(
'nextseq');
2680 $navigation_url = $this->testrequest->strVal(
'test_player_navigation_url');
2681 if ($navigation_url !==
'') {
2682 $navigation_url_parts = parse_url($navigation_url);
2685 if (!isset($navigation_url_parts[
'host']) || ($ilias_url_parts[
'host'] === $navigation_url_parts[
'host'])) {
2686 return $navigation_url;
2694 return !empty($this->testrequest->raw(
'test_answer_changed'));
2699 $this->
ctrl->setParameter($this,
'test_answer_changed', $changed ?
'1' :
'0');
2704 if ($this->getAnswerChangedParameter()) {
2705 $this->saveQuestionSolution(
false);
2707 $this->removeIntermediateSolution();
2709 $this->setAnswerChangedParameter($this->getAnswerChangedParameter());
2714 if ($this->testrequest->retrieveBoolFromPost(
'save_on_navigation_prevent_confirmation')) {
2718 if ($this->testrequest->retrieveBoolFromPost(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM)) {
2719 ilSession::set(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM,
true);
2727 if (!$from_cache || !isset($this->cached_question_guis[$question_id])) {
2728 $question_gui = $this->
object->createQuestionGUI(
"", $question_id);
2732 $question->setShuffler($this->shuffler->getAnswerShuffleFor(
2734 $this->test_session->getActiveId(),
2735 $this->test_session->getPass()
2741 $this->initTestQuestionConfig($question_gui->
getObject());
2744 $this->cached_question_guis[$question_id] = $question_gui;
2747 return $this->cached_question_guis[$question_id];
2752 if ($from_cache && isset($this->cached_question_objects[$question_id])) {
2753 return $this->cached_question_objects[$question_id];
2756 $ass_settings =
new ilSetting(
'assessment');
2759 $process_locker_factory->setQuestionId($question->getId());
2760 $process_locker_factory->setUserId($this->
user->getId());
2761 $question->setProcessLocker($process_locker_factory->getLocker());
2763 $this->initTestQuestionConfig($question);
2765 $this->cached_question_objects[$question_id] = $question;
2772 $this->
object->isPreviousSolutionReuseEnabled($this->test_session->getActiveId())
2780 .
"active={$this->test_session->getActiveId()} "
2781 .
"qId=$question_id seq=$sequence_element "
2782 . serialize($this->test_sequence)
2785 $this->
ctrl->setParameter($this,
'sequence', $this->test_sequence->getFirstSequence());
2791 if ($this->
object->getKioskMode()) {
2792 $this->tpl->addBlockfile($this->getContentBlockName(),
'content',
"tpl.il_as_tst_kiosk_mode_content.html",
"components/ILIAS/Test");
2793 $this->tpl->setContent($content_html);
2796 $this->tpl->setVariable($this->getContentBlockName(), $content_html);
2804 $signals = [self::DISCARD_MODAL => $this->populateDiscardSolutionModal()];
2806 if ($this->
object->isFollowupQuestionAnswerFixationEnabled()) {
2807 $signals[self::LOCKS_CHANGED_MODAL] = $this->populateNextLocksChangedModal();
2808 $signals[self::LOCKS_UNCHANGED_MODAL] = $this->populateNextLocksUnchangedModal();
2816 $modal = $this->ui_factory->modal()->interruptive(
2817 $this->
lng->txt(
'discard_answer'),
2818 $this->lng->txt(
'discard_answer_confirmation'),
2820 )->withActionButtonLabel($this->
lng->txt(
'discard_answer'));
2822 $this->tpl->setCurrentBlock(
'discard_solution_modal');
2823 $this->tpl->setVariable(
'DISCARD_SOLUTION_MODAL', $this->ui_renderer->render($modal));
2824 $this->tpl->parseCurrentBlock();
2825 return $modal->getShowSignal();
2830 $modal = $this->ui_factory->modal()->interruptive(
2831 $this->
lng->txt(
'tst_nav_next_locks_empty_answer_header'),
2832 $this->lng->txt(
'tst_nav_next_locks_empty_answer_confirm'),
2833 'javascript:il.TestPlayerQuestionEditControl.confirmNextLocksUnchanged()'
2834 )->withActionButtonLabel($this->
lng->txt(
'tst_proceed'));
2836 $this->tpl->setCurrentBlock(
'next_locks_unchanged_modal');
2837 $this->tpl->setVariable(
'NEXT_LOCKS_UNCHANGED_MODAL', $this->ui_renderer->render($modal));
2838 $this->tpl->parseCurrentBlock();
2839 return $modal->getShowSignal();
2844 $empty_signal = new \ILIAS\UI\Implementation\Component\Signal(
'');
2845 if ($this->isFollowUpQuestionLocksConfirmationPrevented()) {
2846 return $empty_signal;
2849 $modal_message = $this->ui_factory->messageBox()->confirmation(
2850 $this->
lng->txt(
'tst_nav_next_locks_current_answer_confirm')
2852 $modal_checkbox = $this->ui_factory->input()->field()->checkbox(
2853 $this->
lng->txt(
'tst_dont_show_msg_again_in_current_session')
2854 )->withDedicatedName(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM);
2856 $modal = $this->ui_factory->modal()->roundtrip(
2857 $this->
lng->txt(
'tst_nav_next_locks_current_answer_header'),
2859 [ $modal_checkbox ],
2860 'javascript:il.TestPlayerQuestionEditControl.confirmNextLocksChanged()'
2861 )->withSubmitLabel($this->
lng->txt(
'tst_proceed'));
2863 $this->tpl->setCurrentBlock(
'next_locks_changed_modal');
2864 $this->tpl->setVariable(
'NEXT_LOCKS_CHANGED_MODAL', $this->ui_renderer->render($modal));
2865 $this->tpl->parseCurrentBlock();
2866 return $modal->getShowSignal();
2869 public const FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM =
'followup_qst_locks_prevent_confirmation';
2873 ilSession::set(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM,
true);
2878 if (
ilSession::get(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM) ==
null) {
2882 return ilSession::get(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM);
2888 $state = $question_gui->
getObject()->lookupForExistingSolutions($this->test_session->getActiveId(), $this->test_session->getPass());
2889 $config[
'isAnswered'] = $state[
'authorized'];
2890 $config[
'isAnswerChanged'] = $state[
'intermediate'] || $this->getAnswerChangedParameter();
2891 $config[
'isAnswerFixed'] = $this->isParticipantsAnswerFixed($question_gui->
getObject()->getId());
2894 $config[
'autosaveUrl'] =
'';
2895 $config[
'autosaveInterval'] = 0;
2898 $config[
'autosaveInterval'] = $this->
object->getMainSettings()->getQuestionBehaviourSettings()->getAutosaveInterval();
2901 $question_config = $question_gui->
getObject()->getTestPresentationConfig();
2903 $config[
'withFormChangeDetection'] = $question_config->isFormChangeDetectionEnabled();
2906 $config[
'withBackgroundChangeDetection'] = $question_config->isBackgroundChangeDetectionEnabled();
2910 $config[
'forcedInstantFeedback'] = $this->
object->isForceInstantFeedbackEnabled();
2911 $config[
'questionLocked'] = $this->isParticipantsAnswerFixed($question_gui->
getObject()->getId());
2912 $config[
'nextQuestionLocks'] = $this->
object->isFollowupQuestionAnswerFixationEnabled();
2913 $config[
'autosaveFailureMessage'] = $this->
lng->txt(
'autosave_failed');
2916 $config[
'modalSignals'] = array_map(fn(
Signal $signal) => $signal->
getId(), $this->modal_signals);
2917 $config[
'preventConfirmationParam'] = self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM;
2919 $this->tpl->addJavascript(
'assets/js/ilTestPlayerQuestionEditControl.js');
2920 $this->tpl->addOnLoadCode(
'il.TestPlayerQuestionEditControl.init(' . json_encode($config) .
')');
2926 return self::PRESENTATION_MODE_EDIT;
2934 $forced_feeback_navigation_url =
ilSession::get(
'forced_feedback_navigation_url');
2935 $forced_feeback_navigation_url[$this->test_session->getActiveId()] = $forced_feedback_nav_url;
2936 ilSession::set(
'forced_feedback_navigation_url', $forced_feeback_navigation_url);
2944 $forced_feedback_navigation_url =
ilSession::get(
'forced_feedback_navigation_url');
2945 if (!isset($forced_feedback_navigation_url[$this->test_session->getActiveId()])) {
2949 return $forced_feedback_navigation_url[$this->test_session->getActiveId()];
2954 return $this->getRegisteredForcedFeedbackNavUrl() !==
null;
2959 $forced_feedback_navigation_url =
ilSession::get(
'forced_feedback_navigation_url');
2960 if (isset($forced_feedback_navigation_url[$this->test_session->getActiveId()])) {
2961 unset($forced_feedback_navigation_url[$this->test_session->getActiveId()]);
2962 ilSession::set(
'forced_feedback_navigation_url', $forced_feedback_navigation_url);
2968 $this->updateWorkingTime();
2969 $this->saveQuestionSolution(
false);
2980 if ($sequence_element ===
false) {
2984 if ($sequence_element < 1) {
2988 if (!$this->test_sequence->getPositionOfSequence($sequence_element)) {
2997 if ($this->
object->isForceInstantFeedbackEnabled()) {
2998 $this->submitSolutionCmd();
3002 if ($this->saveQuestionSolution(
true,
false)) {
3003 $this->test_sequence->getQuestionForSequence(
3004 $this->getCurrentSequenceElement()
3007 $this->removeIntermediateSolution();
3009 $next_sequence_element = $this->test_sequence->getNextSequence($this->getCurrentSequenceElement());
3011 if (!$this->isValidSequenceElement($next_sequence_element)) {
3012 $next_sequence_element = $this->test_sequence->getFirstSequence();
3015 $this->test_session->setLastSequence($next_sequence_element ?? 0);
3016 $this->test_session->saveToDb();
3018 $this->
ctrl->setParameter($this,
'sequence', $next_sequence_element);
3019 $this->
ctrl->setParameter($this,
'pmode',
'');
3028 $this->test_sequence->postponeQuestion($question_id);
3029 $this->test_sequence->saveToDb();
3034 $testObj =
new ilObjTest($this->ref_id,
true);
3036 $participants = $testObj->getActiveParticipantList();
3037 $participant = $participants->getParticipantByActiveId($this->testrequest->getActiveId());
3038 if ($participant && $participant->hasUnfinishedPasses()) {
3041 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
'tst_current_run_no_longer_valid'),
true);
3042 if ($with_redirect) {
3043 $this->
ctrl->redirectByClass([
3044 ilRepositoryGUI::class,
3045 ilObjTestGUI::class,
3046 TestScreenGUI::class
3053 if ($this->test_session->getActiveId() > 0) {
3054 if ($this->test_sequence->hasRandomQuestionsForPass($this->test_session->getActiveId(), $this->test_session->getPass()) > 0) {
3056 __METHOD__ .
' Random Questions allready exists for user ' .
3057 $this->
user->getId() .
' in test ' . $this->object->getTestId()
3063 $this->
logger->info(__METHOD__ .
' ' . sprintf(
3064 $this->
lng->txt(
"error_random_question_generation"),
3065 $this->user->getId(),
3066 $this->object->getTestId()
3082 $this->component_repository,
3084 $this->questionrepository
3086 $questionSetConfig->loadFromDb();
3091 $sourcePoolDefinitionList->loadDefinitions();
3093 $this->process_locker->executeRandomPassBuildOperation(
function () use ($questionSetConfig, $sourcePoolDefinitionList) {
3094 if (!$this->performTearsAndAngerBrokenConfessionChecks()) {
3103 $sourcePoolDefinitionList,
3104 $stagingPoolQuestionList
3107 $questionSetBuilder->performBuild($this->test_session);
3109 }, $sourcePoolDefinitionList->hasTaxonomyFilters());
3114 $ass_settings =
new ilSetting(
'assessment');
3117 $userSolutionAdopter->setUserId($this->
user->getId());
3118 $userSolutionAdopter->setActiveId($this->test_session->getActiveId());
3119 $userSolutionAdopter->setTargetPass($this->test_sequence->getPass());
3120 $userSolutionAdopter->setQuestionIds($this->test_sequence->getOptionalQuestions());
3122 $userSolutionAdopter->perform();
3127 $this->tpl->setOnScreenMessage(
'failure', sprintf($this->
lng->txt(
'tst_objective_oriented_test_pass_without_questions'), $this->object->getTitle()),
true);
3128 $this->
ctrl->redirectByClass(ilObjTestGUI::class);
3133 $is_next_primary =
true;
3135 if ($this->
object->isForceInstantFeedbackEnabled()) {
3136 $is_next_primary =
false;
3139 $questions_missing_result = $this->questionrepository->getQuestionsMissingResultRecord(
3140 $this->test_session->getActiveId(),
3141 $this->test_session->getPass(),
3142 $this->test_sequence->getOrderedSequenceQuestions()
3145 if ($questions_missing_result === []) {
3150 if (count($questions_missing_result) === 1
3151 && $current_question_id === current($questions_missing_result)) {
3156 return $is_next_primary;
3161 $title_content = $this->ui_factory->listing()->property();
3163 if ($this->
object->getShowKioskModeParticipant()) {
3164 $pax_name_label = $this->
lng->txt(
"conf_user_name");
3168 $pax_name_value =
"<span class='il-test-kiosk-head__participant-name'>"
3169 . $this->
user->getFullname() .
"</span>";
3170 $title_content = $title_content->withProperty($pax_name_label, $pax_name_value,
false);
3173 if ($this->
object->isShowExamIdInTestPassEnabled()) {
3174 $exam_id_label = $this->
lng->txt(
"exam_id_label");
3176 $this->test_session->getActiveId(),
3177 $this->test_session->getPass(),
3178 $this->object->getId()
3180 $title_content = $title_content->withProperty($exam_id_label, $exam_id_value);
3183 if ($this->
object->getShowKioskModeTitle()) {
3184 $test_title_label = $this->
lng->txt(
"test");
3185 $test_title_value = $this->
object->getTitle();
3186 $title_content = $title_content->withProperty($test_title_label, $test_title_value,
false);
3189 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 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)
sendNewPassFinishedNotificationEmailIfActivated(int $active_id, int $pass)
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
getId()
Get the ID of this signal.
static http()
Fetches the global http state from ILIAS.
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
form( $class_path, string $cmd, string $submit_caption="")
TestParticipantInteractionTypes