19declare(strict_types=1);
36 private const CMD_SHOW =
'showManScoringByQuestionParticipantsTable';
37 private const CMD_SAVE =
'saveManScoringByQuestion';
48 $this->
lng->loadLanguageModule(
'form');
50 $this->
ctrl->saveParameterByClass(self::class,
'q_id');
51 $uri = ILIAS_HTTP_PATH .
'/' . $this->
ctrl->getLinkTargetByClass(
52 [\ilObjTestGUI::class, self::class],
55 $this->
ctrl->clearParameterByClass(self::class,
'q_id');
57 (
new DataFactory())->uri($uri)
62 $this->action_parameter_token,
65 [
'manual_scoring',
'by_question'],
78 return 'man_scoring_by_qst';
82 ?RoundTripModal $modal =
null
88 $globally_enabled = $this->
object->getGlobalSettings()->isManualScoringEnabled();
89 $access_granted = $this->test_access->checkScoreParticipantsAccess()
90 || $this->test_access->checkScoreParticipantsAccessAnon();
91 if (!($globally_enabled && $access_granted)) {
92 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'cannot_edit_test'),
true);
93 $this->
ctrl->redirectByClass([\ilRepositoryGUI::class, \ilObjTestGUI::class, \ilInfoScreenGUI::class]);
96 $test_question_properties = $this->testquestionsrepository
97 ->getQuestionPropertiesForTest($this->
object);
99 if ($test_question_properties === []) {
100 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'manscoring_questions_not_found'));
105 $this->ui_factory->dropdown()->standard(
106 $this->buildSelectableQuestionsArray($test_question_properties)
108 $this->lng->txt(
'select_question')
112 $question_id = $this->testrequest->getQuestionId();
113 if ($question_id === 0) {
114 $question_id = reset($test_question_properties)->getQuestionId();
117 $table =
new ScoringByQuestionTable(
120 $this->action_parameter_token,
126 $affected_rows = $this->testrequest->raw($this->row_id_token->getName());
133 $this->
user->getDateTimeFormat(),
134 $this->http->request(),
136 $this->ctrl->getLinkTargetByClass(
137 [\ilObjTestGUI::class, self::class],
138 $this->getDefaultCommand()
140 new ScoringByQuestionTableBinder(
142 new \DateTimeZone($this->
user->getTimeZone()),
143 $this->participant_access_filter,
147 $this->object->getAnonymity() || !$this->test_access->checkScoreParticipantsAccess(),
151 if ($modal !==
null) {
152 $content[] = $modal->withOnLoad($modal->getShowSignal());
155 $this->tpl->setContent($this->ui_renderer->render($content));
160 $active_id = $this->testrequest->getActiveId();
161 $question_id = $this->testrequest->getQuestionId();
162 $attempt = $this->testrequest->getPassId();
163 if ($active_id === 0 || $question_id === 0
164 || !$this->test_access->checkScoreParticipantsAccessForActiveId($active_id, $this->object->getTestId())) {
165 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'cannot_edit_test'),
true);
166 $this->
ctrl->redirectByClass(\ilObjTestGUI::class);
169 $question_gui = $this->
object->createQuestionGUI(
'', $question_id);
170 $previously_reached_points = $question_gui->getObject()->getReachedPoints($active_id, $attempt);
171 $available_points = $question_gui->getObject()->getMaximumPoints();
173 $form = $this->buildForm(
177 $previously_reached_points,
181 if (!$form->checkInput()) {
182 $form->setValuesByPost();
183 $this->showManScoringByQuestionParticipantsTable(
184 $this->buildFeedbackModal(
194 if (isset($feedback[
'finalized_evaluation'])
195 && $feedback[
'finalized_evaluation'] === 1) {
196 $new_reached_points = $previously_reached_points;
197 $feedback_text = $feedback[
'feedback'];
199 $new_reached_points = $this->
refinery->kindlyTo()->float()
200 ->transform($form->getInput(
'points'));
202 $form->getInput(
'feedback'),
207 if ($new_reached_points !== $previously_reached_points) {
208 \assQuestion::_setReachedPoints(
222 $finalized = $this->
refinery->byTrying([
223 $this->
refinery->kindlyTo()->bool(),
224 $this->refinery->always(
false)
225 ])->transform($form->getInput(
'finalized'));
226 $this->
object->saveManualFeedback(
234 if ($this->
logger->isLoggingEnabled()) {
235 $this->
logger->logScoringInteraction(
236 $this->
logger->getInteractionFactory()->buildScoringInteraction(
237 $this->getObject()->getRefId(),
239 $this->user->getId(),
241 TestScoringInteractionTypes::QUESTION_GRADED,
246 ->getAdditionalInformationGenerator()->getTrueFalseTagForBool($finalized)
252 $this->tpl->setOnScreenMessage(
255 $this->
lng->txt(
'tst_saved_manscoring_by_question_successfully'),
256 $question_gui->getObject()->getTitleForHTMLOutput(),
260 $this->showManScoringByQuestionParticipantsTable();
265 $row_info_array = explode(
'_', $row_id);
267 if (count($row_info_array) !== 2) {
268 $this->
http->close();
271 [$active_id, $attempt] = $this->
refinery->container()->mapValues(
273 )->transform($row_info_array);
275 if (!$this->getTestAccess()->checkScoreParticipantsAccessForActiveId($active_id, $this->
object->getTestId())) {
276 $this->
http->close();
279 $this->
http->saveResponse(
280 $this->
http->response()->withBody(
282 $this->ui_renderer->renderAsync(
283 $this->buildFeedbackModal($question_id, $active_id, $attempt)
288 $this->
http->sendResponse();
289 $this->
http->close();
298 $question_gui = $this->
object->createQuestionGUI(
'', $question_id);
300 $content = [$this->buildSolutionPanel($question_gui, $active_id, $attempt)];
303 $content[] = $this->buildAutosavedSolutionPanel($question_gui, $question_id, $attempt);
306 $reached_points = $question_gui->getObject()->getReachedPoints($active_id, $attempt);
307 $available_points = $question_gui->getObject()->getMaximumPoints();
308 $content[] = $this->ui_factory->panel()->standard(
309 $this->
lng->txt(
'scoring'),
310 $this->ui_factory->legacy()->content(
312 $this->
lng->txt(
'part_received_a_of_b_points'),
320 if ($this->
object->getShowSolutionSuggested() && $suggested_solution !==
'') {
321 $content[] = $this->ui_factory->legacy()->content(
322 $this->ui_factory->panel()->standard(
323 $this->lng->txt(
'solution_hint'),
329 $content[] = $this->ui_factory->legacy()->content(($form ?? $this->buildForm(
337 return $this->ui_factory->modal()->roundtrip(
338 $this->getModalTitle($active_id, $attempt),
349 $question_gui->getObject()->getTitleForHTMLOutput(),
350 $this->ui_factory->
legacy()->content(
351 $question_gui->getSolutionOutput(
357 $this->
object->getShowSolutionFeedback(),
369 $this->
lng->txt(
'autosavecontent'),
370 $this->ui_factory->
legacy()->content(
371 $question_gui->getAutoSavedSolutionOutput(
377 $this->
object->getShowSolutionFeedback(),
385 $usr_id = $this->
object->_getUserIdFromActiveId($active_id);
386 if ($this->
object->getAnonymity() ===
true
387 || in_array($usr_id, $this->
object->getAnonOnlyParticipantIds())
389 return $this->
lng->txt(
'answers_of')
393 return $this->
lng->txt(
'answers_of') .
' ' . $this->
object->getCompleteEvaluationData()
394 ->getParticipant($active_id)
402 float $reached_points,
403 float $available_points
405 $feedback = \
ilObjTest::getSingleManualFeedback($active_id, $question_id, $attempt);
406 $finalized = isset($feedback[
'finalized_evaluation'])
407 && $feedback[
'finalized_evaluation'] === 1;
409 $form = new \ilPropertyFormGUI();
410 $form->setFormAction($this->buildFormTarget($question_id, $active_id, $attempt));
411 $form->setTitle($this->
lng->txt(
'manscoring'));
412 $form->addCommandButton(self::CMD_SAVE, $this->
lng->txt(
'save'));
416 $feedback_input = new \ilNonEditableValueGUI(
417 $this->
lng->txt(
'set_manual_feedback'),
422 $feedback_input = new \ilTextAreaInputGUI(
423 $this->
lng->txt(
'set_manual_feedback'),
426 $feedback_input->setUseRte(
true);
428 $feedback_input->setValue($feedback[
'feedback'] ??
'');
429 $form->addItem($feedback_input);
431 $reached_points_input = new \ilNumberInputGUI(
432 $this->
lng->txt(
'tst_change_points_for_question'),
435 $reached_points_input->allowDecimals(
true);
436 $reached_points_input->setSize(5);
437 $reached_points_input->setMaxValue($available_points,
true);
438 $reached_points_input->setDisabled($finalized);
439 $reached_points_input->setValue((
string) $reached_points);
440 $reached_points_input->setClientSideValidation(
true);
441 $form->addItem($reached_points_input);
443 $finalized_input = new \ilCheckboxInputGUI(
444 $this->
lng->txt(
'finalized_evaluation'),
447 $finalized_input->setChecked($finalized);
448 $form->addItem($finalized_input);
458 $this->
ctrl->setParameterByClass(self::class,
'q_id', $question_id);
459 $this->
ctrl->setParameterByClass(self::class,
'active_id', $active_id);
460 $this->
ctrl->setParameterByClass(self::class,
'pass_id', $attempt);
461 $target = $this->
ctrl->getFormAction($this, self::CMD_SAVE);
462 $this->
ctrl->clearParameterByClass(self::class,
'q_id');
463 $this->
ctrl->clearParameterByClass(self::class,
'active_id');
464 $this->
ctrl->clearParameterByClass(self::class,
'pass_id');
475 $dropdown = array_map(
476 function (TestQuestionProperties $v): StandardLink {
477 $this->
ctrl->setParameterByClass(self::class,
'q_id', $v->getGeneralQuestionProperties()->getQuestionId());
478 return $this->ui_factory->link()->standard(
479 $this->buildQuestionTitleWithPoints($v),
480 $this->ctrl->getLinkTargetByClass(self::class, $this->getDefaultCommand())
485 $this->
ctrl->clearParameterByClass(self::class,
'q_id');
491 $question_properties = $test_question_properties->getGeneralQuestionProperties();
492 $lang_var = $question_properties->getAvailablePoints() === 1.0 ? $this->
lng->txt(
'point') : $this->
lng->txt(
'points');
493 return "{$this->refinery->encode()->htmlSpecialCharsAsEntities()->transform($question_properties->getTitle())} "
494 .
"({$question_properties->getAvailablePoints()} {$lang_var}) "
495 .
"[{$this->lng->txt('question_id_short')}: {$question_properties->getQuestionId()}]";
500 $math_jax_setting = new \ilSetting(
'MathJax');
501 if ($math_jax_setting->get(
'enable')) {
502 $this->tpl->addJavaScript($math_jax_setting->get(
'path_to_mathjax'));
506 $this->initTinymce();
512 $this->tpl->addJavaScript(
'node_modules/tinymce/tinymce.min.js');
513 $this->tpl->addOnLoadCode(
"
516 document.getElementById('ilContentContainer'),
517 {childList: true, subtree: true}
520 const o = new MutationObserver(
525 selector: 'textarea.RTEditor',
528 fix_list_elements: true,
532 toolbar: 'bold italic underline strikethrough | undo redo | bullist numlist',
533 toolbar_mode: 'sliding',
534 init_instance_callback: () => {aO(o);}
static ofString(string $string)
Creates a new stream with an initial value.
URLBuilderToken $row_id_token
buildQuestionTitleWithPoints(TestQuestionProperties $test_question_properties)
getAnswerDetail(int $question_id, string $row_id)
__construct(\ilObjTest $object, private readonly \ilUIService $ui_service)
saveManScoringByQuestion()
URLBuilderToken $action_parameter_token
showManScoringByQuestionParticipantsTable(?RoundTripModal $modal=null)
buildFormTarget(int $question_id, int $active_id, int $attempt)
buildAutosavedSolutionPanel(assQuestionGUI $question_gui, int $active_id, int $attempt)
buildSelectableQuestionsArray(array $question_data)
getModalTitle(int $active_id, int $attempt)
buildFeedbackModal(int $question_id, int $active_id, int $attempt, ?\ilPropertyFormGUI $form=null)
buildForm(int $attempt, int $active_id, int $question_id, float $reached_points, float $available_points)
buildSolutionPanel(\assQuestionGUI $question_gui, int $active_id, int $attempt)
acquireParameters(array $namespace, string ... $names)
static _getSuggestedSolutionOutput(int $question_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _updateStatus(int $a_obj_id, int $a_usr_id, ?object $a_obj=null, bool $a_percentage=false, bool $a_force_raise=false)
static _getParticipantId(int $active_id)
Get user id for active id.
static getSingleManualFeedback(int $active_id, int $question_id, int $pass)
static buildExamId($active_id, $pass, $test_obj_id=null)
static _getUsedHTMLTagsAsString(string $module='')
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
return['delivery_method'=> 'php',]
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This describes a Standard Dropdown.
static http()
Fetches the global http state from ILIAS.
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
TestScoringInteractionTypes
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.