43 insertGapCodeAtCaret:
function() {
44 return this.each(
function(i) {
45 var code_start =
'[gap]';
46 var code_end =
'[/gap]';
47 if (typeof tinyMCE !==
'undefined' && typeof tinyMCE.get(
'cloze_text') !==
'undefined') {
48 var ed = tinyMCE.get(
'cloze_text');
49 il.ClozeHelper.internetExplorerTinyMCECursorFix(ed);
50 ed.selection.setContent(code_start + ed.selection.getContent() + code_end);
54 if (document.selection) {
57 sel = document.selection.createRange();
58 sel.text = code_start + sel.text + code_end;
60 }
else if (this.selectionStart || this.selectionStart ==
'0') {
62 var startPos = this.selectionStart;
63 var endPos = this.selectionEnd;
64 var scrollTop = this.scrollTop;
65 this.value = this.value.substring(0, startPos)
67 + this.value.substring(startPos, endPos)
69 + this.value.substring(endPos, this.value.length);
71 this.scrollTop = scrollTop;
73 this.value += code_start + code_end;
100 $this->ui_factory = $DIC[
'ui.factory'];
101 $this->ui_renderer = $DIC[
'ui.renderer'];
102 $this->db = $DIC[
'ilDB'];
106 $this->
object->loadFromDb(
$id);
109 $this->randomGroup = $this->
refinery->random();
114 if (preg_match(
"/^(removegap|addgap)_(\d+)$/", $cmd, $matches)) {
116 $this->gapIndex = $matches[2];
126 $hasErrors = (!$always) ? $this->
editQuestion(
true) :
false;
132 $this->request_data_collector->raw(
'cloze_text')
135 $this->
object->setQuestion(
136 $this->request_data_collector->raw(
'question')
140 $this->
object->setClozeText($cloze_text);
141 $this->
object->setTextgapRating($this->request_data_collector->raw(
'textgap_rating'));
142 $this->
object->setIdenticalScoring($this->request_data_collector->bool(
'identical_scoring') ??
false);
143 $this->
object->setFixedTextLength($this->request_data_collector->int(
'fixedTextLength') ?? 0);
151 $gaps = $this->request_data_collector->strArray(
'gap');
156 if ($this->
ctrl->getCmd() !==
'createGaps') {
157 $this->
object->clearGapAnswers();
160 $answer_trafo = $this->
refinery->kindlyTo()->listOf($this->
refinery->kindlyTo()->string());
161 $points_trafo = $this->
refinery->kindlyTo()->listOf($this->
refinery->kindlyTo()->float());
163 foreach (array_keys($gaps) as $idx) {
164 $cloze_type = $this->request_data_collector->int(
'clozetype_' . $idx);
165 $this->
object->setGapType($idx, $cloze_type);
167 $gap_idx = $this->request_data_collector->raw(
'gap_' . $idx);
170 $answer = $answer_trafo->transform($gap_idx[
'answer'] ?? []);
171 if ($this->
ctrl->getCmd() !==
'createGaps') {
172 if (!empty($answer)) {
173 foreach ($answer as $order => $value) {
174 $this->
object->addGapAnswer($idx, $order, $value);
177 $this->
object->addGapAnswer($idx, 0,
'');
181 $points = $points_trafo->transform($gap_idx[
'points'] ?? []);
182 foreach ($points as $order => $value) {
183 $this->
object->setGapAnswerPoints($idx, $order, $value);
188 $this->
object->setGapShuffle(0);
190 $gap_size = $this->request_data_collector->int(
'gap_' . $idx .
'_gapsize');
191 if ($gap_size !== 0) {
192 $this->
object->setGapSize($idx, $gap_size);
195 $this->
object->setGapShuffle($idx, $this->request_data_collector->int(
'shuffle_' . $idx));
199 $this->
object->getGap($idx)->clearItems();
201 $gap_idx_numeric = $this->request_data_collector->float(
'gap_' . $idx .
'_numeric');
202 if ($gap_idx_numeric !== 0.0) {
203 $this->
object->addGapAnswer($idx, 0, (
string) $gap_idx_numeric);
204 $this->
object->setGapAnswerLowerBound(
207 (
string) $this->request_data_collector->float(
'gap_' . $idx .
'_numeric_lower')
209 $this->
object->setGapAnswerUpperBound(
212 (
string) $this->request_data_collector->float(
'gap_' . $idx .
'_numeric_upper')
214 $this->
object->setGapAnswerPoints(
217 $this->request_data_collector->float(
'gap_' . $idx .
'_numeric_points')
220 if ($this->
ctrl->getCmd() !==
'createGaps') {
221 $this->
object->addGapAnswer($idx, 0,
'');
224 $this->
object->setGapAnswerLowerBound($idx, 0,
'');
225 $this->
object->setGapAnswerUpperBound($idx, 0,
'');
230 $ass_cloze_gab_combination->clearGapCombinationsFromDb($this->
object->getId());
232 $gap_combination = $this->request_data_collector->rawArray(
'gap_combination', 4);
233 if ($gap_combination !== []) {
234 $ass_cloze_gab_combination->saveGapCombinationToDb(
237 $this->request_data_collector->rawArray(
'gap_combination_values')
239 $this->
object->setGapCombinationsExists(
true);
243 if ($this->
ctrl->getCmd() !==
'createGaps') {
244 $this->
object->updateClozeTextFromGaps();
250 $this->
object->setClozeText($this->request_data_collector->string(
'cloze_quest'));
251 $this->
object->setTextgapRating($this->request_data_collector->string(
'textgap_rating'));
252 $this->
object->setIdenticalScoring($this->request_data_collector->bool(
'textgap_rating') ??
true);
253 $this->
object->setFixedTextLength($this->request_data_collector->int(
'fixedTextLength'));
262 bool $checkonly =
false,
263 ?
bool $is_save_cmd =
null 268 $this->editForm = $form;
270 $form->setFormAction($this->
ctrl->getFormAction($this));
272 $form->setMultipart(
false);
273 $form->setTableWidth(
"100%");
274 $form->setId(
"assclozetest");
286 $form->setValuesByPost();
287 $errors = !$form->checkInput();
288 $form->setValuesByPost();
290 $gap_combinations = $this->request_data_collector->raw(
'gap_combination');
291 if (is_array($gap_combinations)
292 && $gap_combinations !== []
294 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
'points_non_numeric_or_negative_msg'));
311 foreach ($gap_combinations[
'points'] as $gaps_points) {
312 foreach ($gaps_points as $points) {
313 $points_standardized = str_replace(
',',
'.', $points);
314 if (!is_numeric($points_standardized)
315 || (
float) $points_standardized < 0) {
330 $cloze_text->setInfo($this->
lng->txt(
"close_text_hint") .
' ' 331 . $this->
lng->txt(
'latex_edit_info'));
332 $cloze_text->setRows(10);
333 $cloze_text->setCols(80);
334 if (!$this->
object->getSelfAssessmentEditingMode()) {
336 $cloze_text->setUseRte(
true);
341 $cloze_text->setUseTagsForRteOnly(
false);
343 $cloze_text->setRTESupport($this->
object->getId(),
"qpl",
"assessment");
346 $tpl =
new ilTemplate(
"tpl.il_as_qpl_cloze_gap_button_code.html",
true,
true,
"components/ILIAS/TestQuestionPool");
350 $button_text_gap = $this->ui_factory->button()->standard($this->
lng->txt(
'text_gap'),
'')
354 $button_select_gap = $this->ui_factory->button()->standard($this->
lng->txt(
'select_gap'),
'')
358 $button_numeric_gap = $this->ui_factory->button()->standard($this->
lng->txt(
'numeric_gap'),
'')
371 $this->tpl->addOnloadCode(self::JS_INSERT_GAP_CODE_AT_CARET);
375 if (!$this->
object->getSelfAssessmentEditingMode()) {
378 "ci" => $this->
lng->txt(
"cloze_textgap_case_insensitive"),
379 "cs" => $this->
lng->txt(
"cloze_textgap_case_sensitive"),
380 "l1" => sprintf($this->
lng->txt(
"cloze_textgap_levenshtein_of"),
"1"),
381 "l2" => sprintf($this->
lng->txt(
"cloze_textgap_levenshtein_of"),
"2"),
382 "l3" => sprintf($this->
lng->txt(
"cloze_textgap_levenshtein_of"),
"3"),
383 "l4" => sprintf($this->
lng->txt(
"cloze_textgap_levenshtein_of"),
"4"),
384 "l5" => sprintf($this->
lng->txt(
"cloze_textgap_levenshtein_of"),
"5")
387 $textrating->setValue($this->
object->getTextgapRating());
391 $fixedTextLength =
new ilNumberInputGUI($this->
lng->txt(
"cloze_fixed_textlength"),
"fixedTextLength");
392 $ftl = $this->
object->getFixedTextLength();
394 $fixedTextLength->
setValue($ftl > 0 ? $ftl :
'');
395 $fixedTextLength->setMinValue(0);
396 $fixedTextLength->setSize(3);
397 $fixedTextLength->setMaxLength(6);
398 $fixedTextLength->setInfo($this->
lng->txt(
'cloze_fixed_textlength_description'));
399 $fixedTextLength->setRequired(
false);
400 $form->
addItem($fixedTextLength);
403 $identical_scoring =
new ilCheckboxInputGUI($this->
lng->txt(
"identical_scoring"),
"identical_scoring");
404 $identical_scoring->setValue(1);
405 $identical_scoring->setChecked($this->
object->getIdenticalScoring());
406 $identical_scoring->setInfo($this->
lng->txt(
'identical_scoring_desc'));
407 $identical_scoring->setRequired(
false);
408 $form->
addItem($identical_scoring);
415 return fn(
$id) =>
"var el = document.getElementById('{$id}').addEventListener('click', " 417 .
' e.preventDefault();' 418 .
" ClozeQuestionGapBuilder.addGapClickFunction('{$gap_type}');" 426 $combination_exists = $assClozeGapCombinationObject->combinationExistsForQid($this->
object->getId());
428 if ($combination_exists) {
429 $combinations = $assClozeGapCombinationObject->loadFromDb($this->
object->getId());
434 $new_builder->setValueByArray($json);
435 $new_builder->setValueCombinationFromDb($combinations);
442 $gap = $this->
object->getGaps();
447 $translate_type = [
'text',
'select',
'numeric'];
449 foreach ($gap as $content) {
451 $value = $content->getItemsRaw();
453 for ($j = 0, $jMax = count($value); $j < $jMax; $j++) {
454 if ($content->isNumericGap()) {
456 'answer' => $value[$j]->getAnswerText(),
457 'lower' => $value[$j]->getLowerBound(),
458 'upper' => $value[$j]->getUpperBound(),
459 'points' => $value[$j]->getPoints(),
465 'points' => $value[$j]->getPoints(),
469 if ($content->isSelectGap()) {
470 $shuffle = $content->getShuffle();
475 'type' => $translate_type[$content->getType()] ,
477 'shuffle' => $shuffle,
478 'text_field_length' => $content->getGapSize() > 0 ? $content->getGapSize() :
'',
479 'used_in_gap_combination' =>
true];
497 $gap = $this->
object->getGap($gapCounter);
504 $header->setTitle($this->
lng->txt(
"gap") .
" " . ($gapCounter + 1));
505 $form->addItem($header);
508 $gapcounter->setValue($gapCounter);
509 $form->addItem($gapcounter);
513 0 => $this->
lng->txt(
"text_gap"),
514 1 => $this->
lng->txt(
"select_gap"),
515 2 => $this->
lng->txt(
"numeric_gap")
518 $gaptype->setValue($gap->getType());
519 $form->addItem($gaptype);
524 if (count($gap->getItemsRaw()) == 0) {
529 if (count($gap->getItemsRaw()) == 0) {
536 if (count($gap->getItemsRaw()) == 0) {
539 foreach ($gap->getItemsRaw() as $item) {
553 $gapSizeFormItem =
new ilNumberInputGUI($this->
lng->txt(
'cloze_fixed_textlength'),
"gap_" . $gapCounter .
'_gapsize');
556 $gapSizeFormItem->setMinValue(0);
557 $gapSizeFormItem->setSize(3);
558 $gapSizeFormItem->setMaxLength(6);
559 $gapSizeFormItem->setInfo($this->
lng->txt(
'cloze_gap_size_info'));
560 $gapSizeFormItem->setValue($gap->getGapSize());
561 $form->addItem($gapSizeFormItem);
582 $values->setQuestionObject($this->
object);
583 $values->setSingleline(
true);
584 $values->setAllowMove(
false);
586 $values->setValues($gap->getItemsRaw());
587 $form->addItem($values);
590 $shuffle =
new ilCheckboxInputGUI($this->
lng->txt(
"shuffle_answers"),
"shuffle_" . $gapCounter .
"");
591 $shuffle->setValue(1);
592 $shuffle->setChecked($gap->getShuffle());
593 $shuffle->setRequired(
false);
594 $form->addItem($shuffle);
613 $values->setQuestionObject($this->
object);
614 $values->setSingleline(
true);
615 $values->setAllowMove(
false);
616 $values->setValues($gap->getItemsRaw());
617 $form->addItem($values);
619 if ($this->
object->getFixedTextLength() > 0) {
620 $values->setSize($this->
object->getFixedTextLength());
621 $values->setMaxLength($this->
object->getFixedTextLength());
641 if (!$this->
object->getSelfAssessmentEditingMode()) {
645 $lowerbound =
new ilFormulaInputGUI($this->
lng->txt(
'range_lower_limit'),
"gap_" . $gapCounter .
"_numeric_lower");
648 $upperbound =
new ilFormulaInputGUI($this->
lng->txt(
'range_upper_limit'),
"gap_" . $gapCounter .
"_numeric_upper");
651 $value =
new ilNumberInputGUI($this->
lng->txt(
'value'),
"gap_" . $gapCounter .
"_numeric");
654 $lowerbound =
new ilNumberInputGUI($this->
lng->txt(
'range_lower_limit'),
"gap_" . $gapCounter .
"_numeric_lower");
657 $upperbound =
new ilNumberInputGUI($this->
lng->txt(
'range_upper_limit'),
"gap_" . $gapCounter .
"_numeric_upper");
663 $value->setRequired(
true);
664 $form->addItem($value);
666 $lowerbound->setSize(10);
667 $lowerbound->setRequired(
true);
669 $form->addItem($lowerbound);
671 $upperbound->setSize(10);
672 $upperbound->setRequired(
true);
674 $form->addItem($upperbound);
676 if ($this->
object->getFixedTextLength() > 0) {
677 $value->setSize($this->
object->getFixedTextLength());
678 $value->setMaxLength($this->
object->getFixedTextLength());
679 $lowerbound->setSize($this->
object->getFixedTextLength());
680 $lowerbound->setMaxLength($this->
object->getFixedTextLength());
681 $upperbound->setSize($this->
object->getFixedTextLength());
682 $upperbound->setMaxLength($this->
object->getFixedTextLength());
685 $points =
new ilNumberInputGUI($this->
lng->txt(
'points'),
"gap_" . $gapCounter .
"_numeric_points");
688 $points->setRequired(
true);
690 $form->addItem($points);
701 $this->
object->saveToDb();
709 $this->
object->deleteAnswerText(
711 $this->request_data_collector->getCmdIndex(
'removegap_' . $this->gapIndex)
720 $this->
object->addGapAnswer(
722 $this->request_data_collector->getCmdIndex(
'addgap_' . $this->gapIndex) + 1,
729 bool $show_question_only =
false,
730 bool $show_inline_feedback =
false 734 $template =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_output.html",
true,
true,
"components/ILIAS/TestQuestionPool");
735 $output = $this->
object->getClozeTextForHTMLOutput();
736 foreach ($this->
object->getGaps() as $gap_index => $gap) {
737 switch ($gap->getType()) {
739 $gaptemplate =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_gap_text.html",
true,
true,
"components/ILIAS/TestQuestionPool");
741 $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->
object->getFixedTextLength();
743 $gaptemplate->setCurrentBlock(
'size_and_maxlength');
744 $gaptemplate->setVariable(
"TEXT_GAP_SIZE", $gap_size);
745 $gaptemplate->parseCurrentBlock();
747 $gaptemplate->setVariable(
"GAP_COUNTER", $gap_index);
748 foreach ($user_solution as $val1 => $val2) {
749 if (strcmp($val1, $gap_index) == 0) {
756 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
760 $gaptemplate =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_gap_select.html",
true,
true,
"components/ILIAS/TestQuestionPool");
761 foreach ($gap->getItems($this->object->getShuffler(), $gap_index) as $item) {
762 $gaptemplate->setCurrentBlock(
"select_gap_option");
763 $gaptemplate->setVariable(
"SELECT_GAP_VALUE", $item->getOrder());
764 $gaptemplate->setVariable(
768 foreach ($user_solution as $val1 => $val2) {
769 if (strcmp($val1, $gap_index) == 0) {
770 if (strcmp($val2, $item->getOrder()) == 0) {
771 $gaptemplate->setVariable(
"SELECT_GAP_SELECTED",
" selected=\"selected\"");
775 $gaptemplate->parseCurrentBlock();
777 $gaptemplate->setVariable(
"PLEASE_SELECT", $this->
lng->txt(
"please_select"));
778 $gaptemplate->setVariable(
"GAP_COUNTER", $gap_index);
779 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
783 $gaptemplate =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_gap_numeric.html",
true,
true,
"components/ILIAS/TestQuestionPool");
784 $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->
object->getFixedTextLength();
786 $gaptemplate->setCurrentBlock(
'size_and_maxlength');
787 $gaptemplate->setVariable(
"TEXT_GAP_SIZE", $gap_size);
788 $gaptemplate->parseCurrentBlock();
790 $gaptemplate->setVariable(
"GAP_COUNTER", $gap_index);
791 foreach ($user_solution as $val1 => $val2) {
792 if (strcmp($val1, $gap_index) == 0) {
799 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
804 $template->setVariable(
"QUESTIONTEXT", $this->
renderLatex($this->
object->getQuestionForHTMLOutput()));
806 $questionoutput = $template->get();
807 if (!$show_question_only) {
811 return $questionoutput;
817 bool $graphical_output =
false,
818 bool $result_output =
false,
819 bool $show_question_only =
true,
820 bool $show_feedback =
false,
821 bool $show_correct_solution =
false,
822 bool $show_manual_scoring =
false,
823 bool $show_question_text =
true,
824 bool $show_inline_feedback =
true 827 if (($active_id > 0) && (!$show_correct_solution)) {
828 $user_solution = $this->
object->getSolutionValues($active_id, $pass);
829 if (!is_array($user_solution)) {
842 $show_correct_solution,
843 $show_manual_scoring,
851 mixed $user_solutions,
854 bool $graphical_output =
false,
855 bool $result_output =
false,
856 bool $show_question_only =
true,
857 bool $show_feedback =
false,
858 bool $show_correct_solution =
false,
859 bool $show_manual_scoring =
false,
860 bool $show_question_text =
true,
861 bool $show_autosave_title =
false,
862 bool $show_inline_feedback =
false,
864 $template =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_output_solution.html",
true,
true,
"components/ILIAS/TestQuestionPool");
865 $output = $this->
object->getClozeTextForHTMLOutput();
867 $check_for_gap_combinations = $assClozeGapCombinationObject->loadFromDb($this->
object->getId());
869 foreach ($this->
object->getGaps() as $gap_index => $gap) {
870 $gaptemplate =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_output_solution_gap.html",
true,
true,
"components/ILIAS/TestQuestionPool");
872 foreach ($user_solutions as $solutionarray) {
873 if ($solutionarray[
"value1"] == $gap_index) {
874 $found = $solutionarray;
879 && $graphical_output) {
881 $details = $this->
object->getUserResultDetails($active_id, $pass);
882 $check = $details[$gap_index] ?? [];
884 if (count($check_for_gap_combinations) != 0) {
885 $gaps_used_in_combination = $assClozeGapCombinationObject->getGapsWhichAreUsedInCombination($this->
object->getId());
886 $custom_user_solution = [];
887 if (array_key_exists($gap_index, $gaps_used_in_combination)) {
888 $combination_id = $gaps_used_in_combination[$gap_index];
889 foreach ($gaps_used_in_combination as $key => $value) {
891 if ($value == $combination_id) {
892 foreach ($user_solutions as $solution_key => $solution_value) {
893 if ($solution_value[
'value1'] == $key) {
895 $result_row[
'gap_id'] = $solution_value[
'value1'];
896 $result_row[
'value'] = $solution_value[
'value2'];
897 array_push($custom_user_solution, $result_row);
902 $points_array = $this->
object->calculateCombinationResult($custom_user_solution);
903 $max_combination_points = $assClozeGapCombinationObject->getMaxPointsForCombination($this->
object->getId(), $combination_id);
904 if ($points_array[0] == $max_combination_points) {
906 } elseif ($points_array[0] > 0) {
912 if (array_key_exists(
'best',
$check) &&
$check[
"best"]) {
913 $gaptemplate->setCurrentBlock(
"icon_ok");
915 $gaptemplate->parseCurrentBlock();
917 $gaptemplate->setCurrentBlock(
"icon_ok");
918 if (array_key_exists(
'positive',
$check) &&
$check[
"positive"]) {
923 $gaptemplate->parseCurrentBlock();
927 if (array_key_exists(
'best',
$check) &&
$check[
"best"]) {
928 $gaptemplate->setCurrentBlock(
"icon_ok");
930 $gaptemplate->parseCurrentBlock();
932 $gaptemplate->setCurrentBlock(
"icon_ok");
933 if (array_key_exists(
'positive',
$check) &&
$check[
"positive"]) {
938 $gaptemplate->parseCurrentBlock();
943 switch ($gap->getType()) {
947 if (($active_id > 0) && (!$show_correct_solution)) {
948 if ((count($found) == 0) || (strlen(trim($found[
"value2"])) == 0)) {
949 for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++) {
950 $solutiontext .=
" ";
956 $solutiontext = $this->
getBestSolutionText($gap, $gap_index, $check_for_gap_combinations);
960 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
965 if (($active_id > 0) && (!$show_correct_solution)) {
966 if ((count($found) == 0) || (strlen(trim($found[
"value2"])) == 0)) {
967 for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++) {
968 $solutiontext .=
" ";
971 $item = $gap->getItem($found[
"value2"]);
972 if (is_object($item)) {
975 for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++) {
976 $solutiontext .=
" ";
981 $solutiontext = $this->
getBestSolutionText($gap, $gap_index, $check_for_gap_combinations);
985 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
991 if ($show_question_text) {
992 $template->setVariable(
"QUESTIONTEXT", $this->
renderLatex($this->
object->getQuestionForHTMLOutput()));
998 $solutiontemplate =
new ilTemplate(
"tpl.il_as_tst_solution_output.html",
true,
true,
"components/ILIAS/TestQuestionPool");
999 $questionoutput = $template->get();
1002 if ($show_feedback) {
1008 $this->
object->fetchIndexedValuesFromValuePairs($user_solutions)
1011 if ($feedback !==
'') {
1017 $solutiontemplate->setVariable(
"ILC_FB_CSS_CLASS", $cssClass);
1018 $solutiontemplate->setVariable(
"FEEDBACK", $this->
renderLatex(
1023 $solutiontemplate->setVariable(
"SOLUTION_OUTPUT", $questionoutput);
1025 $solutionoutput = $solutiontemplate->get();
1027 if (!$show_question_only) {
1029 $solutionoutput = $this->
getILIASPage($solutionoutput);
1032 return $solutionoutput;
1043 $combination =
null;
1044 foreach ((array) $gap_combinations as $combiGapSolRow) {
1045 if ($combiGapSolRow[
'gap_fi'] == $gap_index && $combiGapSolRow[
'best_solution']) {
1046 $combination = $combiGapSolRow;
1051 $gap->getBestSolutionOutput(
1052 $this->object->getShuffler(),
1056 return $best_solution_text;
1062 if (strlen($manual_feedback)) {
1063 return $manual_feedback;
1065 $correct_feedback = $this->
object->feedbackOBJ->getGenericFeedbackTestPresentation($this->
object->getId(),
true);
1066 $incorrect_feedback = $this->
object->feedbackOBJ->getGenericFeedbackTestPresentation($this->
object->getId(),
false);
1069 if ($correct_feedback . $incorrect_feedback !==
'') {
1079 bool $is_question_postponed =
false,
1080 array|
bool $user_post_solutions =
false,
1081 bool $show_specific_inline_feedback =
false 1084 $user_solution = [];
1085 if ($user_post_solutions !==
false) {
1086 $indexedSolution = $this->
object->fetchSolutionSubmit();
1087 $user_solution = $this->
object->fetchValuePairsFromIndexedValues($indexedSolution);
1088 } elseif ($active_id) {
1089 $user_solution = $this->
object->getTestOutputSolutions($active_id, $pass);
1091 if (!is_array($user_solution)) {
1092 $user_solution = [];
1096 $template =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_output.html",
true,
true,
"components/ILIAS/TestQuestionPool");
1097 $output = $this->
object->getClozeTextForHTMLOutput();
1098 foreach ($this->
object->getGaps() as $gap_index => $gap) {
1099 switch ($gap->getType()) {
1101 $gaptemplate =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_gap_text.html",
true,
true,
"components/ILIAS/TestQuestionPool");
1102 $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->
object->getFixedTextLength();
1104 if ($gap_size > 0) {
1105 $gaptemplate->setCurrentBlock(
'size_and_maxlength');
1106 $gaptemplate->setVariable(
"TEXT_GAP_SIZE", $gap_size);
1107 $gaptemplate->parseCurrentBlock();
1110 $gaptemplate->setVariable(
"GAP_COUNTER", $gap_index);
1111 foreach ($user_solution as $solution) {
1112 if (strcmp($solution[
"value1"], $gap_index) == 0) {
1119 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
1123 $gaptemplate =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_gap_select.html",
true,
true,
"components/ILIAS/TestQuestionPool");
1124 foreach ($gap->getItems($this->object->getShuffler(), $gap_index) as $item) {
1125 $gaptemplate->setCurrentBlock(
"select_gap_option");
1126 $gaptemplate->setVariable(
"SELECT_GAP_VALUE", $item->getOrder());
1127 $gaptemplate->setVariable(
1131 foreach ($user_solution as $solution) {
1132 if (strcmp($solution[
"value1"], $gap_index) == 0) {
1133 if (strcmp($solution[
"value2"], $item->getOrder()) == 0) {
1134 $gaptemplate->setVariable(
"SELECT_GAP_SELECTED",
" selected=\"selected\"");
1138 $gaptemplate->parseCurrentBlock();
1140 $gaptemplate->setVariable(
"PLEASE_SELECT", $this->
lng->txt(
"please_select"));
1141 $gaptemplate->setVariable(
"GAP_COUNTER", $gap_index);
1142 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
1146 $gaptemplate =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_gap_numeric.html",
true,
true,
"components/ILIAS/TestQuestionPool");
1147 $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->
object->getFixedTextLength();
1148 if ($gap_size > 0) {
1149 $gaptemplate->setCurrentBlock(
'size_and_maxlength');
1150 $gaptemplate->setVariable(
"TEXT_GAP_SIZE", $gap_size);
1151 $gaptemplate->parseCurrentBlock();
1154 $gaptemplate->setVariable(
"GAP_COUNTER", $gap_index);
1155 foreach ($user_solution as $solution) {
1156 if (strcmp($solution[
"value1"], $gap_index) == 0) {
1163 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
1169 $template->setVariable(
"QUESTIONTEXT", $this->
renderLatex($this->
object->getQuestionForHTMLOutput()));
1171 $questionoutput = $template->get();
1172 $pageoutput = $this->
outQuestionPage(
"", $is_question_postponed, $active_id, $questionoutput);
1178 if (!$this->
object->feedbackOBJ->isSpecificAnswerFeedbackAvailable($this->object->getId())) {
1182 $feedback =
'<table class="test_specific_feedback"><tbody>';
1184 foreach ($this->
object->gaps as $gap_index => $gap) {
1185 $answer_value = $this->
object->fetchAnswerValueForGap($user_solution, $gap_index);
1187 && $answer_value ===
'') {
1190 $answer_index = $this->
object->feedbackOBJ->determineAnswerIndexForAnswerValue($gap, $answer_value);
1191 $fb = $this->
object->feedbackOBJ->determineTestOutputGapFeedback($gap_index, $answer_index);
1193 $caption = $this->
lng->txt(
'gap') .
' ' . ($gap_index + 1) .
': ';
1194 $feedback .=
'<tr><td>';
1195 $feedback .= $caption .
'</td><td>';
1196 $feedback .= $fb .
'</td> </tr>';
1198 $feedback .=
'</tbody></table>';
1237 public function getAggregatedAnswersView(array $relevant_answers):
string 1241 foreach ($relevant_answers as $answer) {
1242 $overview[$answer[
'active_fi']][$answer[
'pass']][$answer[
'value1']] = $answer[
'value2'];
1245 foreach ($overview as $active) {
1246 foreach ($active as $answer) {
1247 foreach ($answer as $option => $value) {
1248 $aggregation[$option][$value] = $aggregation[$option][$value] + 1;
1255 foreach ($this->
object->getGaps() as $gap_index => $gap) {
1257 $html .=
'<p>Gap ' . ($i + 1) .
' - SELECT</p>';
1260 foreach ($gap->getItems($this->object->getShuffler(), $gap_index) as $gap_item) {
1261 $aggregate = $aggregation[$i];
1262 $html .=
'<li>' . $gap_item->getAnswerText() .
' - ' . ($aggregate[$j] ? $aggregate[$j] : 0) .
'</li>';
1269 $present_elements = [];
1270 foreach ($gap->getItems($this->randomGroup->shuffleArray(
new Seed\
RandomSeed())) as $item) {
1272 $present_elements[] = $item->getAnswertext();
1275 $html .=
'<p>Gap ' . ($i + 1) .
' - TEXT</p>';
1277 $aggregate = (array) $aggregation[$i];
1278 foreach ($aggregate as $answer => $count) {
1280 if (in_array($answer, $present_elements)) {
1281 $show_mover =
' style="display: none;" ';
1284 $html .=
'<li>' . $answer .
' - ' . $count
1285 .
' <button class="clone_fields_add btn btn-link" ' . $show_mover .
' data-answer="' . $answer .
'" name="add_gap_' . $i .
'_0"> 1286 <span class="sr-only"></span><span class="glyphicon glyphicon-plus"></span></button> 1293 $html .=
'<p>Gap ' . ($i + 1) .
' - NUMERIC</p>';
1296 foreach ($gap->getItems($this->object->getShuffler(), $gap_index) as $gap_item) {
1297 $aggregate = (array) $aggregation[$i];
1298 foreach ($aggregate as $answer => $count) {
1299 $html .=
'<li>' . $answer .
' - ' . $count .
'</li>';
1315 $parts = explode(
'[gap', $question_text);
1317 $question_text =
'';
1318 foreach (
$parts as $part) {
1320 $question_text .= $part;
1322 $question_text .=
'[gap ' . $i . $part;
1326 return $question_text;
1331 $parts = preg_split(
'/\[gap \d*\]/', $question_text);
1332 $question_text = implode(
'[gap]',
$parts);
1333 return $question_text;
1343 $gaptemplate->setCurrentBlock(
'gap_span');
1344 $gaptemplate->setVariable(
'SPAN_SOLUTION', $solutiontext);
1346 $gaptemplate->setCurrentBlock(
'gap_select');
1347 $gaptemplate->setVariable(
'SELECT_SOLUTION', $solutiontext);
1349 $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->
object->getFixedTextLength();
1351 if ($gap_size > 0) {
1352 $gaptemplate->setCurrentBlock(
'gap_size');
1353 $gaptemplate->setVariable(
"GAP_SIZE", $gap_size);
1354 $gaptemplate->parseCurrentBlock();
1357 $gaptemplate->setCurrentBlock(
'gap_input');
1358 $gaptemplate->setVariable(
'INPUT_SOLUTION', $solutiontext);
1362 $gaptemplate->parseCurrentBlock();
1368 if (isset($answer[
'actions'])) {
1378 $table = parent::getAnswerFrequencyTableGUI(
1387 $this->
lng->txt(
'tst_corrections_answers_tbl_subindex'),
1388 $this->
lng->txt(
'gap') .
' ' . ($questionIndex + 1)
1393 $table->addColumn(
'',
'',
'200');
1401 return array_keys($this->
object->getGaps());
1406 $gap = $this->
object->getGap(
$gapIndex);
1408 switch ($gap->type) {
1415 $items = $gap->getItems($this->randomGroup->dontShuffle());
1416 return $items[$answer]->getAnswertext();
1422 $gap = $this->
object->getGap($gap_index);
1425 $this->isUsedInCombinations($gap_index)) {
1429 foreach ($answers as $key => $ans) {
1432 foreach ($gap->getItems($this->randomGroup->dontShuffle()) as $item) {
1433 if ($ans[
'answer'] !== $item->getAnswerText()) {
1442 $answers[$key][
'addable'] =
true;
1453 foreach ($relevantAnswers as $row) {
1454 if ($row[
'value1'] != $questionIndex) {
1458 if (!isset($answers[$row[
'value2']])) {
1461 $answers[$row[
'value2']] = [
1462 'answer' => $label,
'frequency' => 0
1466 $answers[$row[
'value2']][
'frequency']++;
1476 foreach ($this->
object->getGapCombinations() as $combination) {
1477 if ($combination[
'gap_fi'] !=
$gapIndex) {
1491 foreach ($this->
object->getGapCombinations() as
$c) {
1492 if (!isset($combinations[
$c[
'cid']])) {
1493 $combinations[$c[
'cid']] = [];
1496 if (!isset($combinations[$c[
'cid']][$c[
'row_id']])) {
1497 $combinations[$c[
'cid']][$c[
'row_id']] = [
1498 'gaps' => [],
'points' => $c[
'points'],
1502 if (!isset($combinations[$c[
'cid']][$c[
'row_id']][
'gaps'][$c[
'gap_fi']])) {
1503 $combinations[$c[
'cid']][$c[
'row_id']][
'gaps'][$c[
'gap_fi']] = [];
1506 $combinations[$c[
'cid']][$c[
'row_id']][
'gaps'][$c[
'gap_fi']] = $c[
'answer'];
1509 return $combinations;
1523 if ($this->
object->getGapCombinationsExists()) {
1533 $header->setTitle(
"Gap Combination " . ($combiIndex + 1));
1537 $inp->setValues($gapCombi);
1549 $header->setTitle($this->
lng->txt(
"gap") .
" " . (
$gapIndex + 1));
1550 $form->addItem($header);
1555 foreach ($gap->getItemsRaw() as $item) {
1565 $values->setRequired(
true);
1566 $values->setQuestionObject($this->
object);
1567 $values->setValues($gap->getItemsRaw());
1568 $form->addItem($values);
1575 $value->setSize(10);
1577 $value->setRequired(
true);
1578 $form->addItem($value);
1582 $lowerbound->setSize(10);
1583 $lowerbound->setRequired(
true);
1585 $form->addItem($lowerbound);
1589 $upperbound->setSize(10);
1590 $upperbound->setRequired(
true);
1592 $form->addItem($upperbound);
1597 $points->setSize(3);
1598 $points->setRequired(
true);
1600 $form->addItem($points);
1617 if ($this->
object->getGapCombinationsExists()) {
1637 foreach ($gap->
getItemsRaw() as $index => $item) {
1638 $item->setPoints((
float) str_replace(
',',
'.', $answers[$index]->getPoints()));
1654 $combinationPoints = [
'points' => [],
'select' => []];
1655 $combinationValues = [];
1660 if (!isset($combinationPoints[
'points'][$combiId])) {
1661 $combinationPoints[
'points'][$combiId] = [];
1662 $combinationPoints[
'select'][$combiId] = [];
1663 $combinationValues[$combiId] = [];
1666 foreach ($combi as $varId => $variant) {
1667 $combinationPoints[
'points'][$combiId][$varId] = (float) str_replace(
',',
'.', $values[$varId][
'points']);
1668 $combinationPoints[
'select'][$combiId] = array_keys($values[$varId][
'gaps']);
1669 $combinationValues[$combiId][$varId] = array_values($values[$varId][
'gaps']);
1674 $assClozeGapCombinationObject->clearGapCombinationsFromDb($this->
object->getId());
1676 $assClozeGapCombinationObject->saveGapCombinationToDb(
1681 $this->
object->setGapCombinationsExists(
true);
isTestPresentationContext()
const ADDITIONAL_CONTENT_EDITING_MODE_IPE
setAdditionalContentEditingModeFromPost()
hasCorrectSolution($activeId, $passIndex)
genericFeedbackOutputBuilder(int $active_id, ?int $pass)
populateNumericGapCorrectionFormProperty($form, $item, $gapIndex, $hidePoints)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
generateCorrectnessIconsForCorrectness(int $correctness)
getAnswersFrequency($relevantAnswers, $questionIndex)
getTestOutput(int $active_id, int $pass, bool $is_question_postponed=false, array|bool $user_post_solutions=false, bool $show_specific_inline_feedback=false)
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
if($clientAssertionType !='urn:ietf:params:oauth:client-assertion-type:jwt-bearer'|| $grantType !='client_credentials') $parts
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
renderLatex($content)
Wrap content with latex in a LatexContent UI component and render it to be processed by MathJax in th...
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)
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
saveGapCorrectionFormProperty(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
setPoints($points=0.0)
Sets the points.
addBasicQuestionFormProperties(ilPropertyFormGUI $form)
withAdditionalOnLoadCode(Closure $binder)
parseCurrentBlock(string $blockname=self::DEFAULT_BLOCK)
Parses the given block.
escapeTemplatePlaceholders(string $text)
getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex)
saveGapCombinationCorrectionFormProperties(ilPropertyFormGUI $form)
Class for cloze question gaps.
populateTextGapFormPart($form, $gap, $gapCounter)
Populates the form-part for a text gap.
populateSolutiontextToGapTpl($gaptemplate, $gap, $solutiontext)
const CSS_CLASS_FEEDBACK_CORRECT
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
Extracts the question specific values from the request and applies them to the data object...
ilGlobalPageTemplate $tpl
getPreview(bool $show_question_only=false, bool $show_inline_feedback=false)
populateTaxonomyFormSection(ilPropertyFormGUI $form)
editQuestion(bool $checkonly=false, ?bool $is_save_cmd=null)
Creates an output of the edit form for the question.
getBestSolutionText($gap, $gap_index, $gap_combinations)
addQuestionFormCommandButtons(ilPropertyFormGUI $form)
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
static _getUsedHTMLTags(string $module='')
populateGapCombinationCorrectionFormProperty(ilPropertyFormGUI $form, $gapCombi, $combiIndex)
getItemsRaw()
Gets the items of a cloze gap.
Cloze test question GUI representation.
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from the request and applies them to the data object...
populateQuestionSpecificFormPart(ilPropertyFormGUI $form)
Adds the question specific forms parts to a question property form gui.
createGaps()
Create gaps from cloze text.
writeQuestionGenericPostData()
get(string $part=self::DEFAULT_BLOCK)
Renders the given block and returns the html string.
hasAddAnswerAction($relevantAnswers, $questionIndex)
populateGapFormPart($form, $gapCounter)
Populates a gap form-part.
populateAnswerSpecificFormPart(ilPropertyFormGUI $form)
Adds the answer specific form parts to a question property form gui.
populateTextOrSelectGapCorrectionFormProperty($form, $gap, $gapIndex, $hidePoints)
saveTextOrSelectGapCorrectionFormProperty(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
hasErrorInGapCombinationPoints(array $gap_combinations)
populateGapSizeFormPart($form, $gap, $gapCounter)
const CSS_CLASS_FEEDBACK_WRONG
writePostData(bool $always=false)
{}
const JS_INSERT_GAP_CODE_AT_CARET
saveNumericGapCorrectionFormProperty(ilPropertyFormGUI $form, assAnswerCloze $item, $gapIndex)
setUpperBound(string $bound)
Sets the upper bound.
populateGapCorrectionFormProperties($form, $gap, $gapIndex, $hidePoints)
isUsedInCombinations($gapIndex)
populateNumericGapFormPart($form, $gap, $gapCounter)
Populates the form-part for a numeric gap.
populateSelectGapFormPart($form, $gap, $gapCounter)
Populates the form-part for a select gap.
saveTaxonomyAssignments()
getILIASPage(string $html="")
Returns the ILIAS Page around a question.
renderSolutionOutput(mixed $user_solutions, int $active_id, ?int $pass, 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_autosave_title=false, bool $show_inline_feedback=false,)
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
completeAddAnswerAction($answers, $gap_index)
applyIndizesToGapText($question_text)
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
__construct(Container $dic, ilPlugin $plugin)
This class represents a text area property in a property form.
getGenericFeedbackOutput(int $active_id, $pass)
setAnswertext($answertext="")
Sets the answer text.
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
setLowerBound(string $bound)
Sets the lower boind.
isRenderPurposePrintPdf()
getAddGapButtonClickClosure(string $gap_type)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$gapIndex
A temporary variable to store gap indexes of ilCtrl commands in the getCommand method.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setInlineStyle(string $a_style)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getManualFeedback(int $active_id, int $question_id, ?int $pass)
Retrieves the feedback comment for a question in a test if it is finalized.
setVariable(string $variable, $value='')
Sets the given variable to the given value.
getSpecificFeedbackOutput(array $user_solution)
removeIndizesFromGapText($question_text)
__construct(int $id=-1)
assClozeTestGUI constructor
getAnswerTextLabel($gapIndex, $answer)
renderEditForm(ilPropertyFormGUI $form)