19declare(strict_types=1);
83 $this->ref_id = $this->testrequest->getRefId();
89 $this->
tabs->clearTargets();
91 $cmd = $this->
ctrl->getCmd();
92 $next_class = $this->
ctrl->getNextClass($this);
95 if ($cmd ===
'autosave') {
96 echo $this->
lng->txt(
'autosave_failed') .
': ' . $read_access;
99 $this->tpl->setOnScreenMessage(
'failure', $read_access,
true);
100 $this->
ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, TestScreenGUI::class]);
103 $this->
ctrl->saveParameter($this,
"sequence");
104 $this->
ctrl->saveParameter($this,
"pmode");
105 $this->
ctrl->saveParameter($this,
"active_id");
110 $this->test_session = $testSessionFactory->getSession($this->testrequest->int(
'active_id'));
119 $this->test_sequence->loadFromDb();
120 $this->test_sequence->loadQuestions();
128 $instance_name = $this->
settings->get(
'short_inst_name') ??
'';
129 if (trim($instance_name) ===
'') {
130 $instance_name =
'ILIAS';
132 $this->global_screen->tool()->context()->current()->addAdditionalData(
136 $this->global_screen->tool()->context()->current()->addAdditionalData(
138 $this->
object->getKioskMode()
140 $this->global_screen->tool()->context()->current()->addAdditionalData(
144 $this->global_screen->tool()->context()->current()->addAdditionalData(
149 switch ($next_class) {
150 case 'ilassquestionpagegui':
156 $page_gui->setFileDownloadLink(
157 $this->
ctrl->getLinkTargetByClass(ilObjTestGUI::class,
'downloadFile')
159 $ret = $this->
ctrl->forwardCommand($page_gui);
162 case 'iltestsubmissionreviewgui':
168 $ret = $this->
ctrl->forwardCommand($gui);
171 case 'ilassspecfeedbackpagegui':
172 case 'ilassgenfeedbackpagegui':
173 $id = $this->testrequest->int(
'pg_id');
174 if ($this->
ctrl->getCmd() !==
'displayMediaFullscreen'
180 $next_class ===
'ilassgenfeedbackpagegui' ?
'qfbg' :
'qfbs',
182 ))->displayMediaFullscreen();
185 case 'iltestpasswordprotectiongui':
193 $this->password_checker,
197 $ret = $this->
ctrl->forwardCommand($gui);
205 if ($cmd ===
'outQuestionSummary'
206 || $cmd ===
'submitSolution') {
210 if ($cmd ===
'showQuestion') {
212 $testPassesSelector->setActiveId($this->test_session->getActiveId());
213 $testPassesSelector->setLastFinishedPass($this->test_session->getLastFinishedPass());
215 if (!$testPassesSelector->openPassExists()) {
216 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'tst_pass_finished'),
true);
217 $this->
ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, TestScreenGUI::class]);
222 $ret = $this->$cmd();
233 if (!$this->rbac_system->checkAccess(
'read', $this->object->getRefId())) {
234 return $this->
lng->txt(
'cannot_execute_test');
237 $participant_access = (
new ilTestAccess($this->
object->getRefId()))->isParticipantAllowed(
241 if ($participant_access !== ParticipantAccess::ALLOWED) {
242 return $participant_access->getAccessForbiddenMessage($this->
lng);
250 $executable = $this->
object->isExecutable($this->test_session, $this->test_session->getUserId());
252 if (!$executable[
'executable']) {
253 $this->tpl->setOnScreenMessage(
'info', $executable[
'errormessage'],
true);
254 $this->
ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, TestScreenGUI::class]);
261 throw new ilTestException(
'active id given does not relate to current user!');
288 $this->process_locker = $process_lockerFactory->withContextId((
int) $activeId)->getLocker();
300 $tagging_gui->setObject($this->
object->getId(), $this->object->getType());
301 $tagging_gui->saveInput();
302 $this->
ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, ilInfoScreenGUI::class]);
311 $this->
object->updateWorkingTime(
ilSession::get(
"active_time_id"));
316 $this->
object->startWorkingTime(
317 $this->test_session->getActiveId(),
318 $this->test_session->getPass()
328 $this->test_session->getActiveId(),
329 $this->test_session->getPass()
334 bool $authorized =
true,
354 if ($question_obj ===
null) {
358 $saved = ($force || $this->
canSaveResult()) && $this->
save($question_obj, $authorized);
361 $this->
ctrl->setParameter($this,
'save_error',
'1');
362 ilSession::set(
'previouspost', $this->testrequest->getParsedBody());
374 $formtimestamp = $this->testrequest->int(
'formtimestamp');
386 $q_id = $this->test_sequence->getQuestionForSequence($this->testrequest->int(
'sequence'));
388 if ($this->isParticipantsAnswerFixed($q_id)) {
394 if ($q_id ===
null) {
398 return $this->getQuestionInstance($q_id);
403 $active_id = $this->test_session->getActiveId();
413 if ($authorized && $this->test_session->isObjectiveOriented()) {
415 $objectivesAdapter->updateQuestionResult($this->test_session, $question_obj);
418 if ($authorized && $this->
object->isSkillServiceToBeConsidered()) {
419 $this->handleSkillTriggering($this->test_session);
422 if ($authorized && $this->
logger->isLoggingEnabled()
423 && !$this->getObject()->getAnonymity()
425 $this->logger->getAdditionalInformationGenerator(),
426 $this->getObject()->getRefId(),
429 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
430 TestParticipantInteractionTypes::ANSWER_SUBMITTED
432 $this->
logger->logParticipantInteraction($interaction);
439 return !$this->
object->endingTimeReached() && !$this->isMaxProcessingTimeReached() && !$this->isNrOfTriesReached();
444 $this->
ctrl->redirectByClass(TestScreenGUI::class, TestScreenGUI::DEFAULT_CMD);
449 $active_id = $this->test_session->getActiveId();
450 $starting_time = $this->
object->getStartingTimeOfUser($active_id);
451 if ($starting_time ===
false) {
454 return $this->
object->isMaxProcessingTimeReached($starting_time, $active_id);
460 $show_question_inline_score =
false;
461 if ($this->
object->getAnswerFeedbackPoints()) {
462 $show_question_inline_score =
true;
463 return $show_question_inline_score;
465 return $show_question_inline_score;
470 $this->tpl->setCurrentBlock(
'test_nav_toolbar');
471 $this->tpl->setVariable(
'TEST_NAV_TOOLBAR', $toolbar_gui->getHTML());
472 $this->tpl->parseCurrentBlock();
474 if ($this->finish_test_modal ===
null) {
478 $this->tpl->setCurrentBlock(
'finish_test_modal');
479 $this->tpl->setVariable(
481 $this->ui_renderer->render(
482 $this->finish_test_modal->withOnLoad($this->finish_test_modal->getShowSignal())
485 $this->tpl->parseCurrentBlock();
490 if (!$this->isFirstQuestionInSequence($sequence_element)) {
491 $this->populatePreviousButtons();
494 if (!$this->isLastQuestionInSequence($sequence_element)) {
495 $this->populateNextButtons($primary_next);
501 $this->populateUpperPreviousButtonBlock();
502 $this->populateLowerPreviousButtonBlock();
507 $this->populateUpperNextButtonBlock($primary_next);
508 $this->populateLowerNextButtonBlock($primary_next);
513 $button = $this->buildNextButtonInstance($primary_next);
515 $this->tpl->setCurrentBlock(
"next_bottom");
516 $this->tpl->setVariable(
"BTN_NEXT_BOTTOM", $this->ui_renderer->render($button));
517 $this->tpl->parseCurrentBlock();
522 $button = $this->buildNextButtonInstance($primaryNext);
524 $this->tpl->setCurrentBlock(
"next");
525 $this->tpl->setVariable(
"BTN_NEXT", $this->ui_renderer->render($button));
526 $this->tpl->parseCurrentBlock();
531 $button = $this->buildPreviousButtonInstance();
533 $this->tpl->setCurrentBlock(
"prev_bottom");
534 $this->tpl->setVariable(
"BTN_PREV_BOTTOM", $this->ui_renderer->render($button));
535 $this->tpl->parseCurrentBlock();
540 $button = $this->buildPreviousButtonInstance();
542 $this->tpl->setCurrentBlock(
"prev");
543 $this->tpl->setVariable(
"BTN_PREV", $this->ui_renderer->render($button));
544 $this->tpl->parseCurrentBlock();
555 $button = $this->ui_factory->button()->primary(
556 $this->
lng->txt(
'next_question') . $this->ui_renderer->render($this->ui_factory->symbol()->glyph()->next()),
558 )->withUnavailableAction(
true)
561 $button = $this->ui_factory->button()->standard(
562 $this->
lng->txt(
'next_question') . $this->ui_renderer->render($this->ui_factory->symbol()->glyph()->next()),
564 )->withUnavailableAction(
true)
577 $button = $this->ui_factory->button()->standard(
578 $this->ui_renderer->render($this->ui_factory->symbol()->glyph()->back()) . $this->lng->txt(
'previous_question'),
580 )->withUnavailableAction(
true)
587 return static function (
string $id) use ($target, $cmd):
string {
588 return "document.getElementById('{$id}').addEventListener('click', "
589 .
"(e) => {il.TestPlayerQuestionEditControl.checkNavigation('{$target}', '{$cmd}', e);}"
591 .
"document.getElementById('{$id}').removeAttribute('disabled');";
600 $solutionValues = $question_gui->
getObject()->getSolutionValues(
601 $this->test_session->getActiveId(),
606 $question_gui->
getObject()->fetchIndexedValuesFromValuePairs($solutionValues)
609 if (!empty($feedback)) {
610 $this->tpl->setCurrentBlock(
"specific_feedback");
611 $this->tpl->setVariable(
"SPECIFIC_FEEDBACK", $feedback);
612 $this->tpl->parseCurrentBlock();
624 $feedback = $question_gui->
getGenericFeedbackOutput($this->test_session->getActiveId(), $this->test_session->getPass());
626 if (strlen($feedback)) {
632 $this->tpl->setCurrentBlock(
"answer_feedback");
633 $this->tpl->setVariable(
"ANSWER_FEEDBACK", $feedback);
634 $this->tpl->setVariable(
"ILC_FB_CSS_CLASS", $cssClass);
635 $this->tpl->parseCurrentBlock();
643 $scoreInformation = sprintf(
644 $this->
lng->txt(
"you_received_a_of_b_points"),
649 $this->tpl->setCurrentBlock(
"received_points_information");
650 $this->tpl->setVariable(
"RECEIVED_POINTS_INFORMATION", $scoreInformation);
651 $this->tpl->parseCurrentBlock();
656 if (strlen($solutionoutput)) {
657 $this->tpl->setCurrentBlock(
"solution_output");
658 $this->tpl->setVariable(
"CORRECT_SOLUTION", $this->
lng->txt(
"tst_best_solution_is"));
659 $this->tpl->setVariable(
"QUESTION_FEEDBACK", $solutionoutput);
660 $this->tpl->parseCurrentBlock();
666 $this->tpl->setCurrentBlock(
"SyntaxStyle");
667 $this->tpl->setVariable(
668 "LOCATION_SYNTAX_STYLESHEET",
671 $this->tpl->parseCurrentBlock();
676 $this->tpl->setCurrentBlock(
"ContentStyle");
677 $this->tpl->setVariable(
678 "LOCATION_CONTENT_STYLESHEET",
681 $this->tpl->parseCurrentBlock();
691 if ($this->test_session->isAnonymousUser()) {
692 $this->test_session->setAccessCodeToSession($this->testrequest->strVal(
'anonymous_id'));
695 $this->
ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, ilInfoScreenGUI::class]);
706 $testStartLock = $this->getLockParameter();
707 $isFirstTestStartRequest =
false;
709 $this->process_locker->executeTestStartLockOperation(
function () use ($testStartLock, &$isFirstTestStartRequest) {
710 if ($this->test_session->lookupTestStartLock() !== $testStartLock) {
711 $this->test_session->persistTestStartLock($testStartLock);
712 $isFirstTestStartRequest = true;
716 if ($isFirstTestStartRequest) {
717 $this->handleUserSettings();
721 $this->
ctrl->setParameterByClass(
'ilObjTestGUI',
'lock', $testStartLock);
722 $this->
ctrl->redirectByClass([ilRepositoryGUI::class, ilObjTestGUI::class, ilInfoScreenGUI::class]);
727 if ($this->testrequest->isset(
'lock') && strlen($this->testrequest->raw(
'lock'))) {
728 return $this->testrequest->raw(
'lock');
736 $this->handleUserSettings();
738 $active_id = $this->test_session->getActiveId();
739 $this->
ctrl->setParameter($this,
"active_id", $active_id);
741 $active_time_id = $this->
object->startWorkingTime($active_id, $this->test_session->getPass());
745 if ($this->
object->isRandomTest()) {
746 if (!$this->test_sequence->hasRandomQuestionsForPass($active_id, $this->test_session->getPass())) {
748 $this->generateRandomTestPassForActiveUser();
752 $shuffle = $this->
object->getShuffleQuestions();
753 if ($this->
object->isRandomTest()) {
757 $this->test_result_repository->updateTestAttemptResult(
759 $this->test_session->getPass(),
761 $this->object->getId()
765 if (!$this->test_sequence->hasSequence()) {
766 $this->test_sequence->createNewSequence($this->
object->getQuestionCount(), $shuffle);
767 $this->test_sequence->saveToDb();
770 if ($this->
object->getListOfQuestionsStart()) {
774 $this->
ctrl->setParameter($this,
'sequence', $this->test_session->getLastSequence());
775 $this->
ctrl->setParameter($this,
'pmode',
'');
784 if ($this->test_session->isAnonymousUser()
785 && !$this->test_session->doesAccessCodeInSessionExists()) {
786 $access_code = $this->test_session->createNewAccessCode();
788 $this->test_session->setAccessCodeToSession($access_code);
789 $this->test_session->setAnonymousId($access_code);
790 $this->test_session->saveToDb();
795 if (!$this->test_session->isAnonymousUser()) {
796 $this->test_session->unsetAccessCodeInSession();
803 $this->tpl->addBlockFile($this->getContentBlockName(),
"adm_content",
"tpl.il_as_tst_anonymous_code_presentation.html",
"components/ILIAS/Test");
804 $this->tpl->setCurrentBlock(
"adm_content");
805 $this->tpl->setVariable(
"TEXT_ANONYMOUS_CODE_CREATED", $this->
lng->txt(
"tst_access_code_created"));
806 $this->tpl->setVariable(
"TEXT_ANONYMOUS_CODE", $this->test_session->getAccessCodeFromSession());
807 $this->tpl->setVariable(
"FORMACTION", $this->
ctrl->getFormAction($this));
809 $this->tpl->setVariable(
"TXT_CONFIRM", $this->
lng->txt(
"continue_work"));
810 $this->tpl->parseCurrentBlock();
823 if ($this->
object->getNrOfTries() != 1
824 && $this->object->getUsePreviousAnswers() == 1
826 $chb_use_previous_answers = 0;
827 if ($this->post_wrapper->has(
'chb_use_previous_answers')) {
828 $chb_use_previous_answers = $this->post_wrapper->retrieve(
829 'chb_use_previous_answers',
833 $this->
user->writePref(
"tst_use_previous_answers", (
string) $chb_use_previous_answers);
843 $this->performTestPassFinishedTasks(StatusOfAttempt::FINISHED_BY_DURATION);
845 $this->redirectAfterFinish();
850 $this->performTestPassFinishedTasks(StatusOfAttempt::FINISHED_BY_DURATION);
852 $this->redirectAfterFinish();
859 $this->tpl->addBlockFile($this->getContentBlockName(),
"adm_content",
"tpl.il_as_tst_redirect_autosave.html",
"components/ILIAS/Test");
860 $this->tpl->setVariable(
"TEXT_REDIRECT", $this->
lng->txt(
"redirectAfterSave"));
861 $this->tpl->setVariable(
"URL",
$url);
866 return $this->test_sequence->getQuestionForSequence($this->testrequest->int(
'sequence'));
875 if (!$this->
access->checkAccess(
'read',
'', $this->ref_id)) {
876 echo $this->
lng->txt(
'autosave_failed') .
': ' . $this->
lng->txt(
'msg_no_perm_read_item');
879 $test_can_run = $this->
object->isExecutable($this->test_session, $this->test_session->getUserId());
880 if (!$test_can_run[
'executable']) {
881 echo $test_can_run[
'errormessage'];
884 if ($this->testrequest->getPostKeys() === []) {
889 if (!$this->canSaveResult() || $this->isParticipantsAnswerFixed($this->getCurrentQuestionId())) {
894 if ($this->saveQuestionSolution(!$this->getAnswerChangedParameter(),
true)) {
895 echo $this->
lng->txt(
'autosave_success');
899 echo $this->
lng->txt(
'autosave_failed');
909 if (!$this->isParticipantsAnswerFixed($this->getCurrentQuestionId())) {
910 $this->saveQuestionSolution(
false,
true);
924 $question_id = $this->getCurrentQuestionId();
925 $state = $this->getQuestionInstance($question_id)->lookupForExistingSolutions(
926 $this->test_session->getActiveId(),
927 $this->test_session->getPass()
930 $result[
'isAnswered'] = $state[
'authorized'];
931 $result[
'isAnswerChanged'] = $state[
'intermediate'];
933 echo json_encode($result);
940 $this->saveQuestionSolution(
false,
true);
942 $this->setAnswerChangedParameter(
true);
949 $this->handleIntermediateSubmit();
950 $this->markQuestionCmd();
958 $question_id = $this->test_sequence->getQuestionForSequence(
959 $this->getCurrentSequenceElement()
962 $this->
object->setQuestionSetSolved(1, $question_id, $this->test_session->getUserId());
970 $this->handleIntermediateSubmit();
972 $this->unmarkQuestionCmd();
980 $question_id = $this->test_sequence->getQuestionForSequence(
981 $this->getCurrentSequenceElement()
984 $this->
object->setQuestionSetSolved(0, $question_id, $this->test_session->getUserId());
991 $this->handleCheckTestPassValid();
994 if ($this->testrequest->strVal(
'finalization_confirmed') !==
'confirmed') {
995 $this->finish_test_modal = $this->buildFinishTestModal();
996 $this->showQuestionCmd();
1005 $this->performTestPassFinishedTasks(StatusOfAttempt::FINISHED_BY_PARTICIPANT);
1007 if ($this->
logger->isLoggingEnabled()
1008 && !$this->getObject()->getAnonymity()
1009 && ($interaction = $this->logger->getInteractionFactory()->buildParticipantInteraction(
1012 $this->user->getId(),
1013 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
1017 $this->
logger->logParticipantInteraction($interaction);
1026 $this->test_session,
1028 $this->test_result_repository
1029 ))->performFinishTasks($this->process_locker, $status_of_attempt);
1030 $this->test_result_repository->updateTestResultCache($this->test_session->getActiveId());
1036 if (!$this->testrequest->isset(
'skipfinalstatement')
1037 && $this->object->getMainSettings()->getFinishingSettings()->getConcludingRemarksEnabled()) {
1041 if ($this->
object->canShowTestResults($this->test_session)) {
1042 $this->redirectBackCmd();
1046 $redirection_mode = $this->
object->getMainSettings()->getFinishingSettings()->getRedirectionMode();
1051 $redirection_url = $this->
object->getMainSettings()->getFinishingSettings()->getRedirectionUrl();
1052 if (empty($redirection_url)
1053 || $redirection_mode === RedirectionModes::NONE
1054 || $redirection_mode === RedirectionModes::IF_KIOSK_ACTIVATED
1055 && !$this->
object->getKioskMode()) {
1056 $this->redirectBackCmd();
1059 $this->
ctrl->redirectToURL($redirection_url);
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();
1965 return "ADM_CONTENT";
1967 if ($this->
object->getKioskMode()) {
1968 $this->tpl->setBodyClass(
"kiosk");
1969 $this->tpl->hideFooter();
1972 return "ADM_CONTENT";
1978 $this->
ctrl->redirectByClass(
1979 [ilRepositoryGUI::class, ilObjTestGUI::class, ilTestEvaluationGUI::class],
1980 "outUserResultsOverview"
1987 return $sequence_element == $this->test_sequence->getFirstSequence();
1992 return $sequence_element == $this->test_sequence->getLastSequence();
1997 $question_id = $this->test_sequence->getQuestionForSequence(
1998 $this->getCurrentSequenceElement()
2001 if (!$this->isParticipantsAnswerFixed($question_id)) {
2002 $this->updateWorkingTime();
2003 $this->saveQuestionSolution(
false);
2005 $this->setAnswerChangedParameter(
true);
2014 $question_id = $this->test_sequence->getQuestionForSequence(
2015 $this->getCurrentSequenceElement()
2018 if (!$this->isParticipantsAnswerFixed($question_id)) {
2019 if ($this->saveQuestionSolution(
true)) {
2020 $this->removeIntermediateSolution();
2021 $this->setAnswerChangedParameter(
false);
2025 $this->test_sequence->setQuestionChecked($question_id);
2026 $this->test_sequence->saveToDb();
2027 } elseif ($this->
object->isForceInstantFeedbackEnabled()) {
2028 $this->test_sequence->setQuestionChecked($question_id);
2029 $this->test_sequence->saveToDb();
2032 $this->
ctrl->setParameter($this,
'instresp', 1);
2035 if ($this->getNavigationUrlParameter()) {
2036 $this->saveNavigationPreventConfirmation();
2037 $this->registerForcedFeedbackNavUrl($this->getNavigationUrlParameter());
2045 $this->handleCheckTestPassValid();
2046 $last_sequence_element = $this->getCurrentSequenceElement();
2047 $next_sequence_element = $this->test_sequence->getNextSequence($last_sequence_element);
2049 $question_id = $this->test_sequence->getQuestionForSequence($last_sequence_element);
2050 $is_worked_through = $this->questionrepository->lookupResultRecordExist(
2051 $this->test_session->getActiveId(),
2053 $this->test_session->getPass()
2056 if (!$is_worked_through) {
2057 if ($this->
logger->isLoggingEnabled()
2058 && !$this->getObject()->getAnonymity()) {
2059 $this->
logger->logParticipantInteraction(
2060 $this->
logger->getInteractionFactory()->buildParticipantInteraction(
2061 $this->object->getRefId(),
2063 $this->user->getId(),
2064 $this->logger->isIPLoggingEnabled() ?
$_SERVER[
'REMOTE_ADDR'] :
'',
2065 TestParticipantInteractionTypes::QUESTION_SKIPPED,
2070 if ($this->
object->isPostponingEnabled()) {
2071 $this->handleQuestionPostponing($question_id);
2075 if (!$this->isValidSequenceElement($next_sequence_element)) {
2076 $next_sequence_element = $this->test_sequence->getFirstSequence();
2079 $this->
ctrl->setParameter($this,
'sequence', $next_sequence_element);
2080 $this->
ctrl->setParameter($this,
'pmode',
'');
2087 $this->handleCheckTestPassValid();
2089 $sequence_element = $this->test_sequence->getPreviousSequence(
2090 $this->getCurrentSequenceElement()
2093 if (!$this->isValidSequenceElement($sequence_element)) {
2094 $sequence_element = $this->test_sequence->getLastSequence();
2097 $this->
ctrl->setParameter($this,
'sequence', $sequence_element);
2098 $this->
ctrl->setParameter($this,
'pmode',
'');
2105 $this->tpl->addBlockFile(
2106 $this->getContentBlockName(),
2108 'tpl.il_as_tst_question_summary.html',
2109 'components/ILIAS/Test'
2116 let key_event = (
event) => {
2117 if(
event.key === 13 &&
event.target.tagName.toLowerCase() ===
"a" ) {
2120 if (
event.key === 13 &&
2121 event.target.tagName.toLowerCase() !==
"textarea" &&
2122 (
event.target.tagName.toLowerCase() !==
"input" ||
event.target.type.toLowerCase() !==
"submit")) {
2123 event.preventDefault();
2127 let
form = document.getElementById(
'taForm');
2128 form.onkeyup = key_event;
2129 form.onkeydown = key_event;
2130 form.onkeypress = key_event;
2132 $this->tpl->addOnLoadCode($onload_js);
2133 $this->tpl->addBlockFile(
2134 $this->getContentBlockName(),
2136 'tpl.il_as_tst_output.html',
2137 'components/ILIAS/Test'
2149 if ($this->test_session->isPasswordChecked() ===
true) {
2153 if ($this->
ctrl->getNextClass() ===
'iltestpasswordprotectiongui') {
2157 if (!$this->password_checker->isPasswordProtectionPageRedirectRequired()) {
2158 $this->test_session->setPasswordChecked(
true);
2162 $this->
ctrl->setParameterByClass(self::class,
'lock', $this->getLockParameter());
2165 $this->
ctrl->setParameterByClass(ilTestPasswordProtectionGUI::class,
'nextCommand', $next_command);
2166 $this->
ctrl->redirectByClass(ilTestPasswordProtectionGUI::class,
'showPasswordForm');
2171 if ($this->
object->isInstantFeedbackAnswerFixationEnabled()) {
2172 return $this->test_sequence->isQuestionChecked($question_id);
2175 if ($this->
object->isFollowupQuestionAnswerFixationEnabled()) {
2176 return $this->isForcedFeedbackNavUrlRegistered() || $this->test_sequence->isNextQuestionPresented($question_id);
2187 return $this->
lng->txt(
"save_introduction");
2192 $this->ass_settings =
new ilSetting(
'assessment');
2203 $this->
object->getTestId(),
2204 $this->object->getRefId(),
2205 $this->skills_service->profile(),
2206 $this->skills_service->personal()
2209 $skill_evaluation->setUserId($test_session->
getUserId());
2210 $skill_evaluation->setActiveId($test_session->
getActiveId());
2211 $skill_evaluation->setPass($test_session->
getPass());
2213 $skill_evaluation->setNumRequiredBookingsForSkillTriggering(
2214 $this->
object->getGlobalSettings()->getSkillTriggeringNumberOfAnswers()
2217 $question_list = $this->buildTestPassQuestionList();
2218 $question_list->load();
2219 $skill_evaluation->init($question_list);
2220 $skill_evaluation->evaluate(
2221 $this->
object->getTestResult(
2228 $skill_evaluation->handleSkillTriggering();
2235 $confirmation->setFormAction($this->
ctrl->getFormAction($this));
2236 $confirmation->setCancelCmd(
'cancelAnswerOptionalQuestions');
2237 $confirmation->setConfirmCmd(
'confirmAnswerOptionalQuestions');
2239 $confirmation->build($this->
object->isFixedTest());
2241 $this->populateHelperGuiContent($confirmation);
2246 $this->test_sequence->setAnsweringOptionalQuestionsConfirmed(
true);
2247 $this->test_sequence->saveToDb();
2249 $this->
ctrl->setParameter($this,
'activecommand',
'gotoquestion');
2250 $this->
ctrl->redirect($this,
'redirectQuestion');
2255 if ($this->
object->getListOfQuestions()) {
2256 $this->
ctrl->setParameter($this,
'activecommand',
'summary');
2258 $this->
ctrl->setParameter($this,
'activecommand',
'previous');
2261 $this->
ctrl->redirect($this,
'redirectQuestion');
2269 $this->tpl->setVariable($this->getContentBlockName(), $this->
ctrl->getHTML($helperGui));
2275 $navigation_toolbar->setSuspendTestButtonEnabled($this->
object->getShowCancel());
2276 $navigation_toolbar->setUserPassOverviewEnabled($this->
object->getUsrPassOverviewEnabled());
2277 $navigation_toolbar->setFinishTestCommand($this->getFinishTestCommand());
2278 return $navigation_toolbar;
2289 if (!$this->isParticipantsAnswerFixed($question_id)) {
2293 if ($this->
object->getShowMarker()) {
2297 if (count($solved_array) > 0) {
2298 $solved = array_pop($solved_array);
2299 $solved = $solved[
"solved"];
2304 $navigationGUI->setQuestionMarked(
true);
2307 $navigationGUI->setQuestionMarked(
false);
2312 return $navigationGUI;
2326 if ($this->
object->getSpecificAnswerFeedback()
2327 || $this->object->getGenericAnswerFeedback()
2328 || $this->object->getAnswerFeedbackPoints()
2329 || $this->object->getInstantFeedbackSolution()) {
2330 $navigation_gui->setAnswerFreezingEnabled($this->
object->isInstantFeedbackAnswerFixationEnabled());
2332 if ($this->
object->isForceInstantFeedbackEnabled()) {
2333 $navigation_gui->setForceInstantResponseEnabled(
true);
2340 if ($this->
object->getShowMarker()) {
2344 if (count($solved_array) > 0) {
2345 $solved = array_pop($solved_array);
2346 $solved = $solved[
'solved'];
2349 if ($solved === 1) {
2351 $navigation_gui->setQuestionMarked(
true);
2354 $navigation_gui->setQuestionMarked(
false);
2357 return $navigation_gui;
2362 if (!$this->
object->getListOfQuestionsEnd()) {
2374 $answer_feedback_enabled = $this->
object->getSpecificAnswerFeedback();
2377 $this->test_session->getActiveId(), #active_id
2378 $this->test_session->getPass(), #pass
2379 false, #graphical_output
2380 false, #result_output
2381 true, #show_question_only
2382 $answer_feedback_enabled, #show_feedback
2383 false, #show_correct_solution
2384 false, #show_manual_scoring
2385 true #show_question_text
2390 $this->isShowingPostponeStatusReguired($question_gui->
getObject()->getId()),
2391 $this->test_session->getActiveId(),
2395 $tpl =
new ilTemplate(
'tpl.tst_player_response_modal.html',
true,
true,
'components/ILIAS/Test');
2398 $saved_tpl = $this->tpl;
2400 $this->populateInstantResponseBlocks($question_gui,
true);
2401 $this->tpl = $saved_tpl;
2403 $tpl->setVariable(
'QUESTION_OUTPUT', $pageoutput);
2404 $this->tpl->setVariable(
'INSTANT_RESPONSE_MODAL', $this->getQuestionFeedbackModalHtml($tpl, $nav_url));
2409 $modal = $this->ui_factory->modal()->roundtrip(
2410 $this->
lng->txt(
'tst_instant_feedback'),
2411 $this->ui_factory->legacy()->content($tpl->
get()),
2413 )->withActionButtons([
2414 $this->ui_factory->button()->standard($this->lng->txt(
'proceed'), $nav_url)
2417 return $this->ui_renderer->render([
2418 $modal->withOnLoad($modal->getShowSignal())
2428 $response_available =
false;
2429 $jump_to_response =
false;
2433 if ($this->
object->getInstantFeedbackSolution()) {
2434 $show_question_inline_score = $this->determineInlineScoreDisplay();
2438 $this->test_session->getActiveId(), #active_id
2439 $this->test_session->getPass(), #pass
2440 false, #graphical_output
2441 $show_question_inline_score, #result_output
2442 true, #show_question_only
2443 false, #show_feedback
2444 true, #show_correct_solution
2445 false, #show_manual_scoring
2446 false #show_question_text
2448 $solutionoutput = str_replace(
'<h1 class="ilc_page_title_PageTitle"></h1>',
'', $solutionoutput);
2449 $this->populateSolutionBlock($solutionoutput);
2450 $response_available =
true;
2451 $jump_to_response =
true;
2454 $reachedPoints = $question_gui->
getObject()->getAdjustedReachedPoints(
2455 $this->test_session->getActiveId(),
2460 $maxPoints = $question_gui->
getObject()->getMaximumPoints();
2462 $solutionCorrect = ($reachedPoints == $maxPoints);
2466 if ($this->
object->getAnswerFeedbackPoints()) {
2467 $this->populateScoreBlock($reachedPoints, $maxPoints);
2468 $response_available =
true;
2469 $jump_to_response =
true;
2474 if ($this->
object->getGenericAnswerFeedback()) {
2475 if ($this->populateGenericFeedbackBlock($question_gui, $solutionCorrect)) {
2476 $response_available =
true;
2477 $jump_to_response =
true;
2483 if ($this->
object->getSpecificAnswerFeedback()) {
2486 $jump_to_response =
false;
2487 } elseif ($this->populateSpecificFeedbackBlock($question_gui)) {
2488 $response_available =
true;
2489 $jump_to_response =
true;
2493 $this->populateFeedbackBlockHeader($jump_to_response);
2494 if (!$response_available) {
2496 $this->populateFeedbackBlockMessage($this->
lng->txt(
'tst_feedback_is_given_inline'));
2498 $this->populateFeedbackBlockMessage($this->
lng->txt(
'tst_feedback_not_available_for_answer'));
2505 if ($withFocusAnchor) {
2506 $this->tpl->setCurrentBlock(
'inst_resp_id');
2507 $this->tpl->setVariable(
'INSTANT_RESPONSE_FOCUS_ID',
'focus');
2508 $this->tpl->parseCurrentBlock();
2511 $this->tpl->setCurrentBlock(
'instant_response_header');
2512 $this->tpl->setVariable(
'INSTANT_RESPONSE_HEADER', $this->
lng->txt(
'tst_feedback'));
2513 $this->tpl->parseCurrentBlock();
2518 $this->tpl->setCurrentBlock(
'instant_response_message');
2519 $this->tpl->setVariable(
'INSTANT_RESPONSE_MESSAGE', $a_message);
2520 $this->tpl->parseCurrentBlock();
2526 if ($this->getSequenceElementParameter()) {
2527 return $this->getSequenceElementParameter();
2530 return $this->test_session->getLastSequence();
2535 if ($this->testrequest->isset(
'sequence')) {
2536 return $this->testrequest->int(
'sequence');
2544 if ($this->testrequest->isset(
'pmode')) {
2545 return $this->testrequest->raw(
'pmode');
2553 return $this->testrequest->isInstanceResponseRequested();
2559 if ($this->testrequest->isset(
'nextcmd')) {
2560 $nextcmd = $this->testrequest->strVal(
'nextcmd');
2563 return $nextcmd !==
'' ? $nextcmd :
null;
2568 return $this->testrequest->int(
'nextseq');
2573 $navigation_url = $this->testrequest->strVal(
'test_player_navigation_url');
2574 if ($navigation_url !==
'') {
2575 $navigation_url_parts = parse_url($navigation_url);
2578 if (!isset($navigation_url_parts[
'host']) || ($ilias_url_parts[
'host'] === $navigation_url_parts[
'host'])) {
2579 return $navigation_url;
2587 return !empty($this->testrequest->raw(
'test_answer_changed'));
2592 $this->
ctrl->setParameter($this,
'test_answer_changed', $changed ?
'1' :
'0');
2597 if ($this->getAnswerChangedParameter()) {
2598 $this->saveQuestionSolution(
false);
2600 $this->removeIntermediateSolution();
2602 $this->setAnswerChangedParameter($this->getAnswerChangedParameter());
2607 if ($this->testrequest->retrieveBoolFromPost(
'save_on_navigation_prevent_confirmation')) {
2611 if ($this->testrequest->retrieveBoolFromPost(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM)) {
2612 ilSession::set(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM,
true);
2620 if (!$from_cache || !isset($this->cached_question_guis[$question_id])) {
2621 $question_gui = $this->
object->createQuestionGUI(
"", $question_id);
2625 $question->setShuffler($this->shuffler->getAnswerShuffleFor(
2627 $this->test_session->getActiveId(),
2628 $this->test_session->getPass()
2634 $this->initTestQuestionConfig($question_gui->
getObject());
2637 $this->cached_question_guis[$question_id] = $question_gui;
2640 return $this->cached_question_guis[$question_id];
2645 if ($from_cache && isset($this->cached_question_objects[$question_id])) {
2646 return $this->cached_question_objects[$question_id];
2649 $ass_settings =
new ilSetting(
'assessment');
2652 $process_locker_factory->setQuestionId($question->getId());
2653 $process_locker_factory->setUserId($this->
user->getId());
2654 $question->setProcessLocker($process_locker_factory->getLocker());
2656 $this->initTestQuestionConfig($question);
2658 $this->cached_question_objects[$question_id] = $question;
2665 $this->
object->isPreviousSolutionReuseEnabled()
2673 .
"active={$this->test_session->getActiveId()} "
2674 .
"qId=$question_id seq=$sequence_element "
2675 . serialize($this->test_sequence)
2678 $this->
ctrl->setParameter($this,
'sequence', $this->test_sequence->getFirstSequence());
2684 if ($this->
object->getKioskMode()) {
2685 $this->tpl->addBlockfile($this->getContentBlockName(),
'content',
"tpl.il_as_tst_kiosk_mode_content.html",
"components/ILIAS/Test");
2686 $this->tpl->setContent($content_html);
2689 $this->tpl->setVariable($this->getContentBlockName(), $content_html);
2697 $signals = [self::DISCARD_MODAL => $this->populateDiscardSolutionModal()];
2699 if ($this->
object->isFollowupQuestionAnswerFixationEnabled()) {
2700 $signals[self::LOCKS_CHANGED_MODAL] = $this->populateNextLocksChangedModal();
2701 $signals[self::LOCKS_UNCHANGED_MODAL] = $this->populateNextLocksUnchangedModal();
2709 $modal = $this->ui_factory->modal()->interruptive(
2710 $this->
lng->txt(
'discard_answer'),
2711 $this->lng->txt(
'discard_answer_confirmation'),
2713 )->withActionButtonLabel($this->
lng->txt(
'discard_answer'));
2715 $this->tpl->setCurrentBlock(
'discard_solution_modal');
2716 $this->tpl->setVariable(
'DISCARD_SOLUTION_MODAL', $this->ui_renderer->render($modal));
2717 $this->tpl->parseCurrentBlock();
2718 return $modal->getShowSignal();
2723 $modal = $this->ui_factory->modal()->interruptive(
2724 $this->
lng->txt(
'tst_nav_next_locks_empty_answer_header'),
2725 $this->lng->txt(
'tst_nav_next_locks_empty_answer_confirm'),
2726 'javascript:il.TestPlayerQuestionEditControl.confirmNextLocksUnchanged()'
2727 )->withActionButtonLabel($this->
lng->txt(
'tst_proceed'));
2729 $this->tpl->setCurrentBlock(
'next_locks_unchanged_modal');
2730 $this->tpl->setVariable(
'NEXT_LOCKS_UNCHANGED_MODAL', $this->ui_renderer->render($modal));
2731 $this->tpl->parseCurrentBlock();
2732 return $modal->getShowSignal();
2737 $empty_signal = new \ILIAS\UI\Implementation\Component\Signal(
'');
2738 if ($this->isFollowUpQuestionLocksConfirmationPrevented()) {
2739 return $empty_signal;
2742 $modal_message = $this->ui_factory->messageBox()->confirmation(
2743 $this->
lng->txt(
'tst_nav_next_locks_current_answer_confirm')
2745 $modal_checkbox = $this->ui_factory->input()->field()->checkbox(
2746 $this->
lng->txt(
'tst_dont_show_msg_again_in_current_session')
2747 )->withDedicatedName(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM);
2749 $modal = $this->ui_factory->modal()->roundtrip(
2750 $this->
lng->txt(
'tst_nav_next_locks_current_answer_header'),
2752 [ $modal_checkbox ],
2753 'javascript:il.TestPlayerQuestionEditControl.confirmNextLocksChanged()'
2754 )->withSubmitLabel($this->
lng->txt(
'tst_proceed'));
2756 $this->tpl->setCurrentBlock(
'next_locks_changed_modal');
2757 $this->tpl->setVariable(
'NEXT_LOCKS_CHANGED_MODAL', $this->ui_renderer->render($modal));
2758 $this->tpl->parseCurrentBlock();
2759 return $modal->getShowSignal();
2762 public const FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM =
'followup_qst_locks_prevent_confirmation';
2766 ilSession::set(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM,
true);
2771 if (
ilSession::get(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM) ==
null) {
2775 return ilSession::get(self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM);
2781 $state = $question_gui->
getObject()->lookupForExistingSolutions($this->test_session->getActiveId(), $this->test_session->getPass());
2782 $config[
'isAnswered'] = $state[
'authorized'];
2783 $config[
'isAnswerChanged'] = $state[
'intermediate'] || $this->getAnswerChangedParameter();
2784 $config[
'isAnswerFixed'] = $this->isParticipantsAnswerFixed($question_gui->
getObject()->getId());
2787 $config[
'autosaveUrl'] =
'';
2788 $config[
'autosaveInterval'] = 0;
2791 $config[
'autosaveInterval'] = $this->
object->getMainSettings()->getQuestionBehaviourSettings()->getAutosaveInterval();
2794 $question_config = $question_gui->
getObject()->getTestPresentationConfig();
2796 $config[
'withFormChangeDetection'] = $question_config->isFormChangeDetectionEnabled();
2799 $config[
'withBackgroundChangeDetection'] = $question_config->isBackgroundChangeDetectionEnabled();
2803 $config[
'forcedInstantFeedback'] = $this->
object->isForceInstantFeedbackEnabled();
2804 $config[
'questionLocked'] = $this->isParticipantsAnswerFixed($question_gui->
getObject()->getId());
2805 $config[
'nextQuestionLocks'] = $this->
object->isFollowupQuestionAnswerFixationEnabled();
2806 $config[
'autosaveFailureMessage'] = $this->
lng->txt(
'autosave_failed');
2809 $config[
'modalSignals'] = array_map(fn(
Signal $signal) => $signal->
getId(), $this->modal_signals);
2810 $config[
'preventConfirmationParam'] = self::FOLLOWUP_QST_LOCKS_PREVENT_CONFIRMATION_PARAM;
2812 $this->tpl->addJavascript(
'assets/js/ilTestPlayerQuestionEditControl.js');
2813 $this->tpl->addOnLoadCode(
'il.TestPlayerQuestionEditControl.init(' . json_encode($config) .
')');
2819 return self::PRESENTATION_MODE_EDIT;
2827 $forced_feeback_navigation_url =
ilSession::get(
'forced_feedback_navigation_url');
2828 $forced_feeback_navigation_url[$this->test_session->getActiveId()] = $forced_feedback_nav_url;
2829 ilSession::set(
'forced_feedback_navigation_url', $forced_feeback_navigation_url);
2837 $forced_feedback_navigation_url =
ilSession::get(
'forced_feedback_navigation_url');
2838 if (!isset($forced_feedback_navigation_url[$this->test_session->getActiveId()])) {
2842 return $forced_feedback_navigation_url[$this->test_session->getActiveId()];
2847 return $this->getRegisteredForcedFeedbackNavUrl() !==
null;
2852 $forced_feedback_navigation_url =
ilSession::get(
'forced_feedback_navigation_url');
2853 if (isset($forced_feedback_navigation_url[$this->test_session->getActiveId()])) {
2854 unset($forced_feedback_navigation_url[$this->test_session->getActiveId()]);
2855 ilSession::set(
'forced_feedback_navigation_url', $forced_feedback_navigation_url);
2861 $this->updateWorkingTime();
2862 $this->saveQuestionSolution(
false);
2873 if ($sequence_element ===
false) {
2877 if ($sequence_element < 1) {
2881 if (!$this->test_sequence->getPositionOfSequence($sequence_element)) {
2890 if ($this->
object->isForceInstantFeedbackEnabled()) {
2891 $this->submitSolutionCmd();
2895 if ($this->saveQuestionSolution(
true,
false)) {
2896 $this->test_sequence->getQuestionForSequence(
2897 $this->getCurrentSequenceElement()
2900 $this->removeIntermediateSolution();
2902 $next_sequence_element = $this->test_sequence->getNextSequence($this->getCurrentSequenceElement());
2904 if (!$this->isValidSequenceElement($next_sequence_element)) {
2905 $next_sequence_element = $this->test_sequence->getFirstSequence();
2908 $this->test_session->setLastSequence($next_sequence_element ?? 0);
2909 $this->test_session->saveToDb();
2911 $this->
ctrl->setParameter($this,
'sequence', $next_sequence_element);
2912 $this->
ctrl->setParameter($this,
'pmode',
'');
2921 $this->test_sequence->postponeQuestion($question_id);
2922 $this->test_sequence->saveToDb();
2927 $testObj =
new ilObjTest($this->ref_id,
true);
2929 $participants = $testObj->getActiveParticipantList();
2930 $participant = $participants->getParticipantByActiveId($this->testrequest->getActiveId());
2931 if ($participant && $participant->hasUnfinishedPasses()) {
2934 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
'tst_current_run_no_longer_valid'),
true);
2935 if ($with_redirect) {
2936 $this->
ctrl->redirectByClass([
2937 ilRepositoryGUI::class,
2938 ilObjTestGUI::class,
2939 TestScreenGUI::class
2946 if ($this->test_session->getActiveId() > 0) {
2947 if ($this->test_sequence->hasRandomQuestionsForPass($this->test_session->getActiveId(), $this->test_session->getPass()) > 0) {
2949 __METHOD__ .
' Random Questions allready exists for user ' .
2950 $this->
user->getId() .
' in test ' . $this->object->getTestId()
2956 $this->
logger->info(__METHOD__ .
' ' . sprintf(
2957 $this->
lng->txt(
"error_random_question_generation"),
2958 $this->user->getId(),
2959 $this->object->getTestId()
2975 $this->component_repository,
2977 $this->questionrepository
2979 $questionSetConfig->loadFromDb();
2984 $sourcePoolDefinitionList->loadDefinitions();
2986 $this->process_locker->executeRandomPassBuildOperation(
function () use ($questionSetConfig, $sourcePoolDefinitionList) {
2987 if (!$this->performTearsAndAngerBrokenConfessionChecks()) {
2996 $sourcePoolDefinitionList,
2997 $stagingPoolQuestionList
3000 $questionSetBuilder->performBuild($this->test_session);
3002 }, $sourcePoolDefinitionList->hasTaxonomyFilters());
3007 $ass_settings =
new ilSetting(
'assessment');
3010 $userSolutionAdopter->setUserId($this->
user->getId());
3011 $userSolutionAdopter->setActiveId($this->test_session->getActiveId());
3012 $userSolutionAdopter->setTargetPass($this->test_sequence->getPass());
3013 $userSolutionAdopter->setQuestionIds($this->test_sequence->getOptionalQuestions());
3015 $userSolutionAdopter->perform();
3020 $this->tpl->setOnScreenMessage(
'failure', sprintf($this->
lng->txt(
'tst_objective_oriented_test_pass_without_questions'), $this->object->getTitle()),
true);
3021 $this->
ctrl->redirectByClass(ilObjTestGUI::class);
3026 $is_next_primary =
true;
3028 if ($this->
object->isForceInstantFeedbackEnabled()) {
3029 $is_next_primary =
false;
3032 $questions_missing_result = $this->questionrepository->getQuestionsMissingResultRecord(
3033 $this->test_session->getActiveId(),
3034 $this->test_session->getPass(),
3035 $this->test_sequence->getOrderedSequenceQuestions()
3038 if ($questions_missing_result === []) {
3043 if (count($questions_missing_result) === 1
3044 && $current_question_id === current($questions_missing_result)) {
3049 return $is_next_primary;
3054 $title_content = $this->ui_factory->listing()->property();
3056 if ($this->
object->getShowKioskModeParticipant()) {
3057 $pax_name_label = $this->
lng->txt(
"conf_user_name");
3061 $pax_name_value =
"<span class='il-test-kiosk-head__participant-name'>"
3062 . $this->
user->getFullname() .
"</span>";
3063 $title_content = $title_content->withProperty($pax_name_label, $pax_name_value,
false);
3066 if ($this->
object->isShowExamIdInTestPassEnabled()) {
3067 $exam_id_label = $this->
lng->txt(
"exam_id_label");
3069 $this->test_session->getActiveId(),
3070 $this->test_session->getPass(),
3071 $this->object->getId()
3073 $title_content = $title_content->withProperty($exam_id_label, $exam_id_value);
3076 if ($this->
object->getShowKioskModeTitle()) {
3077 $test_title_label = $this->
lng->txt(
"test");
3078 $test_title_value = $this->
object->getTitle();
3079 $title_content = $title_content->withProperty($test_title_label, $test_title_value,
false);
3082 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)
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