47 insertGapCodeAtCaret:
function() {
48 return this.each(
function(i) {
49 var code_start =
"[gap]" 50 var code_end =
"[/gap]" 51 if (typeof tinyMCE !=
"undefined" && typeof tinyMCE.get(
'cloze_text') !=
"undefined") {
52 var ed = tinyMCE.get(
'cloze_text');
53 il.ClozeHelper.internetExplorerTinyMCECursorFix(ed);
54 ed.selection.setContent(code_start + ed.selection.getContent() + code_end);
58 if (document.selection) {
61 sel = document.selection.createRange();
62 sel.text = code_start + sel.text + code_end;
64 }
else if (this.selectionStart || this.selectionStart ==
'0') {
66 var startPos = this.selectionStart;
67 var endPos = this.selectionEnd;
68 var scrollTop = this.scrollTop;
69 this.value = this.value.substring(0, startPos)
71 + this.value.substring(startPos, endPos)
73 + this.value.substring(endPos, this.value.length);
75 this.scrollTop = scrollTop;
77 this.value += code_start + code_end;
106 $this->ui_factory = $DIC->ui()->factory();
107 $this->ui_renderer = $DIC->ui()->renderer();
108 $this->post = $this->dic->http()->wrapper()->post();
112 $this->
object->loadFromDb(
$id);
115 $this->randomGroup = $this->
refinery->random();
120 if (preg_match(
"/^(removegap|addgap)_(\d+)$/", $cmd, $matches)) {
122 $this->gapIndex = $matches[2];
132 $hasErrors = (!$always) ? $this->
editQuestion(
true) :
false;
138 $this->request->raw(
'cloze_text')
141 $this->
object->setQuestion(
142 $this->request->raw(
'question')
146 $this->
object->setClozeText($cloze_text);
147 $this->
object->setTextgapRating($this->request->raw(
'textgap_rating'));
148 $this->
object->setIdenticalScoring((
bool) ($this->request->raw(
'identical_scoring') ??
false));
149 $this->
object->setFixedTextLength(($this->request->int(
'fixedTextLength') ?? 0));
157 if (!$this->post->has(
'gap')) {
161 $gaps = $this->post->retrieve(
166 if ($this->
ctrl->getCmd() !==
'createGaps') {
167 $this->
object->clearGapAnswers();
170 foreach ($gaps as $idx => $hidden) {
171 $clozetype = $this->post->retrieve(
173 $this->
refinery->kindlyTo()->string()
176 $this->
object->setGapType($idx, $clozetype);
178 switch ($clozetype) {
181 $this->
object->setGapShuffle($idx, 0);
183 if ($this->
ctrl->getCmd() !=
'createGaps') {
184 if (is_array($_POST[
'gap_' . $idx][
'answer'])) {
185 foreach ($_POST[
'gap_' . $idx][
'answer'] as $order => $value) {
186 $this->
object->addGapAnswer($idx, $order, $value);
189 $this->
object->addGapAnswer($idx, 0,
'');
193 if (is_array($_POST[
'gap_' . $idx][
'points'])) {
194 foreach ($_POST[
'gap_' . $idx][
'points'] as $order => $value) {
195 $this->
object->setGapAnswerPoints($idx, $order, $value);
199 $k_gapsize =
'gap_' . $idx .
'_gapsize';
200 if ($this->request->isset($k_gapsize)) {
201 $this->
object->setGapSize($idx, $_POST[$k_gapsize]);
207 $this->
object->setGapShuffle($idx, (
int) (isset($_POST[
"shuffle_$idx"]) && $_POST[
"shuffle_$idx"]));
209 if ($this->
ctrl->getCmd() !=
'createGaps') {
210 if (is_array($_POST[
'gap_' . $idx][
'answer'])) {
211 foreach ($_POST[
'gap_' . $idx][
'answer'] as $order => $value) {
212 $this->
object->addGapAnswer($idx, $order, $value);
215 $this->
object->addGapAnswer($idx, 0,
'');
219 if (is_array($_POST[
'gap_' . $idx][
'points'])) {
220 foreach ($_POST[
'gap_' . $idx][
'points'] as $order => $value) {
221 $this->
object->setGapAnswerPoints($idx, $order, $value);
228 $this->
object->setGapShuffle($idx, 0);
230 $gap = $this->
object->getGap($idx);
235 $this->
object->getGap($idx)->clearItems();
237 if ($this->post->has(
'gap_' . $idx .
'_numeric')) {
238 if ($this->
ctrl->getCmd() !==
'createGaps') {
239 $this->
object->addGapAnswer(
242 str_replace(
",",
".", $_POST[
'gap_' . $idx .
'_numeric'])
246 $this->
object->setGapAnswerLowerBound(
249 str_replace(
",",
".", $_POST[
'gap_' . $idx .
'_numeric_lower'])
252 $this->
object->setGapAnswerUpperBound(
255 str_replace(
",",
".", $_POST[
'gap_' . $idx .
'_numeric_upper'])
258 $this->
object->setGapAnswerPoints($idx, 0, $_POST[
'gap_' . $idx .
'_numeric_points']);
260 if ($this->
ctrl->getCmd() !=
'createGaps') {
261 $this->
object->addGapAnswer($idx, 0,
'');
264 $this->
object->setGapAnswerLowerBound($idx, 0,
'');
266 $this->
object->setGapAnswerUpperBound($idx, 0,
'');
269 if ($this->post->has(
'gap_' . $idx .
'_gapsize')) {
270 $this->
object->setGapSize($idx, $_POST[
'gap_' . $idx .
'_gapsize']);
275 $assClozeGapCombinationObject->clearGapCombinationsFromDb($this->
object->getId());
277 isset($_POST[
'gap_combination']) &&
278 is_array($_POST[
'gap_combination']) &&
279 count($_POST[
'gap_combination']) > 0
281 $assClozeGapCombinationObject->saveGapCombinationToDb(
283 $_POST[
'gap_combination'],
284 $_POST[
'gap_combination_values']
286 $this->
object->setGapCombinationsExists(
true);
289 if ($this->
ctrl->getCmd() !=
'createGaps') {
290 $this->
object->updateClozeTextFromGaps();
296 $this->
object->setClozeText($_POST[
'cloze_text']);
297 $this->
object->setTextgapRating($_POST[
"textgap_rating"]);
298 $this->
object->setIdenticalScoring($_POST[
"identical_scoring"]);
299 $this->
object->setFixedTextLength($_POST[
"fixedTextLength"]);
313 $this->editForm = $form;
315 $form->setFormAction($this->
ctrl->getFormAction($this));
317 $form->setMultipart(
false);
318 $form->setTableWidth(
"100%");
319 $form->setId(
"assclozetest");
331 $form->setValuesByPost();
332 $errors = !$form->checkInput();
333 $form->setValuesByPost();
335 $gap_combinations = $this->request->raw(
'gap_combination');
336 if (is_array($gap_combinations)
337 && $gap_combinations !== []
339 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
'points_non_numeric_or_negative_msg'));
350 $modal->setHeading($this->
lng->txt(
''));
351 $modal->setId(
'ilGapModal');
353 $this->tpl->setVariable(
"QUESTION_DATA", $form->getHTML() . $modal->getHTML());
360 foreach ($gap_combinations[
'points'] as $gaps_points) {
361 foreach ($gaps_points as $points) {
362 $points_standardized = str_replace(
',',
'.', $points);
363 if (!is_numeric($points_standardized)
364 || (
float) $points_standardized < 0) {
377 $title->setMaxLength(100);
378 $title->setValue($this->
object->getTitle());
379 $title->setRequired(
true);
382 if (!$this->
object->getSelfAssessmentEditingMode()) {
385 $author->setValue($this->
object->getAuthor());
386 $author->setMaxLength(512);
387 $author->setRequired(
true);
392 $description->setValue($this->
object->getComment());
393 $description->setRequired(
false);
399 if (trim($author) ==
"") {
402 $hi->setValue($author);
415 $question->setRequired(
true);
416 $question->setRows(10);
417 $question->setCols(80);
418 if (!$this->
object->getSelfAssessmentEditingMode()) {
420 $question->setUseRte(
true);
422 $question->addPlugin(
"latex");
423 $question->addButton(
"latex");
424 $question->addButton(
"pastelatex");
425 $question->setRTESupport($this->
object->getId(),
"qpl",
"assessment");
429 $question->setUseTagsForRteOnly(
false);
441 $cloze_text->setInfo($this->
lng->txt(
"close_text_hint"));
442 $cloze_text->setRows(10);
443 $cloze_text->setCols(80);
444 if (!$this->
object->getSelfAssessmentEditingMode()) {
446 $cloze_text->setUseRte(
true);
448 $cloze_text->addPlugin(
"latex");
449 $cloze_text->addButton(
"latex");
450 $cloze_text->addButton(
"pastelatex");
454 $cloze_text->setUseTagsForRteOnly(
false);
456 $cloze_text->setRTESupport($this->
object->getId(),
"qpl",
"assessment");
459 $tpl =
new ilTemplate(
"tpl.il_as_qpl_cloze_gap_button_code.html",
true,
true,
"Modules/TestQuestionPool");
463 $button_text_gap = $this->ui_factory->button()->standard($this->
lng->txt(
'text_gap'),
'')
467 $button_select_gap = $this->ui_factory->button()->standard($this->
lng->txt(
'select_gap'),
'')
471 $button_numeric_gap = $this->ui_factory->button()->standard($this->
lng->txt(
'numeric_gap'),
'')
484 $this->tpl->addOnloadCode(self::JS_INSERT_GAP_CODE_AT_CARET);
488 if (!$this->
object->getSelfAssessmentEditingMode()) {
491 "ci" => $this->
lng->txt(
"cloze_textgap_case_insensitive"),
492 "cs" => $this->
lng->txt(
"cloze_textgap_case_sensitive"),
493 "l1" => sprintf($this->
lng->txt(
"cloze_textgap_levenshtein_of"),
"1"),
494 "l2" => sprintf($this->
lng->txt(
"cloze_textgap_levenshtein_of"),
"2"),
495 "l3" => sprintf($this->
lng->txt(
"cloze_textgap_levenshtein_of"),
"3"),
496 "l4" => sprintf($this->
lng->txt(
"cloze_textgap_levenshtein_of"),
"4"),
497 "l5" => sprintf($this->
lng->txt(
"cloze_textgap_levenshtein_of"),
"5")
500 $textrating->setValue($this->
object->getTextgapRating());
504 $fixedTextLength =
new ilNumberInputGUI($this->
lng->txt(
"cloze_fixed_textlength"),
"fixedTextLength");
505 $ftl = $this->
object->getFixedTextLength();
507 $fixedTextLength->setValue($ftl > 0 ? $ftl :
'');
508 $fixedTextLength->setMinValue(0);
509 $fixedTextLength->setSize(3);
510 $fixedTextLength->setMaxLength(6);
511 $fixedTextLength->setInfo($this->
lng->txt(
'cloze_fixed_textlength_description'));
512 $fixedTextLength->setRequired(
false);
513 $form->
addItem($fixedTextLength);
516 $identical_scoring =
new ilCheckboxInputGUI($this->
lng->txt(
"identical_scoring"),
"identical_scoring");
517 $identical_scoring->setValue(1);
518 $identical_scoring->setChecked($this->
object->getIdenticalScoring());
519 $identical_scoring->setInfo($this->
lng->txt(
'identical_scoring_desc'));
520 $identical_scoring->setRequired(
false);
521 $form->
addItem($identical_scoring);
528 return fn(
$id) =>
"var el = document.getElementById('{$id}').addEventListener('click', " 530 .
' e.preventDefault();' 531 .
" ClozeQuestionGapBuilder.addGapClickFunction('{$gap_type}');" 537 if (self::OLD_CLOZE_TEST_UI) {
538 for ($gapCounter = 0; $gapCounter < $this->
object->getGapCount(); $gapCounter++) {
545 $combination_exists = $assClozeGapCombinationObject->combinationExistsForQid($this->
object->getId());
547 if ($combination_exists) {
548 $combinations = $assClozeGapCombinationObject->loadFromDb($this->
object->getId());
553 $new_builder->setValueByArray($json);
554 $new_builder->setValueCombinationFromDb($combinations);
562 $gap = $this->
object->getGaps();
567 $translate_type = [
'text',
'select',
'numeric'];
569 foreach ($gap as $content) {
571 $value = $content->getItemsRaw();
573 for ($j = 0, $jMax = count($value); $j < $jMax; $j++) {
574 if ($content->isNumericGap()) {
576 'answer' => $value[$j]->getAnswerText(),
577 'lower' => $value[$j]->getLowerBound(),
578 'upper' => $value[$j]->getUpperBound(),
579 'points' => $value[$j]->getPoints(),
585 'points' => $value[$j]->getPoints(),
589 if ($content->isSelectGap()) {
590 $shuffle = $content->getShuffle();
595 'type' => $translate_type[$content->getType()] ,
597 'shuffle' => $shuffle,
598 'text_field_length' => $content->getGapSize() > 0 ? $content->getGapSize() :
'',
599 'used_in_gap_combination' =>
true];
617 $gap = $this->
object->getGap($gapCounter);
624 $header->setTitle($this->
lng->txt(
"gap") .
" " . ($gapCounter + 1));
625 $form->addItem($header);
628 $gapcounter->setValue($gapCounter);
629 $form->addItem($gapcounter);
633 0 => $this->
lng->txt(
"text_gap"),
634 1 => $this->
lng->txt(
"select_gap"),
635 2 => $this->
lng->txt(
"numeric_gap")
638 $gaptype->setValue($gap->getType());
639 $form->addItem($gaptype);
644 if (count($gap->getItemsRaw()) == 0) {
649 if (count($gap->getItemsRaw()) == 0) {
656 if (count($gap->getItemsRaw()) == 0) {
659 foreach ($gap->getItemsRaw() as $item) {
673 $gapSizeFormItem =
new ilNumberInputGUI($this->
lng->txt(
'cloze_fixed_textlength'),
"gap_" . $gapCounter .
'_gapsize');
675 $gapSizeFormItem->allowDecimals(
false);
676 $gapSizeFormItem->setMinValue(0);
677 $gapSizeFormItem->setSize(3);
678 $gapSizeFormItem->setMaxLength(6);
679 $gapSizeFormItem->setInfo($this->
lng->txt(
'cloze_gap_size_info'));
680 $gapSizeFormItem->setValue($gap->getGapSize());
681 $form->addItem($gapSizeFormItem);
702 $values->setQuestionObject($this->
object);
703 $values->setSingleline(
true);
704 $values->setAllowMove(
false);
706 $values->setValues($gap->getItemsRaw());
707 $form->addItem($values);
710 $shuffle =
new ilCheckboxInputGUI($this->
lng->txt(
"shuffle_answers"),
"shuffle_" . $gapCounter .
"");
711 $shuffle->setValue(1);
712 $shuffle->setChecked($gap->getShuffle());
713 $shuffle->setRequired(
false);
714 $form->addItem($shuffle);
733 $values->setQuestionObject($this->
object);
734 $values->setSingleline(
true);
735 $values->setAllowMove(
false);
736 $values->setValues($gap->getItemsRaw());
737 $form->addItem($values);
739 if ($this->
object->getFixedTextLength() > 0) {
740 $values->setSize($this->
object->getFixedTextLength());
741 $values->setMaxLength($this->
object->getFixedTextLength());
761 if (!$this->
object->getSelfAssessmentEditingMode()) {
765 $lowerbound =
new ilFormulaInputGUI($this->
lng->txt(
'range_lower_limit'),
"gap_" . $gapCounter .
"_numeric_lower");
768 $upperbound =
new ilFormulaInputGUI($this->
lng->txt(
'range_upper_limit'),
"gap_" . $gapCounter .
"_numeric_upper");
771 $value =
new ilNumberInputGUI($this->
lng->txt(
'value'),
"gap_" . $gapCounter .
"_numeric");
772 $value->allowDecimals(
true);
774 $lowerbound =
new ilNumberInputGUI($this->
lng->txt(
'range_lower_limit'),
"gap_" . $gapCounter .
"_numeric_lower");
775 $lowerbound->allowDecimals(
true);
777 $upperbound =
new ilNumberInputGUI($this->
lng->txt(
'range_upper_limit'),
"gap_" . $gapCounter .
"_numeric_upper");
778 $upperbound->allowDecimals(
true);
783 $value->setRequired(
true);
784 $form->addItem($value);
786 $lowerbound->setSize(10);
787 $lowerbound->setRequired(
true);
789 $form->addItem($lowerbound);
791 $upperbound->setSize(10);
792 $upperbound->setRequired(
true);
794 $form->addItem($upperbound);
796 if ($this->
object->getFixedTextLength() > 0) {
797 $value->setSize($this->
object->getFixedTextLength());
798 $value->setMaxLength($this->
object->getFixedTextLength());
799 $lowerbound->setSize($this->
object->getFixedTextLength());
800 $lowerbound->setMaxLength($this->
object->getFixedTextLength());
801 $upperbound->setSize($this->
object->getFixedTextLength());
802 $upperbound->setMaxLength($this->
object->getFixedTextLength());
805 $points =
new ilNumberInputGUI($this->
lng->txt(
'points'),
"gap_" . $gapCounter .
"_numeric_points");
806 $points->allowDecimals(
true);
808 $points->setRequired(
true);
810 $form->addItem($points);
820 $this->
object->saveToDb();
830 $this->
object->deleteAnswerText($this->gapIndex, key($_POST[
'cmd'][
'removegap_' . $this->gapIndex]));
840 $this->
object->addGapAnswer($this->gapIndex, key($_POST[
'cmd'][
'addgap_' . $this->gapIndex]) + 1,
"");
852 public function getPreview($show_question_only =
false, $showInlineFeedback =
false): string
856 $template =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_output.html",
true,
true,
"Modules/TestQuestionPool");
857 $output = $this->
object->getClozeTextForHTMLOutput();
858 foreach ($this->
object->getGaps() as $gap_index => $gap) {
859 switch ($gap->getType()) {
861 $gaptemplate =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_gap_text.html",
true,
true,
"Modules/TestQuestionPool");
863 $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->
object->getFixedTextLength();
865 $gaptemplate->setCurrentBlock(
'size_and_maxlength');
866 $gaptemplate->setVariable(
"TEXT_GAP_SIZE", $gap_size);
867 $gaptemplate->parseCurrentBlock();
869 $gaptemplate->setVariable(
"GAP_COUNTER", $gap_index);
870 foreach ($user_solution as $val1 => $val2) {
871 if (strcmp($val1, $gap_index) == 0) {
878 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
882 $gaptemplate =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_gap_select.html",
true,
true,
"Modules/TestQuestionPool");
883 foreach ($gap->getItems($this->object->getShuffler(), $gap_index) as $item) {
884 $gaptemplate->setCurrentBlock(
"select_gap_option");
885 $gaptemplate->setVariable(
"SELECT_GAP_VALUE", $item->getOrder());
886 $gaptemplate->setVariable(
890 foreach ($user_solution as $val1 => $val2) {
891 if (strcmp($val1, $gap_index) == 0) {
892 if (strcmp($val2, $item->getOrder()) == 0) {
893 $gaptemplate->setVariable(
"SELECT_GAP_SELECTED",
" selected=\"selected\"");
897 $gaptemplate->parseCurrentBlock();
899 $gaptemplate->setVariable(
"PLEASE_SELECT", $this->
lng->txt(
"please_select"));
900 $gaptemplate->setVariable(
"GAP_COUNTER", $gap_index);
901 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
905 $gaptemplate =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_gap_numeric.html",
true,
true,
"Modules/TestQuestionPool");
906 $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->
object->getFixedTextLength();
908 $gaptemplate->setCurrentBlock(
'size_and_maxlength');
909 $gaptemplate->setVariable(
"TEXT_GAP_SIZE", $gap_size);
910 $gaptemplate->parseCurrentBlock();
912 $gaptemplate->setVariable(
"GAP_COUNTER", $gap_index);
913 foreach ($user_solution as $val1 => $val2) {
914 if (strcmp($val1, $gap_index) == 0) {
921 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
926 $template->setVariable(
"QUESTIONTEXT", $this->
object->getQuestionForHTMLOutput());
928 $questionoutput = $template->get();
929 if (!$show_question_only) {
933 return $questionoutput;
952 $graphicalOutput =
false,
953 $result_output =
false,
954 $show_question_only =
true,
955 $show_feedback =
false,
956 $show_correct_solution =
false,
957 $show_manual_scoring =
false,
958 $show_question_text =
true 962 if (($active_id > 0) && (!$show_correct_solution)) {
964 $user_solution = $this->
object->getSolutionValues($active_id, $pass);
965 if (!is_array($user_solution)) {
978 $show_correct_solution,
979 $show_manual_scoring,
987 mixed $user_solutions,
990 bool $graphical_output =
false,
991 bool $result_output =
false,
992 bool $show_question_only =
true,
993 bool $show_feedback =
false,
994 bool $show_correct_solution =
false,
995 bool $show_manual_scoring =
false,
996 bool $show_question_text =
true,
997 bool $show_autosave_title =
false,
998 bool $show_inline_feedback =
false,
1001 $template =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_output_solution.html",
true,
true,
"Modules/TestQuestionPool");
1002 $output = $this->
object->getClozeTextForHTMLOutput();
1004 $check_for_gap_combinations = $assClozeGapCombinationObject->loadFromDb($this->
object->getId());
1006 foreach ($this->
object->getGaps() as $gap_index => $gap) {
1007 $gaptemplate =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_output_solution_gap.html",
true,
true,
"Modules/TestQuestionPool");
1009 foreach ($user_solutions as $solutionarray) {
1010 if ($solutionarray[
'value1'] == $gap_index) {
1011 $found = $solutionarray;
1016 if ($graphical_output) {
1018 $details = $this->
object->calculateReachedPoints($active_id, $pass,
true,
true);
1021 if (count($check_for_gap_combinations) != 0) {
1022 $gaps_used_in_combination = $assClozeGapCombinationObject->getGapsWhichAreUsedInCombination($this->
object->getId());
1023 $custom_user_solution = [];
1024 if (array_key_exists($gap_index, $gaps_used_in_combination)) {
1025 $combination_id = $gaps_used_in_combination[$gap_index];
1026 foreach ($gaps_used_in_combination as
$key => $value) {
1028 if ($value == $combination_id) {
1029 foreach ($user_solutions as $solution_key => $solution_value) {
1030 if ($solution_value[
'value1'] ==
$key) {
1032 $result_row[
'gap_id'] = $solution_value[
'value1'];
1033 $result_row[
'value'] = $solution_value[
'value2'];
1034 array_push($custom_user_solution, $result_row);
1039 $points_array = $this->
object->calculateCombinationResult($custom_user_solution);
1040 $max_combination_points = $assClozeGapCombinationObject->getMaxPointsForCombination($this->
object->getId(), $combination_id);
1041 if ($points_array[0] == $max_combination_points) {
1043 } elseif ($points_array[0] > 0) {
1049 if (array_key_exists(
'best',
$check) &&
$check[
"best"]) {
1050 $gaptemplate->setCurrentBlock(
"icon_ok");
1052 $gaptemplate->parseCurrentBlock();
1054 $gaptemplate->setCurrentBlock(
"icon_ok");
1055 if (array_key_exists(
'positive',
$check) &&
$check[
"positive"]) {
1060 $gaptemplate->parseCurrentBlock();
1064 if (array_key_exists(
'best',
$check) &&
$check[
"best"]) {
1065 $gaptemplate->setCurrentBlock(
"icon_ok");
1067 $gaptemplate->parseCurrentBlock();
1069 $gaptemplate->setCurrentBlock(
"icon_ok");
1070 if (array_key_exists(
'positive',
$check) &&
$check[
"positive"]) {
1075 $gaptemplate->parseCurrentBlock();
1080 $combination = null;
1081 switch ($gap->getType()) {
1085 if (($active_id > 0) && (!$show_correct_solution)) {
1086 if ((count($found) == 0) || (strlen(trim($found[
'value2'])) == 0)) {
1087 for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++) {
1088 $solutiontext .=
" ";
1094 $solutiontext = $this->
getBestSolutionText($gap, $gap_index, $check_for_gap_combinations);
1098 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
1103 if (($active_id > 0) && (!$show_correct_solution)) {
1104 if ((count($found) == 0) || (strlen(trim($found[
'value2'])) == 0)) {
1105 for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++) {
1106 $solutiontext .=
" ";
1109 $item = $gap->getItem($found[
'value2']);
1110 if (is_object($item)) {
1113 for ($chars = 0; $chars < $gap->getMaxWidth(); $chars++) {
1114 $solutiontext .=
" ";
1119 $solutiontext = $this->
getBestSolutionText($gap, $gap_index, $check_for_gap_combinations);
1123 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
1129 if ($show_question_text) {
1130 $template->setVariable(
1132 $this->
object->getQuestionForHTMLOutput()
1138 $solutiontemplate =
new ilTemplate(
"tpl.il_as_tst_solution_output.html",
true,
true,
"Modules/TestQuestionPool");
1139 $questionoutput = $template->get();
1142 if ($show_feedback) {
1145 $feedback .= strlen($fb) ? $fb :
'';
1149 $this->
object->fetchIndexedValuesFromValuePairs($user_solutions)
1151 $feedback .= strlen($fb) ? $fb :
'';
1153 if (strlen($feedback)) {
1159 $solutiontemplate->setVariable(
"ILC_FB_CSS_CLASS", $cssClass);
1163 $solutiontemplate->setVariable(
"SOLUTION_OUTPUT", $questionoutput);
1165 $solutionoutput = $solutiontemplate->get();
1167 if (!$show_question_only) {
1169 $solutionoutput = $this->
getILIASPage($solutionoutput);
1172 return $solutionoutput;
1183 $combination = null;
1184 foreach ((array) $gap_combinations as $combiGapSolRow) {
1185 if ($combiGapSolRow[
'gap_fi'] == $gap_index && $combiGapSolRow[
'best_solution']) {
1186 $combination = $combiGapSolRow;
1191 $gap->getBestSolutionOutput(
1192 $this->object->getShuffler(),
1196 return $best_solution_text;
1202 if (strlen($manual_feedback)) {
1203 return $manual_feedback;
1205 $correct_feedback = $this->
object->feedbackOBJ->getGenericFeedbackTestPresentation($this->
object->getId(),
true);
1206 $incorrect_feedback = $this->
object->feedbackOBJ->getGenericFeedbackTestPresentation($this->
object->getId(),
false);
1209 if ($correct_feedback . $incorrect_feedback !==
'') {
1221 $is_postponed =
false,
1222 $use_post_solutions =
false,
1223 $show_feedback =
false 1226 $user_solution = [];
1227 if ($use_post_solutions !==
false) {
1228 $indexedSolution = $this->
object->fetchSolutionSubmit($use_post_solutions);
1229 $user_solution = $this->
object->fetchValuePairsFromIndexedValues($indexedSolution);
1230 } elseif ($active_id) {
1231 $user_solution = $this->
object->getTestOutputSolutions($active_id, $pass);
1233 if (!is_array($user_solution)) {
1234 $user_solution = [];
1238 $template =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_output.html",
true,
true,
"Modules/TestQuestionPool");
1239 $output = $this->
object->getClozeTextForHTMLOutput();
1240 foreach ($this->
object->getGaps() as $gap_index => $gap) {
1241 switch ($gap->getType()) {
1243 $gaptemplate =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_gap_text.html",
true,
true,
"Modules/TestQuestionPool");
1244 $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->
object->getFixedTextLength();
1246 if ($gap_size > 0) {
1247 $gaptemplate->setCurrentBlock(
'size_and_maxlength');
1248 $gaptemplate->setVariable(
"TEXT_GAP_SIZE", $gap_size);
1249 $gaptemplate->parseCurrentBlock();
1252 $gaptemplate->setVariable(
"GAP_COUNTER", $gap_index);
1253 foreach ($user_solution as $solution) {
1254 if (strcmp($solution[
'value1'], $gap_index) == 0) {
1261 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
1265 $gaptemplate =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_gap_select.html",
true,
true,
"Modules/TestQuestionPool");
1266 foreach ($gap->getItems($this->object->getShuffler(), $gap_index) as $item) {
1267 $gaptemplate->setCurrentBlock(
"select_gap_option");
1268 $gaptemplate->setVariable(
"SELECT_GAP_VALUE", $item->getOrder());
1269 $gaptemplate->setVariable(
1273 foreach ($user_solution as $solution) {
1274 if (strcmp($solution[
'value1'], $gap_index) == 0) {
1275 if (strcmp($solution[
'value2'], $item->getOrder()) == 0) {
1276 $gaptemplate->setVariable(
"SELECT_GAP_SELECTED",
" selected=\"selected\"");
1280 $gaptemplate->parseCurrentBlock();
1282 $gaptemplate->setVariable(
"PLEASE_SELECT", $this->
lng->txt(
"please_select"));
1283 $gaptemplate->setVariable(
"GAP_COUNTER", $gap_index);
1284 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
1288 $gaptemplate =
new ilTemplate(
"tpl.il_as_qpl_cloze_question_gap_numeric.html",
true,
true,
"Modules/TestQuestionPool");
1289 $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->
object->getFixedTextLength();
1290 if ($gap_size > 0) {
1291 $gaptemplate->setCurrentBlock(
'size_and_maxlength');
1292 $gaptemplate->setVariable(
"TEXT_GAP_SIZE", $gap_size);
1293 $gaptemplate->parseCurrentBlock();
1296 $gaptemplate->setVariable(
"GAP_COUNTER", $gap_index);
1297 foreach ($user_solution as $solution) {
1298 if (strcmp($solution[
'value1'], $gap_index) == 0) {
1305 $output = $this->
object->replaceFirstGap($output, $gaptemplate->get());
1311 $template->setVariable(
"QUESTIONTEXT", $this->
object->getQuestionForHTMLOutput());
1313 $questionoutput = $template->get();
1314 $pageoutput = $this->
outQuestionPage(
"", $is_postponed, $active_id, $questionoutput);
1320 if (!$this->
object->feedbackOBJ->isSpecificAnswerFeedbackAvailable($this->object->getId())) {
1324 $feedback =
'<table class="test_specific_feedback"><tbody>';
1326 foreach ($this->
object->gaps as $gap_index => $gap) {
1327 $answer_value = $this->
object->fetchAnswerValueForGap($user_solution, $gap_index);
1329 && $answer_value ===
'') {
1332 $answer_index = $this->
object->feedbackOBJ->determineAnswerIndexForAnswerValue($gap, $answer_value);
1333 $fb = $this->
object->feedbackOBJ->determineTestOutputGapFeedback($gap_index, $answer_index);
1335 $caption = $this->
lng->txt(
'gap') .
' ' . ($gap_index + 1) .
': ';
1336 $feedback .=
'<tr><td>';
1337 $feedback .= $caption .
'</td><td>';
1338 $feedback .= $fb .
'</td> </tr>';
1340 $feedback .=
'</tbody></table>';
1383 foreach ($relevant_answers as $answer) {
1384 $overview[$answer[
'active_fi']][$answer[
'pass']][$answer[
'value1']] = $answer[
'value2'];
1387 foreach ($overview as $active) {
1388 foreach ($active as $answer) {
1389 foreach ($answer as $option => $value) {
1390 $aggregation[$option][$value] = $aggregation[$option][$value] + 1;
1397 foreach ($this->
object->getGaps() as $gap_index => $gap) {
1399 $html .=
'<p>Gap ' . ($i + 1) .
' - SELECT</p>';
1402 foreach ($gap->getItems($this->object->getShuffler(), $gap_index) as $gap_item) {
1403 $aggregate = $aggregation[$i];
1404 $html .=
'<li>' . $gap_item->getAnswerText() .
' - ' . ($aggregate[$j] ? $aggregate[$j] : 0) .
'</li>';
1411 $present_elements = [];
1412 foreach ($gap->getItems($this->randomGroup->shuffleArray(
new Seed\
RandomSeed())) as $item) {
1414 $present_elements[] = $item->getAnswertext();
1417 $html .=
'<p>Gap ' . ($i + 1) .
' - TEXT</p>';
1419 $aggregate = (array) $aggregation[$i];
1420 foreach ($aggregate as $answer => $count) {
1422 if (in_array($answer, $present_elements)) {
1423 $show_mover =
' style="display: none;" ';
1426 $html .=
'<li>' . $answer .
' - ' . $count
1427 .
' <button class="clone_fields_add btn btn-link" ' . $show_mover .
' data-answer="' . $answer .
'" name="add_gap_' . $i .
'_0"> 1428 <span class="sr-only"></span><span class="glyphicon glyphicon-plus"></span></button> 1435 $html .=
'<p>Gap ' . ($i + 1) .
' - NUMERIC</p>';
1438 foreach ($gap->getItems($this->object->getShuffler(), $gap_index) as $gap_item) {
1439 $aggregate = (array) $aggregation[$i];
1440 foreach ($aggregate as $answer => $count) {
1441 $html .=
'<li>' . $answer .
' - ' . $count .
'</li>';
1457 $parts = explode(
'[gap', $question_text);
1459 $question_text =
'';
1460 foreach (
$parts as $part) {
1462 $question_text .= $part;
1464 $question_text .=
'[gap ' . $i . $part;
1468 return $question_text;
1473 $parts = preg_split(
'/\[gap \d*\]/', $question_text);
1474 $question_text = implode(
'[gap]',
$parts);
1475 return $question_text;
1485 $gaptemplate->setCurrentBlock(
'gap_span');
1486 $gaptemplate->setVariable(
'SPAN_SOLUTION', $solutiontext);
1488 $gaptemplate->setCurrentBlock(
'gap_select');
1489 $gaptemplate->setVariable(
'SELECT_SOLUTION', $solutiontext);
1491 $gap_size = $gap->getGapSize() > 0 ? $gap->getGapSize() : $this->
object->getFixedTextLength();
1493 if ($gap_size > 0) {
1494 $gaptemplate->setCurrentBlock(
'gap_size');
1495 $gaptemplate->setVariable(
"GAP_SIZE", $gap_size);
1496 $gaptemplate->parseCurrentBlock();
1499 $gaptemplate->setCurrentBlock(
'gap_input');
1500 $gaptemplate->setVariable(
'INPUT_SOLUTION', $solutiontext);
1504 $gaptemplate->parseCurrentBlock();
1510 if (isset($answer[
'actions'])) {
1520 $table = parent::getAnswerFrequencyTableGUI(
1529 $this->
lng->txt(
'tst_corrections_answers_tbl_subindex'),
1530 $this->
lng->txt(
'gap') .
' ' . ($questionIndex + 1)
1535 $table->addColumn(
'',
'',
'200');
1543 return array_keys($this->
object->getGaps());
1548 $gap = $this->
object->getGap(
$gapIndex);
1550 switch ($gap->type) {
1557 $items = $gap->getItems($this->randomGroup->dontShuffle());
1558 return $items[$answer]->getAnswertext();
1564 $gap = $this->
object->getGap($gap_index);
1567 $this->isUsedInCombinations($gap_index)) {
1571 foreach ($answers as
$key => $ans) {
1574 foreach ($gap->getItems($this->randomGroup->dontShuffle()) as $item) {
1575 if ($ans[
'answer'] !== $item->getAnswerText()) {
1584 $answers[
$key][
'addable'] =
true;
1595 foreach ($relevantAnswers as $row) {
1596 if ($row[
'value1'] != $questionIndex) {
1600 if (!isset($answers[$row[
'value2']])) {
1603 $answers[$row[
'value2']] = [
1604 'answer' => $label,
'frequency' => 0
1608 $answers[$row[
'value2']][
'frequency']++;
1618 foreach ($this->
object->getGapCombinations() as $combination) {
1619 if ($combination[
'gap_fi'] !=
$gapIndex) {
1633 foreach ($this->
object->getGapCombinations() as
$c) {
1634 if (!isset($combinations[
$c[
'cid']])) {
1635 $combinations[$c[
'cid']] = [];
1638 if (!isset($combinations[$c[
'cid']][$c[
'row_id']])) {
1639 $combinations[$c[
'cid']][$c[
'row_id']] = [
1640 'gaps' => [],
'points' => $c[
'points'],
1644 if (!isset($combinations[$c[
'cid']][$c[
'row_id']][
'gaps'][$c[
'gap_fi']])) {
1645 $combinations[$c[
'cid']][$c[
'row_id']][
'gaps'][$c[
'gap_fi']] = [];
1648 $combinations[$c[
'cid']][$c[
'row_id']][
'gaps'][$c[
'gap_fi']] = $c[
'answer'];
1651 return $combinations;
1665 if ($this->
object->getGapCombinationsExists()) {
1675 $header->setTitle(
"Gap Combination " . ($combiIndex + 1));
1679 $inp->setValues($gapCombi);
1691 $header->setTitle($this->
lng->txt(
"gap") .
" " . (
$gapIndex + 1));
1692 $form->addItem($header);
1697 foreach ($gap->getItemsRaw() as $item) {
1707 $values->setRequired(
true);
1708 $values->setQuestionObject($this->
object);
1709 $values->setValues($gap->getItemsRaw());
1710 $form->addItem($values);
1716 $value->allowDecimals(
true);
1717 $value->setSize(10);
1719 $value->setRequired(
true);
1720 $form->addItem($value);
1723 $lowerbound->allowDecimals(
true);
1724 $lowerbound->setSize(10);
1725 $lowerbound->setRequired(
true);
1727 $form->addItem($lowerbound);
1730 $upperbound->allowDecimals(
true);
1731 $upperbound->setSize(10);
1732 $upperbound->setRequired(
true);
1734 $form->addItem($upperbound);
1738 $points->allowDecimals(
true);
1739 $points->setSize(3);
1740 $points->setRequired(
true);
1742 $form->addItem($points);
1759 if ($this->
object->getGapCombinationsExists()) {
1779 foreach ($gap->
getItemsRaw() as $index => $item) {
1780 $item->setPoints((
float) str_replace(
',',
'.', $answers[$index]->getPoints()));
1796 $combinationPoints = [
'points' => [],
'select' => []];
1797 $combinationValues = [];
1802 if (!isset($combinationPoints[
'points'][$combiId])) {
1803 $combinationPoints[
'points'][$combiId] = [];
1804 $combinationPoints[
'select'][$combiId] = [];
1805 $combinationValues[$combiId] = [];
1808 foreach ($combi as $varId => $variant) {
1809 $combinationPoints[
'points'][$combiId][$varId] = (float) str_replace(
',',
'.', $values[$varId][
'points']);
1810 $combinationPoints[
'select'][$combiId] = array_keys($values[$varId][
'gaps']);
1811 $combinationValues[$combiId][$varId] = array_values($values[$varId][
'gaps']);
1815 $combinationPoints = $combinationPoints;
1816 $combinationValues = $combinationValues;
1819 $assClozeGapCombinationObject->clearGapCombinationsFromDb($this->
object->getId());
1821 $assClozeGapCombinationObject->saveGapCombinationToDb(
1826 $this->
object->setGapCombinationsExists(
true);
isTestPresentationContext()
hasCorrectSolution($activeId, $passIndex)
populateNumericGapCorrectionFormProperty($form, $item, $gapIndex, $hidePoints)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
genericFeedbackOutputBuilder(string $feedback_correct, string $feedback_incorrect, int $active_id, ?int $pass)
generateCorrectnessIconsForCorrectness(int $correctness)
getAnswersFrequency($relevantAnswers, $questionIndex)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
if($clientAssertionType !='urn:ietf:params:oauth:client-assertion-type:jwt-bearer'|| $grantType !='client_credentials') $parts
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
getAggregatedAnswersView(array $relevant_answers)
Returns an html string containing a question specific representation of the answers so far given in t...
const CLOZE_TEXT
Cloze question constants.
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
saveGapCorrectionFormProperty(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
setPoints($points=0.0)
Sets the points.
getTestOutput( $active_id, $pass, $is_postponed=false, $use_post_solutions=false, $show_feedback=false)
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 $_POST and applies them to the data object.
ilGlobalPageTemplate $tpl
populateTaxonomyFormSection(ilPropertyFormGUI $form)
Customizing of pimple-DIC for ILIAS.
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...
setValue(string $a_value)
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 $_POST 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.
ILIAS UI Factory $ui_factory
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)
{}
Basic GUI class for assessment questions.
const JS_INSERT_GAP_CODE_AT_CARET
saveNumericGapCorrectionFormProperty(ilPropertyFormGUI $form, assAnswerCloze $item, $gapIndex)
setUpperBound(string $bound)
Sets the upper bound.
removegap()
Remove a gap answer.
populateGapCorrectionFormProperties($form, $gap, $gapIndex, $hidePoints)
addgap()
Add a gap answer.
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.
getSolutionOutput( $active_id, $pass=null, $graphicalOutput=false, $result_output=false, $show_question_only=true, $show_feedback=false, $show_correct_solution=false, $show_manual_scoring=false, $show_question_text=true)
Get the question solution output.
saveTaxonomyAssignments()
ILIAS UI Renderer $ui_renderer
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)
This class represents a text area property in a property form.
getGenericFeedbackOutput(int $active_id, $pass)
const ADDITIONAL_CONTENT_EDITING_MODE_RTE
setAnswertext($answertext="")
Sets the answer text.
addBasicQuestionFormProperties(ilPropertyFormGUI $form)
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
$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...
addNumberOfTriesToFormIfNecessary(ilPropertyFormGUI $form)
$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.
getPreview($show_question_only=false, $showInlineFeedback=false)
Creates a preview output of the question.
setVariable(string $variable, $value='')
Sets the given variable to the given value.
getSpecificFeedbackOutput(array $user_solution)
editQuestion($checkonly=false)
Creates an output of the edit form for the question.
removeIndizesFromGapText($question_text)
static _getUsedHTMLTags(string $a_module="")
Returns an array of all allowed HTML tags for text editing.
ArrayBasedRequestWrapper $post
__construct(int $id=-1)
assClozeTestGUI constructor
getAnswerTextLabel($gapIndex, $answer)